ebiten: Bug fix: Fix the texel calculation

In shaders, texCoord is always in texture0's texels. Convert them
at imageNTextureAt functions correctly.

Fixes #1290
This commit is contained in:
Hajime Hoshi 2020-08-11 03:42:21 +09:00
parent 69f87d5fd1
commit 609a3c4e22
6 changed files with 35 additions and 69 deletions

View File

@ -26,14 +26,14 @@ const (
PreservedUniformVariablesNum = 1 + // the destination texture size
1 + // the texture sizes array
1 + // the offsets array of the second and the following images
1 + // the texture source origin
1 // the texture source sizes
1 + // the texture source region's origin
1 // the texture source region's size
DestinationTextureSizeUniformVariableIndex = 0
TextureSizesUniformVariableIndex = 1
TextureSourceOffsetsUniformVariableIndex = 2
TextureSourceOriginUniformVariableIndex = 3
TextureSourceSizesUniformVariableIndex = 4
TextureSourceRegionOriginUniformVariableIndex = 3
TextureSourceRegionSizeUniformVariableIndex = 4
)
const (

View File

@ -167,7 +167,6 @@ func (q *commandQueue) EnqueueDrawTrianglesCommand(dst *Image, srcs [graphics.Sh
sourceRegion.Y /= float32(h)
sourceRegion.Width /= float32(w)
sourceRegion.Height /= float32(h)
// TODO: This doesn't work when the src image sizes are different.
for i := range offsets {
offsets[i][0] /= float32(w)
offsets[i][1] /= float32(h)

View File

@ -1029,30 +1029,13 @@ func (g *Graphics) DrawShader(dstID driver.ImageID, srcIDs [graphics.ShaderImage
}
us[graphics.TextureSourceOffsetsUniformVariableIndex] = uoffsets
// Set the source origin of the first image.
// Set the source region's origin of texture0.
uorigin := []float32{float32(sourceRegion.X), float32(sourceRegion.Y)}
us[graphics.TextureSourceOriginUniformVariableIndex] = uorigin
us[graphics.TextureSourceRegionOriginUniformVariableIndex] = uorigin
// Set the source sizes.
ussizes := make([]float32, 2*len(srcs))
if srcs[0] != nil {
w, h := sourceRegion.Width, sourceRegion.Height
bw, bh := srcs[0].internalSize()
for i, src := range srcs {
if i == 0 {
ussizes[2*i] = float32(w)
ussizes[2*i+1] = float32(h)
continue
}
if src == nil {
continue
}
tw, th := src.internalSize()
ussizes[2*i] = float32(w) * float32(bw) / float32(tw)
ussizes[2*i+1] = float32(h) * float32(bh) / float32(th)
}
}
us[graphics.TextureSourceSizesUniformVariableIndex] = ussizes
// Set the source region's size of texture0.
ussize := []float32{float32(sourceRegion.Width), float32(sourceRegion.Height)}
us[graphics.TextureSourceRegionSizeUniformVariableIndex] = ussize
// Set the additional uniform variables.
for i, v := range uniforms {

View File

@ -336,37 +336,17 @@ func (g *Graphics) DrawShader(dst driver.ImageID, srcs [graphics.ShaderImageNum]
us[idx].typ = s.ir.Uniforms[idx]
}
{
origin := make([]float32, 2)
origin[0] = sourceRegion.X
origin[1] = sourceRegion.Y
const idx = graphics.TextureSourceOriginUniformVariableIndex
origin := []float32{float32(sourceRegion.X), float32(sourceRegion.Y)}
const idx = graphics.TextureSourceRegionOriginUniformVariableIndex
us[idx].name = fmt.Sprintf("U%d", idx)
us[idx].value = origin
us[idx].typ = s.ir.Uniforms[idx]
}
{
sizes := make([]float32, 2*len(srcs))
if baseimg := g.images[srcs[0]]; baseimg != nil {
w, h := sourceRegion.Width, sourceRegion.Height
bw, bh := baseimg.framebufferSize()
for i, src := range srcs {
if i == 0 {
sizes[2*i] = float32(w)
sizes[2*i+1] = float32(h)
continue
}
img := g.images[src]
if img == nil {
continue
}
tw, th := img.framebufferSize()
sizes[2*i] = float32(w) * float32(bw) / float32(tw)
sizes[2*i+1] = float32(h) * float32(bh) / float32(th)
}
}
const idx = graphics.TextureSourceSizesUniformVariableIndex
size := []float32{float32(sourceRegion.Width), float32(sourceRegion.Height)}
const idx = graphics.TextureSourceRegionSizeUniformVariableIndex
us[idx].name = fmt.Sprintf("U%d", idx)
us[idx].value = sizes
us[idx].value = size
us[idx].typ = s.ir.Uniforms[idx]
}

View File

@ -241,12 +241,8 @@ func defaultProgram() shaderir.Program {
}
// Source region origin
p.Uniforms[3] = shaderir.Type{Main: shaderir.Vec2}
// Source region sizes
p.Uniforms[4] = shaderir.Type{
Main: shaderir.Array,
Length: graphics.ShaderImageNum,
Sub: []shaderir.Type{{Main: shaderir.Vec2}},
}
// Source region size
p.Uniforms[4] = shaderir.Type{Main: shaderir.Vec2}
return p
}

View File

@ -49,30 +49,38 @@ func image%[1]dTextureSize() vec2 {
}
shaderSuffix += fmt.Sprintf(`
// The unit is texture0's texels.
var __textureSourceOffsets [%[1]d]vec2
// The unit is texture0's texels.
var __textureSourceOrigin vec2
var __textureSourceSizes [%[2]d]vec2
// The unit is texture0's texels.
var __textureSourceSize vec2
`, graphics.ShaderImageNum-1, graphics.ShaderImageNum)
for i := 0; i < graphics.ShaderImageNum; i++ {
var offset string
pos := "pos"
if i >= 1 {
offset = fmt.Sprintf(" + __textureSourceOffsets[%d]", i-1)
// Convert the position in texture0's texels to the target texture texels.
pos = fmt.Sprintf("(pos + __textureSourceOffsets[%d]) * __textureSizes[0] / __textureSizes[%d]", i-1, i)
}
// __t%d is a special variable for a texture variable.
shaderSuffix += fmt.Sprintf(`
func image%[1]dTextureAt(pos vec2) vec4 {
return texture2D(__t%[1]d, pos%[2]s)
// pos is the position in texture0's texels.
return texture2D(__t%[1]d, %[2]s)
}
func image%[1]dTextureBoundsAt(pos vec2) vec4 {
return texture2D(__t%[1]d, pos%[2]s) *
// pos is the position in texture0's texels.
return texture2D(__t%[1]d, %[2]s) *
step(__textureSourceOrigin.x, pos.x) *
(1 - step(__textureSourceOrigin.x + __textureSourceSizes[%[1]d].x, pos.x)) *
(1 - step(__textureSourceOrigin.x + __textureSourceSize.x, pos.x)) *
step(__textureSourceOrigin.y, pos.y) *
(1 - step(__textureSourceOrigin.y + __textureSourceSizes[%[1]d].y, pos.y))
(1 - step(__textureSourceOrigin.y + __textureSourceSize.y, pos.y))
}
`, i, offset)
`, i, pos)
}
shaderSuffix += `