From fc4d3dbd9e46ac0b50f5905f524e6d984cc0acb9 Mon Sep 17 00:00:00 2001 From: Thomas Friedel Date: Thu, 21 Feb 2019 17:05:46 +0100 Subject: [PATCH] moved image data code into backend --- backend/backendbase/base.go | 3 ++ backend/gogl/gogl.go | 12 +++-- backend/gogl/imagedata.go | 94 ++++++++++++++++++++++++++++++++++++ imagedata.go | 96 ------------------------------------- images.go | 10 ++++ 5 files changed, 116 insertions(+), 99 deletions(-) create mode 100644 backend/gogl/imagedata.go delete mode 100644 imagedata.go diff --git a/backend/backendbase/base.go b/backend/backendbase/base.go index 46f4b41..205af19 100644 --- a/backend/backendbase/base.go +++ b/backend/backendbase/base.go @@ -19,6 +19,9 @@ type Backend interface { Fill(style *FillStyle, pts [][2]float64) DrawImage(dimg Image, sx, sy, sw, sh, dx, dy, dw, dh float64, alpha float64) FillImageMask(style *FillStyle, mask *image.Alpha, pts [][2]float64) // pts must have four points + + GetImageData(x, y, w, h int) *image.RGBA + PutImageData(img *image.RGBA, x, y int) } // FillStyle is the color and other details on how to fill diff --git a/backend/gogl/gogl.go b/backend/gogl/gogl.go index 1689c7e..720641d 100644 --- a/backend/gogl/gogl.go +++ b/backend/gogl/gogl.go @@ -20,6 +20,7 @@ type GoGLBackend struct { buf uint32 shadowBuf uint32 alphaTex uint32 + sr solidShader lgr linearGradientShader rgr radialGradientShader @@ -32,11 +33,16 @@ type GoGLBackend struct { gauss15r gaussianShader gauss63r gaussianShader gauss127r gaussianShader - offscr1 offscreenBuffer - offscr2 offscreenBuffer - glChan chan func() + + offscr1 offscreenBuffer + offscr2 offscreenBuffer + + imageBufTex uint32 + imageBuf []byte ptsBuf []float32 + + glChan chan func() } type offscreenBuffer struct { diff --git a/backend/gogl/imagedata.go b/backend/gogl/imagedata.go new file mode 100644 index 0000000..d2fb0e6 --- /dev/null +++ b/backend/gogl/imagedata.go @@ -0,0 +1,94 @@ +package goglbackend + +import ( + "image" + "image/color" + "unsafe" + + "github.com/go-gl/gl/v3.2-core/gl" +) + +// GetImageData returns an RGBA image of the current image +func (b *GoGLBackend) GetImageData(x, y, w, h int) *image.RGBA { + // cv.activate() + + if x < 0 { + w += x + x = 0 + } + if y < 0 { + h += y + y = 0 + } + if w > b.w { + w = b.w + } + if h > b.h { + h = b.h + } + if len(b.imageBuf) < w*h*3 { + b.imageBuf = make([]byte, w*h*3) + } + + gl.ReadPixels(int32(x), int32(y), int32(w), int32(h), gl.RGB, gl.UNSIGNED_BYTE, gl.Ptr(&b.imageBuf[0])) + rgba := image.NewRGBA(image.Rect(x, y, x+w, y+h)) + bp := 0 + for cy := y; cy < y+h; cy++ { + for cx := x; cx < x+w; cx++ { + rgba.SetRGBA(cx, y+h-1-cy, color.RGBA{R: b.imageBuf[bp], G: b.imageBuf[bp+1], B: b.imageBuf[bp+2], A: 255}) + bp += 3 + } + } + return rgba +} + +// PutImageData puts the given image at the given x/y coordinates +func (b *GoGLBackend) PutImageData(img *image.RGBA, x, y int) { + // cv.activate() + + gl.ActiveTexture(gl.TEXTURE0) + if b.imageBufTex == 0 { + gl.GenTextures(1, &b.imageBufTex) + gl.BindTexture(gl.TEXTURE_2D, b.imageBufTex) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE) + } else { + gl.BindTexture(gl.TEXTURE_2D, b.imageBufTex) + } + + w, h := img.Bounds().Dx(), img.Bounds().Dy() + + if img.Stride == img.Bounds().Dx()*4 { + gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, int32(w), int32(h), 0, gl.RGBA, gl.UNSIGNED_BYTE, gl.Ptr(&img.Pix[0])) + } else { + data := make([]uint8, 0, w*h*4) + for cy := 0; cy < h; cy++ { + start := cy * img.Stride + end := start + w*4 + data = append(data, img.Pix[start:end]...) + } + gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, int32(w), int32(h), 0, gl.RGBA, gl.UNSIGNED_BYTE, gl.Ptr(&data[0])) + } + + dx, dy := float32(x), float32(y) + dw, dh := float32(w), float32(h) + + gl.BindBuffer(gl.ARRAY_BUFFER, b.buf) + data := [16]float32{dx, dy, dx + dw, dy, dx + dw, dy + dh, dx, dy + dh, + 0, 0, 1, 0, 1, 1, 0, 1} + gl.BufferData(gl.ARRAY_BUFFER, len(data)*4, unsafe.Pointer(&data[0]), gl.STREAM_DRAW) + + gl.UseProgram(b.ir.ID) + gl.Uniform1i(b.ir.Image, 0) + gl.Uniform2f(b.ir.CanvasSize, float32(b.fw), float32(b.fh)) + gl.Uniform1f(b.ir.GlobalAlpha, 1) + gl.VertexAttribPointer(b.ir.Vertex, 2, gl.FLOAT, false, 0, nil) + gl.VertexAttribPointer(b.ir.TexCoord, 2, gl.FLOAT, false, 0, gl.PtrOffset(8*4)) + gl.EnableVertexAttribArray(b.ir.Vertex) + gl.EnableVertexAttribArray(b.ir.TexCoord) + gl.DrawArrays(gl.TRIANGLE_FAN, 0, 4) + gl.DisableVertexAttribArray(b.ir.Vertex) + gl.DisableVertexAttribArray(b.ir.TexCoord) +} diff --git a/imagedata.go b/imagedata.go deleted file mode 100644 index 07354d1..0000000 --- a/imagedata.go +++ /dev/null @@ -1,96 +0,0 @@ -package canvas - -import ( - "image" - "image/color" - "unsafe" -) - -var imageBufTex uint32 -var imageBuf []byte - -// GetImageData returns an RGBA image of the currently displayed image. The -// alpha channel is always opaque -func (cv *Canvas) GetImageData(x, y, w, h int) *image.RGBA { - cv.activate() - - if x < 0 { - w += x - x = 0 - } - if y < 0 { - h += y - y = 0 - } - if w > cv.w { - w = cv.w - } - if h > cv.h { - h = cv.h - } - if len(imageBuf) < w*h*3 { - imageBuf = make([]byte, w*h*3) - } - - gli.ReadPixels(int32(x), int32(y), int32(w), int32(h), gl_RGB, gl_UNSIGNED_BYTE, gli.Ptr(&imageBuf[0])) - rgba := image.NewRGBA(image.Rect(x, y, x+w, y+h)) - bp := 0 - for cy := y; cy < y+h; cy++ { - for cx := x; cx < x+w; cx++ { - rgba.SetRGBA(cx, y+h-1-cy, color.RGBA{R: imageBuf[bp], G: imageBuf[bp+1], B: imageBuf[bp+2], A: 255}) - bp += 3 - } - } - return rgba -} - -// PutImageData puts the given image at the given x/y coordinates -func (cv *Canvas) PutImageData(img *image.RGBA, x, y int) { - cv.activate() - - gli.ActiveTexture(gl_TEXTURE0) - if imageBufTex == 0 { - gli.GenTextures(1, &imageBufTex) - gli.BindTexture(gl_TEXTURE_2D, imageBufTex) - gli.TexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MIN_FILTER, gl_LINEAR) - gli.TexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MAG_FILTER, gl_LINEAR) - gli.TexParameteri(gl_TEXTURE_2D, gl_TEXTURE_WRAP_S, gl_CLAMP_TO_EDGE) - gli.TexParameteri(gl_TEXTURE_2D, gl_TEXTURE_WRAP_T, gl_CLAMP_TO_EDGE) - } else { - gli.BindTexture(gl_TEXTURE_2D, imageBufTex) - } - - w, h := img.Bounds().Dx(), img.Bounds().Dy() - - if img.Stride == img.Bounds().Dx()*4 { - gli.TexImage2D(gl_TEXTURE_2D, 0, gl_RGBA, int32(w), int32(h), 0, gl_RGBA, gl_UNSIGNED_BYTE, gli.Ptr(&img.Pix[0])) - } else { - data := make([]uint8, 0, w*h*4) - for cy := 0; cy < h; cy++ { - start := cy * img.Stride - end := start + w*4 - data = append(data, img.Pix[start:end]...) - } - gli.TexImage2D(gl_TEXTURE_2D, 0, gl_RGBA, int32(w), int32(h), 0, gl_RGBA, gl_UNSIGNED_BYTE, gli.Ptr(&data[0])) - } - - dx, dy := float32(x), float32(y) - dw, dh := float32(w), float32(h) - - gli.BindBuffer(gl_ARRAY_BUFFER, buf) - data := [16]float32{dx, dy, dx + dw, dy, dx + dw, dy + dh, dx, dy + dh, - 0, 0, 1, 0, 1, 1, 0, 1} - gli.BufferData(gl_ARRAY_BUFFER, len(data)*4, unsafe.Pointer(&data[0]), gl_STREAM_DRAW) - - gli.UseProgram(ir.id) - gli.Uniform1i(ir.image, 0) - gli.Uniform2f(ir.canvasSize, float32(cv.fw), float32(cv.fh)) - gli.Uniform1f(ir.globalAlpha, 1) - gli.VertexAttribPointer(ir.vertex, 2, gl_FLOAT, false, 0, 0) - gli.VertexAttribPointer(ir.texCoord, 2, gl_FLOAT, false, 0, 8*4) - gli.EnableVertexAttribArray(ir.vertex) - gli.EnableVertexAttribArray(ir.texCoord) - gli.DrawArrays(gl_TRIANGLE_FAN, 0, 4) - gli.DisableVertexAttribArray(ir.vertex) - gli.DisableVertexAttribArray(ir.texCoord) -} diff --git a/images.go b/images.go index 4db66bf..f8a96e5 100644 --- a/images.go +++ b/images.go @@ -172,3 +172,13 @@ func (cv *Canvas) DrawImage(image interface{}, coords ...float64) { cv.b.DrawImage(img.img, sx, sy, sw, sh, dx, dy, dw, dh, cv.state.globalAlpha) } + +// GetImageData returns an RGBA image of the current image +func (cv *Canvas) GetImageData(x, y, w, h int) *image.RGBA { + return cv.b.GetImageData(x, y, w, h) +} + +// PutImageData puts the given image at the given x/y coordinates +func (cv *Canvas) PutImageData(img *image.RGBA, x, y int) { + cv.b.PutImageData(img, x, y) +}