internal/graphics: add built-in Kage functions

This change adds these Kage functions:

* imageDstOrigin
* imageDstSrc
* imageSrcNOrigin
* imageSrcNSrc

and deprecates these functions:

* imageDstRegionOnTexture
* imageSrcRegionOnTexture

Closes #1870
This commit is contained in:
Hajime Hoshi 2023-08-28 03:39:27 +09:00
parent 101c9cbf5c
commit db34930ae8
12 changed files with 64 additions and 43 deletions

View File

@ -33,8 +33,9 @@ func Warp(pos vec2) vec2 {
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
// Adjust the texture position to [0, 1].
origin := imageSrc0Origin()
size := imageSrc0Size()
pos := texCoord
origin, size := imageSrcRegionOnTexture()
pos -= origin
pos /= size

View File

@ -22,8 +22,7 @@ var Time float
var Cursor vec2
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
_, dstSize := imageDstRegionOnTexture()
center := dstSize / 2
center := imageDstSize() / 2
amount := (center - Cursor) / 10
var clr vec3
clr.r = imageSrc2At(texCoord + amount).r

View File

@ -22,9 +22,8 @@ var Time float
var Cursor vec2
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
dstOrigin, dstSize := imageDstRegionOnTexture()
pos := (position.xy - dstOrigin) / dstSize
pos += Cursor / dstSize / 4
pos := (position.xy - imageDstOrigin()) / imageDstSize()
pos += Cursor / imageDstSize() / 4
clr := 0.0
clr += sin(pos.x*cos(Time/15)*80) + cos(pos.y*cos(Time/15)*10)
clr += sin(pos.y*sin(Time/10)*40) + cos(pos.x*sin(Time/25)*40)

View File

@ -22,8 +22,7 @@ var Time float
var Cursor vec2
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
dstOrigin, _ := imageDstRegionOnTexture()
pos := position.xy - dstOrigin
pos := position.xy - imageDstOrigin()
lightpos := vec3(Cursor, 50)
lightdir := normalize(lightpos - vec3(pos, 0))

View File

@ -22,8 +22,7 @@ var Time float
var Cursor vec2
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
dstOrigin, _ := imageDstRegionOnTexture()
pos := position.xy - dstOrigin
pos := position.xy - imageDstOrigin()
dir := normalize(pos - Cursor)
clr := imageSrc2UnsafeAt(texCoord)

View File

@ -20,8 +20,7 @@ package main
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
pos := position.xy
origin, size := imageDstRegionOnTexture()
pos -= origin
pos /= size
pos -= imageDstOrigin()
pos /= imageDstSize()
return vec4(pos.x, pos.y, 0, 1)
}

View File

