go-opengl-pixel/pixelgl/glframe.go

100 lines
2.2 KiB
Go

package pixelgl
import (
"github.com/faiface/glhf"
"github.com/faiface/mainthread"
"github.com/faiface/pixel"
)
// GLFrame is a type that helps implementing OpenGL Targets. It implements most common methods to
// avoid code redundancy. It contains an glhf.Frame that you can draw on.
type GLFrame struct {
frame *glhf.Frame
bounds pixel.Rect
pixels []uint8
dirty bool
}
// NewGLFrame creates a new GLFrame with the given bounds.
func NewGLFrame(bounds pixel.Rect) *GLFrame {
gf := new(GLFrame)
gf.SetBounds(bounds)
return gf
}
// SetBounds resizes the GLFrame to the new bounds.
func (gf *GLFrame) SetBounds(bounds pixel.Rect) {
if bounds == gf.Bounds() {
return
}
mainthread.Call(func() {
oldF := gf.frame
_, _, w, h := intBounds(bounds)
gf.frame = glhf.NewFrame(w, h, false)
// preserve old content
if oldF != nil {
ox, oy, ow, oh := intBounds(bounds)
oldF.Blit(
gf.frame,
ox, oy, ox+ow, oy+oh,
ox, oy, ox+ow, oy+oh,
)
}
})
gf.bounds = bounds
gf.pixels = nil
gf.dirty = true
}
// Bounds returns the current GLFrame's bounds.
func (gf *GLFrame) Bounds() pixel.Rect {
return gf.bounds
}
// Color returns the color of the pixel under the specified position.
func (gf *GLFrame) Color(at pixel.Vec) pixel.RGBA {
if gf.dirty {
mainthread.Call(func() {
tex := gf.frame.Texture()
tex.Begin()
gf.pixels = tex.Pixels(0, 0, tex.Width(), tex.Height())
tex.End()
})
gf.dirty = false
}
if !gf.bounds.Contains(at) {
return pixel.Alpha(0)
}
bx, by, bw, _ := intBounds(gf.bounds)
x, y := int(at.X)-bx, int(at.Y)-by
off := y*bw + x
return pixel.RGBA{
R: float64(gf.pixels[off*4+0]) / 255,
G: float64(gf.pixels[off*4+1]) / 255,
B: float64(gf.pixels[off*4+2]) / 255,
A: float64(gf.pixels[off*4+3]) / 255,
}
}
// Frame returns the GLFrame's Frame that you can draw on.
func (gf *GLFrame) Frame() *glhf.Frame {
return gf.frame
}
// Texture returns the underlying Texture of the GLFrame's Frame.
//
// Implements GLPicture interface.
func (gf *GLFrame) Texture() *glhf.Texture {
return gf.frame.Texture()
}
// Dirty marks the GLFrame as changed. Always call this method when you draw onto the GLFrame's
// Frame.
func (gf *GLFrame) Dirty() {
gf.dirty = true
}