Skip to content

Commit

Permalink
internal/graphics: add built-in Kage functions
Browse files Browse the repository at this point in the history
This change adds these Kage functions:

* imageDstOrigin
* imageDstSrc
* imageSrcNOrigin
* imageSrcNSrc

and deprecates these functions:

* imageDstRegionOnTexture
* imageSrcRegionOnTexture

Closes #1870
  • Loading branch information
hajimehoshi committed Aug 28, 2023
1 parent 101c9cb commit db34930
Show file tree
Hide file tree
Showing 12 changed files with 64 additions and 43 deletions.
3 changes: 2 additions & 1 deletion examples/flappy/crt.go
Expand Up @@ -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

Expand Down
3 changes: 1 addition & 2 deletions examples/shader/chromaticaberration.go
Expand Up @@ -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
Expand Down
5 changes: 2 additions & 3 deletions examples/shader/default.go
Expand Up @@ -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)
Expand Down
3 changes: 1 addition & 2 deletions examples/shader/lighting.go
Expand Up @@ -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))
Expand Down
3 changes: 1 addition & 2 deletions examples/shader/radialblur.go
Expand Up @@ -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)
Expand Down
5 changes: 2 additions & 3 deletions examples/shader/texel.go
Expand Up @@ -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)
}
7 changes: 3 additions & 4 deletions examples/shader/water.go
Expand Up @@ -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,
Expand Down
9 changes: 3 additions & 6 deletions gameforui.go
Expand Up @@ -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
Expand All @@ -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)
}
Expand Down
6 changes: 3 additions & 3 deletions image.go
Expand Up @@ -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.
Expand Down Expand Up @@ -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),
Expand Down
3 changes: 2 additions & 1 deletion internal/builtinshader/shader.go
Expand Up @@ -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}}
Expand Down
42 changes: 37 additions & 5 deletions internal/graphics/shader.go
Expand Up @@ -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 {
Expand All @@ -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.
Expand Down
18 changes: 7 additions & 11 deletions shader_test.go
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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)
Expand All @@ -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)
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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) {
Expand All @@ -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
}
Expand Down

0 comments on commit db34930

Please sign in to comment.