From db34930ae889b05f3e6c290e1529944f621b3699 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Mon, 28 Aug 2023 03:39:27 +0900 Subject: [PATCH] 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 --- examples/flappy/crt.go | 3 +- examples/shader/chromaticaberration.go | 3 +- examples/shader/default.go | 5 ++- examples/shader/lighting.go | 3 +- examples/shader/radialblur.go | 3 +- examples/shader/texel.go | 5 ++- examples/shader/water.go | 7 ++--- gameforui.go | 9 ++---- image.go | 6 ++-- internal/builtinshader/shader.go | 3 +- internal/graphics/shader.go | 42 +++++++++++++++++++++++--- shader_test.go | 18 +++++------ 12 files changed, 64 insertions(+), 43 deletions(-) diff --git a/examples/flappy/crt.go b/examples/flappy/crt.go index 9c2b060e4..1d21ed67e 100644 --- a/examples/flappy/crt.go +++ b/examples/flappy/crt.go @@ -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 diff --git a/examples/shader/chromaticaberration.go b/examples/shader/chromaticaberration.go index f8bafc483..c1469478e 100644 --- a/examples/shader/chromaticaberration.go +++ b/examples/shader/chromaticaberration.go @@ -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 diff --git a/examples/shader/default.go b/examples/shader/default.go index 483f49da7..37b8677f8 100644 --- a/examples/shader/default.go +++ b/examples/shader/default.go @@ -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) diff --git a/examples/shader/lighting.go b/examples/shader/lighting.go index 2786224ff..b80b00e74 100644 --- a/examples/shader/lighting.go +++ b/examples/shader/lighting.go @@ -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)) diff --git a/examples/shader/radialblur.go b/examples/shader/radialblur.go index c77058969..19c45f50b 100644 --- a/examples/shader/radialblur.go +++ b/examples/shader/radialblur.go @@ -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) diff --git a/examples/shader/texel.go b/examples/shader/texel.go index 74b3c2ec0..1f6c18cfa 100644 --- a/examples/shader/texel.go +++ b/examples/shader/texel.go @@ -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) } diff --git a/examples/shader/water.go b/examples/shader/water.go index d07aadd4a..56250b0f6 100644 --- a/examples/shader/water.go +++ b/examples/shader/water.go @@ -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, diff --git a/gameforui.go b/gameforui.go index bf56f3790..10e390b2a 100644 --- a/gameforui.go +++ b/gameforui.go @@ -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) } diff --git a/image.go b/image.go index 374d04f00..f4f4f2c15 100644 --- a/image.go +++ b/image.go @@ -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), diff --git a/internal/builtinshader/shader.go b/internal/builtinshader/shader.go index 620c0535c..781b6242a 100644 --- a/internal/builtinshader/shader.go +++ b/internal/builtinshader/shader.go @@ -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}} diff --git a/internal/graphics/shader.go b/internal/graphics/shader.go index 99fe7125e..f13287f22 100644 --- a/internal/graphics/shader.go +++ b/internal/graphics/shader.go @@ -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. diff --git a/shader_test.go b/shader_test.go index af43e09bf..bc753118f 100644 --- a/shader_test.go +++ b/shader_test.go @@ -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 }