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