@ -22,17 +22,16 @@ var Time float
var Cursor vec2
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
dstOrigin, dstSize := imageDstRegionOnTexture()
pos := position.xy - dstOrigin
pos := position.xy - imageDstOrigin()
border := dstSize.y*0.6 + 4*cos(Time*3+pos.y/10)
border := imageDstSize().y*0.6 + 4*cos(Time*3+pos.y/10)
if pos.y < border {
return imageSrc2UnsafeAt(texCoord)
}
xoffset := 4 * cos(Time*3+pos.y/10)
yoffset := 20 * (1 + cos(Time*3+pos.y/40))
srcOrigin, _ := imageSrcRegionOnTexture()
srcOrigin := imageSrc0Origin()
clr := imageSrc2At(vec2(
texCoord.x+xoffset,
-(texCoord.y+yoffset-srcOrigin.y)+border*2+srcOrigin.y,

View File

@ -29,10 +29,6 @@ const screenShaderSrc = `//kage:unit pixels
package main
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
_, dr := imageDstRegionOnTexture()
_, sr := imageSrcRegionOnTexture()
scale := dr/sr
// Shift 1/512 [pixel] to avoid the tie-breaking issue.
pos := texCoord
p0 := pos - 1/2.0 + 1/512.0
@ -49,8 +45,9 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
// rate indicates how much the 4 colors are mixed. rate is in between [0, 1].
//
// 0 <= p <= 1/Scale: The rate is in between [0, 1]
// 1/Scale < p: Don't care. Adjacent colors (e.g. c0 vs c1 in an X direction) should be the same.
// 0 <= p <= 1/scale: The rate is in between [0, 1]
// 1/scale < p: Don't care. Adjacent colors (e.g. c0 vs c1 in an X direction) should be the same.
scale := imageDstSize()/imageSrc0Size()
rate := clamp(p*scale, 0, 1)
return mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y)
}

View File

@ -737,7 +737,7 @@ var _ [len(DrawRectShaderOptions{}.Images)]struct{} = [graphics.ShaderImageCount
// but these are invalid since texCoord is expected to be in texels in the texel-unit mode.
// This behavior is preserved for backward compatibility. It is recommended to use the pixel-unit mode to avoid confusion.
//
// If no source images are specified, imageSrcRegionOnTexture returns a valid size only when the unit is pixels,
// If no source images are specified, imageSrc0Size returns a valid size only when the unit is pixels,
// but always returns 0 when the unit is texels (default).
//
// When the image i is disposed, DrawRectShader does nothing.
@ -777,8 +777,8 @@ func (i *Image) DrawRectShader(width, height int, shader *Shader, options *DrawR
for i, img := range options.Images {
if img == nil {
if shader.unit == shaderir.Pixels && i == 0 {
// Give the source size as pixels only when the unit is pixels so that users can get the source size via imageSrcRegionOnTexture (#2166).
// With the texel mode, the imageSrcRegionOnTexture values should be in texels so the source position in pixels would not match.
// Give the source size as pixels only when the unit is pixels so that users can get the source size via imageSrc0Size (#2166).
// With the texel mode, the imageSrc0Origin and imageSrc0Size values should be in texels so the source position in pixels would not match.
srcRegions[i] = graphicsdriver.Region{
Width: float32(width),
Height: float32(height),

View File

@ -61,7 +61,8 @@ var ColorMTranslation vec4
{{if eq .Address .AddressRepeat}}
func adjustTexelForAddressRepeat(p vec2) vec2 {
origin, size := imageSrcRegionOnTexture()
origin := imageSrc0Origin()
size := imageSrc0Size()
return mod(p - origin, size) + origin
}
{{end}}

View File

@ -23,19 +23,17 @@ import (
)
func shaderSuffix(unit shaderir.Unit) (string, error) {
shaderSuffix := `
shaderSuffix := fmt.Sprintf(`
var __imageDstTextureSize vec2
// imageSrcTextureSize returns the destination image's texture size in pixels.
func imageDstTextureSize() vec2 {
return __imageDstTextureSize
}
`
shaderSuffix += fmt.Sprintf(`
var __imageSrcTextureSizes [%[1]d]vec2
// imageSrcTextureSize returns the source image's texture size in pixels.
// imageSrcTextureSize returns the 0th source image's texture size in pixels.
// As an image is a part of internal texture, the texture is usually bigger than the image.
// The texture's size is useful when you want to calculate pixels from texels in the texel mode.
func imageSrcTextureSize() vec2 {
@ -52,26 +50,60 @@ var __imageDstRegionSize vec2
// The unit is the source texture's pixel or texel.
//
// As an image is a part of internal texture, the image can be located at an arbitrary position on the texture.
//
// Deprecated: as of v2.6. Use imageDstOrigin or imageDstSize.
func imageDstRegionOnTexture() (vec2, vec2) {
return __imageDstRegionOrigin, __imageDstRegionSize
}
// imageDstRegionOnTexture returns the destination image's origin on its texture.
// The unit is the source texture's pixel or texel.
//
// As an image is a part of internal texture, the image can be located at an arbitrary position on the texture.
func imageDstOrigin() vec2 {
return __imageDstRegionOrigin
}
// imageDstRegionOnTexture returns the destination image's size.
// The unit is the source texture's pixel or texel.
func imageDstSize() vec2 {
return __imageDstRegionSize
}
// The unit is the source texture's pixel or texel.
var __imageSrcRegionOrigins [%[1]d]vec2
// The unit is the source texture's pixel or texel.
var __imageSrcRegionSizes [%[1]d]vec2
// imageSrcRegionOnTexture returns the source image's region (the origin and the size) on its texture.
// imageSrcRegionOnTexture returns the 0th source image's region (the origin and the size) on its texture.
// The unit is the source texture's pixel or texel.
//
// As an image is a part of internal texture, the image can be located at an arbitrary position on the texture.
//
// Deprecated: as of v2.6. Use imageSrc0Origin or imageSrc0Size instead.
func imageSrcRegionOnTexture() (vec2, vec2) {
return __imageSrcRegionOrigins[0], __imageSrcRegionSizes[0]
}
`, ShaderImageCount)
for i := 0; i < ShaderImageCount; i++ {
shaderSuffix += fmt.Sprintf(`
// imageSrc%[1]dOrigin returns the source image's region origin on its texture.
// The unit is the source texture's pixel or texel.
//
// As an image is a part of internal texture, the image can be located at an arbitrary position on the texture.
func imageSrc%[1]dOrigin() vec2 {
return __imageSrcRegionOrigins[%[1]d]
}
// imageSrc%[1]dSize returns the source image's size.
// The unit is the source texture's pixel or texel.
func imageSrc%[1]dSize() vec2 {
return __imageSrcRegionSizes[%[1]d]
}
`, i)
pos := "pos"
if i >= 1 {
// Convert the position in texture0's positions to the target texture positions.

View File

@ -1332,9 +1332,8 @@ package main
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
// Adjust texCoord into [0, 1].
origin, size := imageSrcRegionOnTexture()
texCoord -= origin
texCoord /= size
texCoord -= imageSrc0Origin()
texCoord /= imageSrc0Size()
if texCoord.x >= 0.5 && texCoord.y >= 0.5 {
return vec4(1, 0, 0, 1)
}
@ -1721,8 +1720,7 @@ func TestShaderTexelAndPixel(t *testing.T) {
package main
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
orig, size := imageSrcRegionOnTexture()
pos := (texCoord - orig) / size
pos := (texCoord - imageSrc0Origin()) / imageSrc0Size()
pos *= vec2(%d, %d)
pos /= 255
return vec4(pos.x, pos.y, 0, 1)
@ -1736,8 +1734,7 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
package main
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
orig, _ := imageSrcRegionOnTexture()
pos := texCoord - orig
pos := texCoord - imageSrc0Origin()
pos /= 255
return vec4(pos.x, pos.y, 0, 1)
}
@ -1835,9 +1832,8 @@ func TestShaderIVec(t *testing.T) {
package main
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
orig, _ := imageSrcRegionOnTexture()
pos := ivec2(3, 4)
return imageSrc0At(vec2(pos) + orig)
return imageSrc0At(vec2(pos) + imageSrc0Origin())
}
`))
if err != nil {
@ -2032,7 +2028,7 @@ package main
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
t := texCoord
origin, size := imageSrcRegionOnTexture()
size := imageSrc0Size()
// If the unit is texels and no source images are specified, size is always 0.
if size == vec2(0) {
@ -2044,7 +2040,7 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
}
// Adjust texCoord into [0, 1].
t -= origin
t -= imageSrc0Origin()
if size != vec2(0) {
t /= size
}