diff --git a/backend/backendbase/base.go b/backend/backendbase/base.go index e96e589..eb6ef7b 100644 --- a/backend/backendbase/base.go +++ b/backend/backendbase/base.go @@ -107,7 +107,8 @@ type Image interface { } type ImagePatternData struct { - Image Image + Image Image + Transform [9]float64 } type ImagePattern interface { diff --git a/backend/gogl/gogl.go b/backend/gogl/gogl.go index 38d38b5..1c577e7 100644 --- a/backend/gogl/gogl.go +++ b/backend/gogl/gogl.go @@ -432,13 +432,19 @@ func (b *GoGLBackend) useShader(style *backendbase.FillStyle) (vertexLoc uint32) return b.rgr.Vertex } if ip := style.ImagePattern; ip != nil { - img := ip.(*ImagePattern).data.Image.(*Image) + ipd := ip.(*ImagePattern).data + img := ipd.Image.(*Image) gl.UseProgram(b.ipr.ID) gl.ActiveTexture(gl.TEXTURE0) gl.BindTexture(gl.TEXTURE_2D, img.tex) gl.Uniform2f(b.ipr.CanvasSize, float32(b.fw), float32(b.fh)) gl.Uniform2f(b.ipr.ImageSize, float32(img.w), float32(img.h)) gl.Uniform1i(b.ipr.Image, 0) + var f32mat [9]float32 + for i, v := range ipd.Transform { + f32mat[i] = float32(v) + } + gl.UniformMatrix3fv(b.ipr.ImageTransform, 1, false, &f32mat[0]) gl.Uniform1f(b.ipr.GlobalAlpha, float32(style.Color.A)/255) return b.ipr.Vertex } @@ -489,13 +495,19 @@ func (b *GoGLBackend) useAlphaShader(style *backendbase.FillStyle, alphaTexSlot return b.rgar.Vertex, b.rgar.AlphaTexCoord } if ip := style.ImagePattern; ip != nil { - img := ip.(*ImagePattern).data.Image.(*Image) + ipd := ip.(*ImagePattern).data + img := ipd.Image.(*Image) gl.UseProgram(b.ipar.ID) gl.ActiveTexture(gl.TEXTURE0) gl.BindTexture(gl.TEXTURE_2D, img.tex) gl.Uniform2f(b.ipar.CanvasSize, float32(b.fw), float32(b.fh)) gl.Uniform2f(b.ipar.ImageSize, float32(img.w), float32(img.h)) gl.Uniform1i(b.ipar.Image, 0) + var f32mat [9]float32 + for i, v := range ipd.Transform { + f32mat[i] = float32(v) + } + gl.UniformMatrix3fv(b.ipr.ImageTransform, 1, false, &f32mat[0]) gl.Uniform1i(b.ipar.AlphaTex, alphaTexSlot) gl.Uniform1f(b.ipar.GlobalAlpha, float32(style.Color.A)/255) return b.ipar.Vertex, b.ipar.AlphaTexCoord diff --git a/backend/gogl/shaders.go b/backend/gogl/shaders.go index c9c6605..32eac02 100755 --- a/backend/gogl/shaders.go +++ b/backend/gogl/shaders.go @@ -132,9 +132,11 @@ precision mediump float; varying vec2 v_cp; uniform vec2 imageSize; uniform sampler2D image; +uniform mat3 imageTransform; uniform float globalAlpha; void main() { - vec4 col = texture2D(image, mod(v_cp / imageSize, 1.0)); + vec3 tfp = vec3(v_cp, 1.0) * imageTransform; + vec4 col = texture2D(image, mod(tfp.xy / imageSize, 1.0)); col.a *= globalAlpha; gl_FragColor = col; }` @@ -259,10 +261,12 @@ varying vec2 v_cp; varying vec2 v_atc; uniform vec2 imageSize; uniform sampler2D image; +uniform mat3 imageTransform; uniform sampler2D alphaTex; uniform float globalAlpha; void main() { - vec4 col = texture2D(image, mod(v_cp / imageSize, 1.0)); + vec3 tfp = vec3(v_cp, 1.0) * imageTransform; + vec4 col = texture2D(image, mod(tfp.xy / imageSize, 1.0)); col.a *= texture2D(alphaTex, v_atc).a * globalAlpha; gl_FragColor = col; }` @@ -400,11 +404,12 @@ type radialGradientShader struct { type imagePatternShader struct { shaderProgram - Vertex uint32 - CanvasSize int32 - ImageSize int32 - Image int32 - GlobalAlpha int32 + Vertex uint32 + CanvasSize int32 + ImageSize int32 + Image int32 + ImageTransform int32 + GlobalAlpha int32 } type solidAlphaShader struct { @@ -446,13 +451,14 @@ type radialGradientAlphaShader struct { type imagePatternAlphaShader struct { shaderProgram - Vertex uint32 - AlphaTexCoord uint32 - CanvasSize int32 - ImageSize int32 - Image int32 - AlphaTex int32 - GlobalAlpha int32 + Vertex uint32 + AlphaTexCoord uint32 + CanvasSize int32 + ImageSize int32 + Image int32 + ImageTransform int32 + AlphaTex int32 + GlobalAlpha int32 } type gaussianShader struct { diff --git a/images.go b/images.go index 0c31e77..5a14020 100644 --- a/images.go +++ b/images.go @@ -189,15 +189,29 @@ func (cv *Canvas) PutImageData(img *image.RGBA, x, y int) { type ImagePattern struct { cv *Canvas img *Image + tf [9]float64 ip backendbase.ImagePattern } func (ip *ImagePattern) data() backendbase.ImagePatternData { return backendbase.ImagePatternData{ - Image: ip.img.img, + Image: ip.img.img, + Transform: ip.tf, } } +// SetTransform changes the transformation of the image pattern +// to the given matrix. The matrix is a 3x3 matrix, but three +// of the values are always identity values +func (ip *ImagePattern) SetTransform(tf [6]float64) { + ip.tf = [9]float64{ + tf[0], tf[1], 0, + tf[2], tf[3], 0, + tf[4], tf[5], 1, + } + ip.ip.Replace(ip.data()) +} + // CreatePattern creates a new image pattern with the specified // image and repetition func (cv *Canvas) CreatePattern(src interface{}, repetition string) *ImagePattern {