mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 19:28:57 +01:00
graphicscommand: Span to 1/3 pixels
The center of pixels is problematic as the behavior depends on GPU. In order to avoid this, align the vertices with about 1/3 pixels. Updates #929 Fixes #1171
This commit is contained in:
parent
0b94e2e036
commit
484473b6d9
107
image_test.go
107
image_test.go
@ -16,6 +16,7 @@ package ebiten_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
@ -2067,63 +2068,61 @@ func BenchmarkImageDrawOver(b *testing.B) {
|
||||
}
|
||||
|
||||
// Issue #1171
|
||||
func Disabled_TestImageFloatTranslate(t *testing.T) {
|
||||
const w, h = 16, 16
|
||||
func TestImageFloatTranslate(t *testing.T) {
|
||||
const w, h = 32, 32
|
||||
|
||||
dst, _ := NewImage(320, 240, FilterDefault)
|
||||
src, _ := NewImage(w, h, FilterDefault)
|
||||
pix := make([]byte, 4*w*h)
|
||||
for j := 0; j < h; j++ {
|
||||
for i := 0; i < w; i++ {
|
||||
pix[4*(j*w+i)] = byte(j)
|
||||
pix[4*(j*w+i)+3] = 0xff
|
||||
}
|
||||
}
|
||||
src.ReplacePixels(pix)
|
||||
for s := 2; s <= 8; s++ {
|
||||
s := s
|
||||
t.Run(fmt.Sprintf("scale%d", s), func(t *testing.T) {
|
||||
check := func(src *Image) {
|
||||
dst, _ := NewImage(w*(s+1), h*(s+1), FilterDefault)
|
||||
dst.Fill(color.RGBA{0xff, 0, 0, 0xff})
|
||||
|
||||
op := &DrawImageOptions{}
|
||||
op.GeoM.Scale(2, 2)
|
||||
op.GeoM.Translate(0, 0.501)
|
||||
dst.DrawImage(src, op)
|
||||
op := &DrawImageOptions{}
|
||||
op.GeoM.Scale(float64(s), float64(s))
|
||||
op.GeoM.Translate(0, 0.501)
|
||||
dst.DrawImage(src, op)
|
||||
|
||||
for j := 1; j < h*2+1; j++ {
|
||||
for i := 0; i < w*2; i++ {
|
||||
got := dst.At(i, j)
|
||||
want := color.RGBA{(byte(j) - 1) / 2, 0, 0, 0xff}
|
||||
if got != want {
|
||||
t.Errorf("At(%d, %d): got: %v, want: %v", i, j, got, want)
|
||||
for j := 0; j < h*s+1; j++ {
|
||||
for i := 0; i < w*s; i++ {
|
||||
got := dst.At(i, j)
|
||||
x := byte(0xff)
|
||||
if j > 0 {
|
||||
x = (byte(j) - 1) / byte(s)
|
||||
}
|
||||
want := color.RGBA{x, 0, 0, 0xff}
|
||||
if got != want {
|
||||
t.Errorf("At(%d, %d): got: %v, want: %v", i, j, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Issue #1171
|
||||
func Disabled_TestImageSubImageFloatTranslate(t *testing.T) {
|
||||
const w, h = 16, 16
|
||||
|
||||
dst, _ := NewImage(320, 240, FilterDefault)
|
||||
src, _ := NewImage(w*2, h*2, FilterDefault)
|
||||
pix := make([]byte, 4*(w*2)*(h*2))
|
||||
for j := 0; j < h*2; j++ {
|
||||
for i := 0; i < w*2; i++ {
|
||||
pix[4*(j*(w*2)+i)] = byte(j)
|
||||
pix[4*(j*(w*2)+i)+3] = 0xff
|
||||
}
|
||||
}
|
||||
src.ReplacePixels(pix)
|
||||
|
||||
op := &DrawImageOptions{}
|
||||
op.GeoM.Scale(2, 2)
|
||||
op.GeoM.Translate(0, 0.501)
|
||||
dst.DrawImage(src.SubImage(image.Rect(0, 0, w, h)).(*Image), op)
|
||||
|
||||
for j := 1; j < h*2+1; j++ {
|
||||
for i := 0; i < w*2; i++ {
|
||||
got := dst.At(i, j)
|
||||
want := color.RGBA{(byte(j) - 1) / 2, 0, 0, 0xff}
|
||||
if got != want {
|
||||
t.Errorf("At(%d, %d): got: %v, want: %v", i, j, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("image", func(t *testing.T) {
|
||||
src, _ := NewImage(w, h, FilterDefault)
|
||||
pix := make([]byte, 4*w*h)
|
||||
for j := 0; j < h; j++ {
|
||||
for i := 0; i < w; i++ {
|
||||
pix[4*(j*w+i)] = byte(j)
|
||||
pix[4*(j*w+i)+3] = 0xff
|
||||
}
|
||||
}
|
||||
src.ReplacePixels(pix)
|
||||
check(src)
|
||||
})
|
||||
|
||||
t.Run("subimage", func(t *testing.T) {
|
||||
src, _ := NewImage(w*s, h*s, FilterDefault)
|
||||
pix := make([]byte, 4*(w*s)*(h*s))
|
||||
for j := 0; j < h*s; j++ {
|
||||
for i := 0; i < w*s; i++ {
|
||||
pix[4*(j*(w*s)+i)] = byte(j)
|
||||
pix[4*(j*(w*s)+i)+3] = 0xff
|
||||
}
|
||||
}
|
||||
src.ReplacePixels(pix)
|
||||
check(src.SubImage(image.Rect(0, 0, w, h)).(*Image))
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -203,14 +203,6 @@ func (q *commandQueue) Enqueue(command command) {
|
||||
q.commands = append(q.commands, command)
|
||||
}
|
||||
|
||||
func fract(x float32) float32 {
|
||||
return x - float32(math.Floor(float64(x)))
|
||||
}
|
||||
|
||||
const (
|
||||
dstAdjustmentFactor = 1.0 / 256.0
|
||||
)
|
||||
|
||||
// Flush flushes the command queue.
|
||||
func (q *commandQueue) Flush() error {
|
||||
if len(q.commands) == 0 {
|
||||
@ -236,22 +228,22 @@ func (q *commandQueue) Flush() error {
|
||||
vs[i*graphics.VertexFloatNum+6] /= s.width
|
||||
vs[i*graphics.VertexFloatNum+7] /= s.height
|
||||
|
||||
// Adjust the destination position to avoid jaggy (#929).
|
||||
// This is not a perfect solution since texels on a texture can take a position on borders
|
||||
// which can cause jaggy. But adjusting only edges should work in most cases.
|
||||
// The ideal solution is to fix shaders, but this makes the applications slow by adding 'if'
|
||||
// branches.
|
||||
switch f := fract(vs[i*graphics.VertexFloatNum+0]); {
|
||||
case 0.5-dstAdjustmentFactor <= f && f < 0.5:
|
||||
vs[i*graphics.VertexFloatNum+0] -= f - (0.5 - dstAdjustmentFactor)
|
||||
case 0.5 <= f && f < 0.5+dstAdjustmentFactor:
|
||||
vs[i*graphics.VertexFloatNum+0] += (0.5 + dstAdjustmentFactor) - f
|
||||
}
|
||||
switch f := fract(vs[i*graphics.VertexFloatNum+1]); {
|
||||
case 0.5-dstAdjustmentFactor <= f && f < 0.5:
|
||||
vs[i*graphics.VertexFloatNum+1] -= f - (0.5 - dstAdjustmentFactor)
|
||||
case 0.5 <= f && f < 0.5+dstAdjustmentFactor:
|
||||
vs[i*graphics.VertexFloatNum+1] += (0.5 + dstAdjustmentFactor) - f
|
||||
// Avoid the center of the pixel, which is problematic (#929, #1171).
|
||||
// Instead, align the vertices with about 1/3 pixels.
|
||||
for idx := 0; idx < 2; idx++ {
|
||||
x := vs[i*graphics.VertexFloatNum+idx]
|
||||
int := float32(math.Floor(float64(x)))
|
||||
frac := x - int
|
||||
switch {
|
||||
case frac < 3.0/16.0:
|
||||
vs[i*graphics.VertexFloatNum+idx] = int
|
||||
case frac < 8.0/16.0:
|
||||
vs[i*graphics.VertexFloatNum+idx] = int + 5.0/16.0
|
||||
case frac < 13.0/16.0:
|
||||
vs[i*graphics.VertexFloatNum+idx] = int + 11.0/16.0
|
||||
default:
|
||||
vs[i*graphics.VertexFloatNum+idx] = int + 16.0/16.0
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user