diff --git a/gl/api.go b/gl/api.go index 77ecfc21..1f479cae 100644 --- a/gl/api.go +++ b/gl/api.go @@ -114,6 +114,8 @@ type API interface { GetError() uint32 // ReadPixels reads a block of pixels from the frame buffer ReadPixels(x int32, y int32, width int32, height int32, format uint32, xtype uint32, pixels unsafe.Pointer) + // Finish blocks until all GL execution is complete + Finish() // Ptr takes a slice or pointer (to a singular scalar value or the first // element of an array or slice) and returns its GL-compatible address. // diff --git a/gl/command.go b/gl/command.go index 0b92e3e0..4b880a66 100644 --- a/gl/command.go +++ b/gl/command.go @@ -199,18 +199,30 @@ func (c *AcceleratedCommand) Run(output image.AcceleratedImageSelection, selecti panic("output image created in a different OpenGL context than program") } - c.program.use() - c.api.Enable(scissorTest) - c.api.BindFramebuffer(framebuffer, img.frameBufferID) loc := output.Location - locHeight := loc.Height - if locHeight > img.height { - locHeight = img.height + if loc.X >= img.width { + return + } + if loc.Y >= img.height { + return } x := int32(loc.X) - y := int32(img.height - locHeight - loc.Y) + y := int32(loc.Y) w := int32(loc.Width) - h := int32(locHeight) + h := int32(loc.Height) + if x < 0 { + w += x + x = 0 + } + if y < 0 { + h += y + y = 0 + } + y = int32(img.height) - h - y + + c.program.use() + c.api.Enable(scissorTest) + c.api.BindFramebuffer(framebuffer, img.frameBufferID) c.api.Scissor(x, y, w, h) c.api.Viewport(x, y, w, h) diff --git a/gl/gl_test.go b/gl/gl_test.go index 3d10cae8..b2540efd 100644 --- a/gl/gl_test.go +++ b/gl/gl_test.go @@ -535,5 +535,6 @@ func (a apiStub) GetTexImage(target uint32, level int32, format uint32, xtype ui func (a apiStub) GetError() uint32 { return 0 } func (a apiStub) ReadPixels(x int32, y int32, width int32, height int32, format uint32, xtype uint32, pixels unsafe.Pointer) { } +func (a apiStub) Finish() {} func (a apiStub) Ptr(data interface{}) unsafe.Pointer { return nil } func (a apiStub) PtrOffset(offset int) unsafe.Pointer { return nil } diff --git a/gl/integration/glfw/opengl_integration_test.go b/gl/integration/glfw/opengl_integration_test.go index c0c05702..b2462bab 100644 --- a/gl/integration/glfw/opengl_integration_test.go +++ b/gl/integration/glfw/opengl_integration_test.go @@ -510,16 +510,46 @@ func TestAcceleratedCommand_Run(t *testing.T) { location: image.AcceleratedImageLocation{}, expectedColors: []image.Color{image.Transparent}, }, - "x out of bounds": { + "x equal image width": { width: 1, height: 1, location: image.AcceleratedImageLocation{X: 1, Width: 1, Height: 1}, expectedColors: []image.Color{image.Transparent}, }, - "y out of bounds": { + "x higher than image width": { + width: 1, height: 1, + location: image.AcceleratedImageLocation{X: 2, Width: 1, Height: 1}, + expectedColors: []image.Color{image.Transparent}, + }, + "negative x": { + width: 1, height: 1, + location: image.AcceleratedImageLocation{X: -1, Width: 1, Height: 1}, + expectedColors: []image.Color{image.Transparent}, + }, + "negative x, width 2": { + width: 1, height: 1, + location: image.AcceleratedImageLocation{X: -1, Width: 2, Height: 1}, + expectedColors: []image.Color{color}, + }, + "y equal image height": { width: 1, height: 1, location: image.AcceleratedImageLocation{Y: 1, Width: 1, Height: 1}, expectedColors: []image.Color{image.Transparent}, }, + "y higher than image height": { + width: 1, height: 1, + location: image.AcceleratedImageLocation{Y: 2, Width: 1, Height: 1}, + expectedColors: []image.Color{image.Transparent}, + }, + "negative y": { + width: 1, height: 1, + location: image.AcceleratedImageLocation{Y: -1, Width: 1, Height: 1}, + expectedColors: []image.Color{image.Transparent}, + }, + "negative y, height 2": { + width: 1, height: 1, + location: image.AcceleratedImageLocation{Y: -1, Width: 1, Height: 2}, + expectedColors: []image.Color{color}, + }, "whole image": { width: 1, height: 1, location: image.AcceleratedImageLocation{Width: 1, Height: 1}, diff --git a/glfw/gl_api.go b/glfw/gl_api.go index 7d5e22e2..3790c589 100644 --- a/glfw/gl_api.go +++ b/glfw/gl_api.go @@ -404,6 +404,13 @@ func (g *context) ReadPixels(x int32, y int32, width int32, height int32, format }) } +// Finish blocks until all GL execution is complete +func (g *context) Finish() { + g.run(func() { + gl.Finish() + }) +} + // Ptr takes a slice or pointer (to a singular scalar value or the first // element of an array or slice) and returns its GL-compatible address. // diff --git a/glfw/glfw.go b/glfw/glfw.go index 817af126..2e768bb7 100644 --- a/glfw/glfw.go +++ b/glfw/glfw.go @@ -197,13 +197,13 @@ func (g *OpenGL) OpenWindow(width, height int, options ...WindowOption) (*Window screenAcceleratedImage := g.context.NewAcceleratedImage(width, height) screenImage := image.New(width, height, screenAcceleratedImage) win := &Window{ - mainThreadLoop: g.mainThreadLoop, - keyboardEvents: keyboardEvents, - requestedWidth: width, - requestedHeight: height, - screenAcceleratedImage: screenAcceleratedImage, - screenImage: screenImage, - zoom: 1, + mainThreadLoop: g.mainThreadLoop, + keyboardEvents: keyboardEvents, + requestedWidth: width, + requestedHeight: height, + screenImage: screenImage, + screenContextAPI: g.context.API(), + zoom: 1, } var err error g.mainThreadLoop.Execute(func() { @@ -247,7 +247,7 @@ func (g *OpenGL) OpenWindow(width, height int, options ...WindowOption) (*Window } // in this window context there is only one program used with one texture win.api.UseProgram(win.program.ID()) - win.api.BindTexture(gl33.TEXTURE_2D, win.screenAcceleratedImage.TextureID()) + win.api.BindTexture(gl33.TEXTURE_2D, screenAcceleratedImage.TextureID()) return win, nil } diff --git a/glfw/window.go b/glfw/window.go index 36e99375..0e2635e5 100644 --- a/glfw/window.go +++ b/glfw/window.go @@ -11,24 +11,25 @@ import ( // Window is an implementation of loop.Screen and keyboard.EventSource type Window struct { - glfwWindow *glfw.Window - mainThreadLoop *MainThreadLoop - screenPolygon *screenPolygon - keyboardEvents *internal.KeyboardEvents - requestedWidth int - requestedHeight int - zoom int - screenImage *image.Image - screenAcceleratedImage *gl.AcceleratedImage - api gl.API - context *gl.Context - program *gl.Program + glfwWindow *glfw.Window + mainThreadLoop *MainThreadLoop + screenPolygon *screenPolygon + keyboardEvents *internal.KeyboardEvents + requestedWidth int + requestedHeight int + zoom int + screenImage *image.Image + screenContextAPI gl.API + api gl.API + context *gl.Context + program *gl.Program } // Draw draws a screen image to the invisible buffer. It will be shown in window // after SwapImages is called. func (w *Window) Draw() { w.screenImage.Upload() + w.screenContextAPI.Finish() var width, height int w.mainThreadLoop.Execute(func() { width, height = w.glfwWindow.GetFramebufferSize()