Use dep to vendor things

This commit is contained in:
2018-03-18 04:23:13 +00:00
parent d572a19352
commit 1ba64f2aa8
123 changed files with 34229 additions and 0 deletions

431
vendor/github.com/faiface/pixel/pixelgl/canvas.go generated vendored Normal file
View File

@@ -0,0 +1,431 @@
package pixelgl
import (
"fmt"
"image/color"
"github.com/faiface/glhf"
"github.com/faiface/mainthread"
"github.com/faiface/pixel"
"github.com/go-gl/mathgl/mgl32"
"github.com/pkg/errors"
)
// Canvas is an off-screen rectangular BasicTarget and Picture at the same time, that you can draw
// onto.
//
// It supports TrianglesPosition, TrianglesColor, TrianglesPicture and PictureColor.
type Canvas struct {
gf *GLFrame
shader *glhf.Shader
cmp pixel.ComposeMethod
mat mgl32.Mat3
col mgl32.Vec4
smooth bool
sprite *pixel.Sprite
}
var _ pixel.ComposeTarget = (*Canvas)(nil)
// NewCanvas creates a new empty, fully transparent Canvas with given bounds.
func NewCanvas(bounds pixel.Rect) *Canvas {
c := &Canvas{
gf: NewGLFrame(bounds),
mat: mgl32.Ident3(),
col: mgl32.Vec4{1, 1, 1, 1},
}
c.SetBounds(bounds)
var shader *glhf.Shader
mainthread.Call(func() {
var err error
shader, err = glhf.NewShader(
canvasVertexFormat,
canvasUniformFormat,
canvasVertexShader,
canvasFragmentShader,
)
if err != nil {
panic(errors.Wrap(err, "failed to create Canvas, there's a bug in the shader"))
}
})
c.shader = shader
return c
}
// MakeTriangles creates a specialized copy of the supplied Triangles that draws onto this Canvas.
//
// TrianglesPosition, TrianglesColor and TrianglesPicture are supported.
func (c *Canvas) MakeTriangles(t pixel.Triangles) pixel.TargetTriangles {
return &canvasTriangles{
GLTriangles: NewGLTriangles(c.shader, t),
dst: c,
}
}
// MakePicture create a specialized copy of the supplied Picture that draws onto this Canvas.
//
// PictureColor is supported.
func (c *Canvas) MakePicture(p pixel.Picture) pixel.TargetPicture {
if cp, ok := p.(*canvasPicture); ok {
return &canvasPicture{
GLPicture: cp.GLPicture,
dst: c,
}
}
if gp, ok := p.(GLPicture); ok {
return &canvasPicture{
GLPicture: gp,
dst: c,
}
}
return &canvasPicture{
GLPicture: NewGLPicture(p),
dst: c,
}
}
// SetMatrix sets a Matrix that every point will be projected by.
func (c *Canvas) SetMatrix(m pixel.Matrix) {
// pixel.Matrix is 3x2 with an implicit 0, 0, 1 row after it. So
// [0] [2] [4] [0] [3] [6]
// [1] [3] [5] => [1] [4] [7]
// 0 0 1 0 0 1
// since all matrix ops are affine, the last row never changes, and we don't need to copy it
for i, j := range [...]int{0, 1, 3, 4, 6, 7} {
c.mat[j] = float32(m[i])
}
}
// SetColorMask sets a color that every color in triangles or a picture will be multiplied by.
func (c *Canvas) SetColorMask(col color.Color) {
rgba := pixel.Alpha(1)
if col != nil {
rgba = pixel.ToRGBA(col)
}
c.col = mgl32.Vec4{
float32(rgba.R),
float32(rgba.G),
float32(rgba.B),
float32(rgba.A),
}
}
// SetComposeMethod sets a Porter-Duff composition method to be used in the following draws onto
// this Canvas.
func (c *Canvas) SetComposeMethod(cmp pixel.ComposeMethod) {
c.cmp = cmp
}
// SetBounds resizes the Canvas to the new bounds. Old content will be preserved.
func (c *Canvas) SetBounds(bounds pixel.Rect) {
c.gf.SetBounds(bounds)
if c.sprite == nil {
c.sprite = pixel.NewSprite(nil, pixel.Rect{})
}
c.sprite.Set(c, c.Bounds())
//c.sprite.SetMatrix(pixel.IM.Moved(c.Bounds().Center()))
}
// Bounds returns the rectangular bounds of the Canvas.
func (c *Canvas) Bounds() pixel.Rect {
return c.gf.Bounds()
}
// SetSmooth sets whether stretched Pictures drawn onto this Canvas should be drawn smooth or
// pixely.
func (c *Canvas) SetSmooth(smooth bool) {
c.smooth = smooth
}
// Smooth returns whether stretched Pictures drawn onto this Canvas are set to be drawn smooth or
// pixely.
func (c *Canvas) Smooth() bool {
return c.smooth
}
// must be manually called inside mainthread
func (c *Canvas) setGlhfBounds() {
_, _, bw, bh := intBounds(c.gf.Bounds())
glhf.Bounds(0, 0, bw, bh)
}
// must be manually called inside mainthread
func setBlendFunc(cmp pixel.ComposeMethod) {
switch cmp {
case pixel.ComposeOver:
glhf.BlendFunc(glhf.One, glhf.OneMinusSrcAlpha)
case pixel.ComposeIn:
glhf.BlendFunc(glhf.DstAlpha, glhf.Zero)
case pixel.ComposeOut:
glhf.BlendFunc(glhf.OneMinusDstAlpha, glhf.Zero)
case pixel.ComposeAtop:
glhf.BlendFunc(glhf.DstAlpha, glhf.OneMinusSrcAlpha)
case pixel.ComposeRover:
glhf.BlendFunc(glhf.OneMinusDstAlpha, glhf.One)
case pixel.ComposeRin:
glhf.BlendFunc(glhf.Zero, glhf.SrcAlpha)
case pixel.ComposeRout:
glhf.BlendFunc(glhf.Zero, glhf.OneMinusSrcAlpha)
case pixel.ComposeRatop:
glhf.BlendFunc(glhf.OneMinusDstAlpha, glhf.SrcAlpha)
case pixel.ComposeXor:
glhf.BlendFunc(glhf.OneMinusDstAlpha, glhf.OneMinusSrcAlpha)
case pixel.ComposePlus:
glhf.BlendFunc(glhf.One, glhf.One)
case pixel.ComposeCopy:
glhf.BlendFunc(glhf.One, glhf.Zero)
default:
panic(errors.New("Canvas: invalid compose method"))
}
}
// Clear fills the whole Canvas with a single color.
func (c *Canvas) Clear(color color.Color) {
c.gf.Dirty()
rgba := pixel.ToRGBA(color)
// color masking
rgba = rgba.Mul(pixel.RGBA{
R: float64(c.col[0]),
G: float64(c.col[1]),
B: float64(c.col[2]),
A: float64(c.col[3]),
})
mainthread.CallNonBlock(func() {
c.setGlhfBounds()
c.gf.Frame().Begin()
glhf.Clear(
float32(rgba.R),
float32(rgba.G),
float32(rgba.B),
float32(rgba.A),
)
c.gf.Frame().End()
})
}
// Color returns the color of the pixel over the given position inside the Canvas.
func (c *Canvas) Color(at pixel.Vec) pixel.RGBA {
return c.gf.Color(at)
}
// Texture returns the underlying OpenGL Texture of this Canvas.
//
// Implements GLPicture interface.
func (c *Canvas) Texture() *glhf.Texture {
return c.gf.Texture()
}
// Frame returns the underlying OpenGL Frame of this Canvas.
func (c *Canvas) Frame() *glhf.Frame {
return c.gf.frame
}
// SetPixels replaces the content of the Canvas with the provided pixels. The provided slice must be
// an alpha-premultiplied RGBA sequence of correct length (4 * width * height).
func (c *Canvas) SetPixels(pixels []uint8) {
c.gf.Dirty()
mainthread.Call(func() {
tex := c.Texture()
tex.Begin()
tex.SetPixels(0, 0, tex.Width(), tex.Height(), pixels)
tex.End()
})
}
// Pixels returns an alpha-premultiplied RGBA sequence of the content of the Canvas.
func (c *Canvas) Pixels() []uint8 {
var pixels []uint8
mainthread.Call(func() {
tex := c.Texture()
tex.Begin()
pixels = tex.Pixels(0, 0, tex.Width(), tex.Height())
tex.End()
})
return pixels
}
// Draw draws the content of the Canvas onto another Target, transformed by the given Matrix, just
// like if it was a Sprite containing the whole Canvas.
func (c *Canvas) Draw(t pixel.Target, matrix pixel.Matrix) {
c.sprite.Draw(t, matrix)
}
// DrawColorMask draws the content of the Canvas onto another Target, transformed by the given
// Matrix and multiplied by the given mask, just like if it was a Sprite containing the whole Canvas.
//
// If the color mask is nil, a fully opaque white mask will be used causing no effect.
func (c *Canvas) DrawColorMask(t pixel.Target, matrix pixel.Matrix, mask color.Color) {
c.sprite.DrawColorMask(t, matrix, mask)
}
type canvasTriangles struct {
*GLTriangles
dst *Canvas
}
func (ct *canvasTriangles) draw(tex *glhf.Texture, bounds pixel.Rect) {
ct.dst.gf.Dirty()
// save the current state vars to avoid race condition
cmp := ct.dst.cmp
mat := ct.dst.mat
col := ct.dst.col
smt := ct.dst.smooth
mainthread.CallNonBlock(func() {
ct.dst.setGlhfBounds()
setBlendFunc(cmp)
frame := ct.dst.gf.Frame()
shader := ct.dst.shader
frame.Begin()
shader.Begin()
dstBounds := ct.dst.Bounds()
shader.SetUniformAttr(canvasBounds, mgl32.Vec4{
float32(dstBounds.Min.X),
float32(dstBounds.Min.Y),
float32(dstBounds.W()),
float32(dstBounds.H()),
})
shader.SetUniformAttr(canvasTransform, mat)
shader.SetUniformAttr(canvasColorMask, col)
if tex == nil {
ct.vs.Begin()
ct.vs.Draw()
ct.vs.End()
} else {
tex.Begin()
bx, by, bw, bh := intBounds(bounds)
shader.SetUniformAttr(canvasTexBounds, mgl32.Vec4{
float32(bx),
float32(by),
float32(bw),
float32(bh),
})
if tex.Smooth() != smt {
tex.SetSmooth(smt)
}
ct.vs.Begin()
ct.vs.Draw()
ct.vs.End()
tex.End()
}
shader.End()
frame.End()
})
}
func (ct *canvasTriangles) Draw() {
ct.draw(nil, pixel.Rect{})
}
type canvasPicture struct {
GLPicture
dst *Canvas
}
func (cp *canvasPicture) Draw(t pixel.TargetTriangles) {
ct := t.(*canvasTriangles)
if cp.dst != ct.dst {
panic(fmt.Errorf("(%T).Draw: TargetTriangles generated by different Canvas", cp))
}
ct.draw(cp.GLPicture.Texture(), cp.GLPicture.Bounds())
}
const (
canvasPosition int = iota
canvasColor
canvasTexCoords
canvasIntensity
)
var canvasVertexFormat = glhf.AttrFormat{
canvasPosition: {Name: "position", Type: glhf.Vec2},
canvasColor: {Name: "color", Type: glhf.Vec4},
canvasTexCoords: {Name: "texCoords", Type: glhf.Vec2},
canvasIntensity: {Name: "intensity", Type: glhf.Float},
}
const (
canvasTransform int = iota
canvasColorMask
canvasBounds
canvasTexBounds
)
var canvasUniformFormat = glhf.AttrFormat{
canvasTransform: {Name: "transform", Type: glhf.Mat3},
canvasColorMask: {Name: "colorMask", Type: glhf.Vec4},
canvasBounds: {Name: "bounds", Type: glhf.Vec4},
canvasTexBounds: {Name: "texBounds", Type: glhf.Vec4},
}
var canvasVertexShader = `
#version 330 core
in vec2 position;
in vec4 color;
in vec2 texCoords;
in float intensity;
out vec4 Color;
out vec2 TexCoords;
out float Intensity;
uniform mat3 transform;
uniform vec4 bounds;
void main() {
vec2 transPos = (transform * vec3(position, 1.0)).xy;
vec2 normPos = (transPos - bounds.xy) / bounds.zw * 2 - vec2(1, 1);
gl_Position = vec4(normPos, 0.0, 1.0);
Color = color;
TexCoords = texCoords;
Intensity = intensity;
}
`
var canvasFragmentShader = `
#version 330 core
in vec4 Color;
in vec2 TexCoords;
in float Intensity;
out vec4 color;
uniform vec4 colorMask;
uniform vec4 texBounds;
uniform sampler2D tex;
void main() {
if (Intensity == 0) {
color = colorMask * Color;
} else {
color = vec4(0, 0, 0, 0);
color += (1 - Intensity) * Color;
vec2 t = (TexCoords - texBounds.xy) / texBounds.zw;
color += Intensity * Color * texture(tex, t);
color *= colorMask;
}
}
`

5
vendor/github.com/faiface/pixel/pixelgl/doc.go generated vendored Normal file
View File

@@ -0,0 +1,5 @@
// Package pixelgl implements efficient OpenGL targets and utilities for the Pixel game development
// library, specifically Window and Canvas.
//
// It also contains a few additional utilities to help extend Pixel with OpenGL graphical effects.
package pixelgl

105
vendor/github.com/faiface/pixel/pixelgl/glframe.go generated vendored Normal file
View File

@@ -0,0 +1,105 @@
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)
if w <= 0 {
w = 1
}
if h <= 0 {
h = 1
}
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
}

98
vendor/github.com/faiface/pixel/pixelgl/glpicture.go generated vendored Normal file
View File

@@ -0,0 +1,98 @@
package pixelgl
import (
"math"
"github.com/faiface/glhf"
"github.com/faiface/mainthread"
"github.com/faiface/pixel"
)
// GLPicture is a pixel.PictureColor with a Texture. All OpenGL Targets should implement and accept
// this interface, because it enables seamless drawing of one to another.
//
// Implementing this interface on an OpenGL Target enables other OpenGL Targets to efficiently draw
// that Target onto them.
type GLPicture interface {
pixel.PictureColor
Texture() *glhf.Texture
}
// NewGLPicture creates a new GLPicture with it's own static OpenGL texture. This function always
// allocates a new texture that cannot (shouldn't) be further modified.
func NewGLPicture(p pixel.Picture) GLPicture {
bounds := p.Bounds()
bx, by, bw, bh := intBounds(bounds)
pixels := make([]uint8, 4*bw*bh)
if pd, ok := p.(*pixel.PictureData); ok {
// PictureData short path
for y := 0; y < bh; y++ {
for x := 0; x < bw; x++ {
rgba := pd.Pix[y*pd.Stride+x]
off := (y*bw + x) * 4
pixels[off+0] = rgba.R
pixels[off+1] = rgba.G
pixels[off+2] = rgba.B
pixels[off+3] = rgba.A
}
}
} else if p, ok := p.(pixel.PictureColor); ok {
for y := 0; y < bh; y++ {
for x := 0; x < bw; x++ {
at := pixel.V(
math.Max(float64(bx+x), bounds.Min.X),
math.Max(float64(by+y), bounds.Min.Y),
)
color := p.Color(at)
off := (y*bw + x) * 4
pixels[off+0] = uint8(color.R * 255)
pixels[off+1] = uint8(color.G * 255)
pixels[off+2] = uint8(color.B * 255)
pixels[off+3] = uint8(color.A * 255)
}
}
}
var tex *glhf.Texture
mainthread.Call(func() {
tex = glhf.NewTexture(bw, bh, false, pixels)
})
gp := &glPicture{
bounds: bounds,
tex: tex,
pixels: pixels,
}
return gp
}
type glPicture struct {
bounds pixel.Rect
tex *glhf.Texture
pixels []uint8
}
func (gp *glPicture) Bounds() pixel.Rect {
return gp.bounds
}
func (gp *glPicture) Texture() *glhf.Texture {
return gp.tex
}
func (gp *glPicture) Color(at pixel.Vec) pixel.RGBA {
if !gp.bounds.Contains(at) {
return pixel.Alpha(0)
}
bx, by, bw, _ := intBounds(gp.bounds)
x, y := int(at.X)-bx, int(at.Y)-by
off := y*bw + x
return pixel.RGBA{
R: float64(gp.pixels[off*4+0]) / 255,
G: float64(gp.pixels[off*4+1]) / 255,
B: float64(gp.pixels[off*4+2]) / 255,
A: float64(gp.pixels[off*4+3]) / 255,
}
}

215
vendor/github.com/faiface/pixel/pixelgl/gltriangles.go generated vendored Normal file
View File

@@ -0,0 +1,215 @@
package pixelgl
import (
"fmt"
"github.com/faiface/glhf"
"github.com/faiface/mainthread"
"github.com/faiface/pixel"
)
// GLTriangles are OpenGL triangles implemented using glhf.VertexSlice.
//
// Triangles returned from this function support TrianglesPosition, TrianglesColor and
// TrianglesPicture. If you need to support more, you can "override" SetLen and Update methods.
type GLTriangles struct {
vs *glhf.VertexSlice
data []float32
shader *glhf.Shader
}
var (
_ pixel.TrianglesPosition = (*GLTriangles)(nil)
_ pixel.TrianglesColor = (*GLTriangles)(nil)
_ pixel.TrianglesPicture = (*GLTriangles)(nil)
)
// NewGLTriangles returns GLTriangles initialized with the data from the supplied Triangles.
//
// Only draw the Triangles using the provided Shader.
func NewGLTriangles(shader *glhf.Shader, t pixel.Triangles) *GLTriangles {
var gt *GLTriangles
mainthread.Call(func() {
gt = &GLTriangles{
vs: glhf.MakeVertexSlice(shader, 0, t.Len()),
shader: shader,
}
})
gt.SetLen(t.Len())
gt.Update(t)
return gt
}
// VertexSlice returns the VertexSlice of this GLTriangles.
//
// You can use it to draw them.
func (gt *GLTriangles) VertexSlice() *glhf.VertexSlice {
return gt.vs
}
// Shader returns the GLTriangles's associated shader.
func (gt *GLTriangles) Shader() *glhf.Shader {
return gt.shader
}
// Len returns the number of vertices.
func (gt *GLTriangles) Len() int {
return len(gt.data) / gt.vs.Stride()
}
// SetLen efficiently resizes GLTriangles to len.
//
// Time complexity is amortized O(1).
func (gt *GLTriangles) SetLen(length int) {
switch {
case length > gt.Len():
needAppend := length - gt.Len()
for i := 0; i < needAppend; i++ {
gt.data = append(gt.data,
0, 0,
1, 1, 1, 1,
0, 0,
0,
)
}
case length < gt.Len():
gt.data = gt.data[:length*gt.vs.Stride()]
default:
return
}
mainthread.CallNonBlock(func() {
gt.vs.Begin()
gt.vs.SetLen(length)
gt.vs.End()
})
}
// Slice returns a sub-Triangles of this GLTriangles in range [i, j).
func (gt *GLTriangles) Slice(i, j int) pixel.Triangles {
return &GLTriangles{
vs: gt.vs.Slice(i, j),
data: gt.data[i*gt.vs.Stride() : j*gt.vs.Stride()],
shader: gt.shader,
}
}
func (gt *GLTriangles) updateData(t pixel.Triangles) {
// glTriangles short path
if t, ok := t.(*GLTriangles); ok {
copy(gt.data, t.data)
return
}
// TrianglesData short path
stride := gt.vs.Stride()
length := gt.Len()
if t, ok := t.(*pixel.TrianglesData); ok {
for i := 0; i < length; i++ {
var (
px, py = (*t)[i].Position.XY()
col = (*t)[i].Color
tx, ty = (*t)[i].Picture.XY()
in = (*t)[i].Intensity
)
d := gt.data[i*stride : i*stride+9]
d[0] = float32(px)
d[1] = float32(py)
d[2] = float32(col.R)
d[3] = float32(col.G)
d[4] = float32(col.B)
d[5] = float32(col.A)
d[6] = float32(tx)
d[7] = float32(ty)
d[8] = float32(in)
}
return
}
if t, ok := t.(pixel.TrianglesPosition); ok {
for i := 0; i < length; i++ {
px, py := t.Position(i).XY()
gt.data[i*stride+0] = float32(px)
gt.data[i*stride+1] = float32(py)
}
}
if t, ok := t.(pixel.TrianglesColor); ok {
for i := 0; i < length; i++ {
col := t.Color(i)
gt.data[i*stride+2] = float32(col.R)
gt.data[i*stride+3] = float32(col.G)
gt.data[i*stride+4] = float32(col.B)
gt.data[i*stride+5] = float32(col.A)
}
}
if t, ok := t.(pixel.TrianglesPicture); ok {
for i := 0; i < length; i++ {
pic, intensity := t.Picture(i)
gt.data[i*stride+6] = float32(pic.X)
gt.data[i*stride+7] = float32(pic.Y)
gt.data[i*stride+8] = float32(intensity)
}
}
}
// Update copies vertex properties from the supplied Triangles into this GLTriangles.
//
// The two Triangles (gt and t) must be of the same len.
func (gt *GLTriangles) Update(t pixel.Triangles) {
if gt.Len() != t.Len() {
panic(fmt.Errorf("(%T).Update: invalid triangles len", gt))
}
gt.updateData(t)
// this code is supposed to copy the vertex data and CallNonBlock the update if
// the data is small enough, otherwise it'll block and not copy the data
if len(gt.data) < 256 { // arbitrary heurestic constant
data := append([]float32{}, gt.data...)
mainthread.CallNonBlock(func() {
gt.vs.Begin()
gt.vs.SetVertexData(data)
gt.vs.End()
})
} else {
mainthread.Call(func() {
gt.vs.Begin()
gt.vs.SetVertexData(gt.data)
gt.vs.End()
})
}
}
// Copy returns an independent copy of this GLTriangles.
//
// The returned Triangles are *GLTriangles as the underlying type.
func (gt *GLTriangles) Copy() pixel.Triangles {
return NewGLTriangles(gt.shader, gt)
}
// Position returns the Position property of the i-th vertex.
func (gt *GLTriangles) Position(i int) pixel.Vec {
px := gt.data[i*gt.vs.Stride()+0]
py := gt.data[i*gt.vs.Stride()+1]
return pixel.V(float64(px), float64(py))
}
// Color returns the Color property of the i-th vertex.
func (gt *GLTriangles) Color(i int) pixel.RGBA {
r := gt.data[i*gt.vs.Stride()+2]
g := gt.data[i*gt.vs.Stride()+3]
b := gt.data[i*gt.vs.Stride()+4]
a := gt.data[i*gt.vs.Stride()+5]
return pixel.RGBA{
R: float64(r),
G: float64(g),
B: float64(b),
A: float64(a),
}
}
// Picture returns the Picture property of the i-th vertex.
func (gt *GLTriangles) Picture(i int) (pic pixel.Vec, intensity float64) {
tx := gt.data[i*gt.vs.Stride()+6]
ty := gt.data[i*gt.vs.Stride()+7]
intensity = float64(gt.data[i*gt.vs.Stride()+8])
return pixel.V(float64(tx), float64(ty)), intensity
}

388
vendor/github.com/faiface/pixel/pixelgl/input.go generated vendored Normal file
View File

@@ -0,0 +1,388 @@
package pixelgl
import (
"github.com/faiface/mainthread"
"github.com/faiface/pixel"
"github.com/go-gl/glfw/v3.2/glfw"
)
// Pressed returns whether the Button is currently pressed down.
func (w *Window) Pressed(button Button) bool {
return w.currInp.buttons[button]
}
// JustPressed returns whether the Button has just been pressed down.
func (w *Window) JustPressed(button Button) bool {
return w.currInp.buttons[button] && !w.prevInp.buttons[button]
}
// JustReleased returns whether the Button has just been released up.
func (w *Window) JustReleased(button Button) bool {
return !w.currInp.buttons[button] && w.prevInp.buttons[button]
}
// Repeated returns whether a repeat event has been triggered on button.
//
// Repeat event occurs repeatedly when a button is held down for some time.
func (w *Window) Repeated(button Button) bool {
return w.currInp.repeat[button]
}
// MousePosition returns the current mouse position in the Window's Bounds.
func (w *Window) MousePosition() pixel.Vec {
return w.currInp.mouse
}
// MouseScroll returns the mouse scroll amount (in both axes) since the last call to Window.Update.
func (w *Window) MouseScroll() pixel.Vec {
return w.currInp.scroll
}
// Typed returns the text typed on the keyboard since the last call to Window.Update.
func (w *Window) Typed() string {
return w.currInp.typed
}
// Button is a keyboard or mouse button. Why distinguish?
type Button int
// List of all mouse buttons.
const (
MouseButton1 = Button(glfw.MouseButton1)
MouseButton2 = Button(glfw.MouseButton2)
MouseButton3 = Button(glfw.MouseButton3)
MouseButton4 = Button(glfw.MouseButton4)
MouseButton5 = Button(glfw.MouseButton5)
MouseButton6 = Button(glfw.MouseButton6)
MouseButton7 = Button(glfw.MouseButton7)
MouseButton8 = Button(glfw.MouseButton8)
MouseButtonLast = Button(glfw.MouseButtonLast)
MouseButtonLeft = Button(glfw.MouseButtonLeft)
MouseButtonRight = Button(glfw.MouseButtonRight)
MouseButtonMiddle = Button(glfw.MouseButtonMiddle)
)
// List of all keyboard buttons.
const (
KeyUnknown = Button(glfw.KeyUnknown)
KeySpace = Button(glfw.KeySpace)
KeyApostrophe = Button(glfw.KeyApostrophe)
KeyComma = Button(glfw.KeyComma)
KeyMinus = Button(glfw.KeyMinus)
KeyPeriod = Button(glfw.KeyPeriod)
KeySlash = Button(glfw.KeySlash)
Key0 = Button(glfw.Key0)
Key1 = Button(glfw.Key1)
Key2 = Button(glfw.Key2)
Key3 = Button(glfw.Key3)
Key4 = Button(glfw.Key4)
Key5 = Button(glfw.Key5)
Key6 = Button(glfw.Key6)
Key7 = Button(glfw.Key7)
Key8 = Button(glfw.Key8)
Key9 = Button(glfw.Key9)
KeySemicolon = Button(glfw.KeySemicolon)
KeyEqual = Button(glfw.KeyEqual)
KeyA = Button(glfw.KeyA)
KeyB = Button(glfw.KeyB)
KeyC = Button(glfw.KeyC)
KeyD = Button(glfw.KeyD)
KeyE = Button(glfw.KeyE)
KeyF = Button(glfw.KeyF)
KeyG = Button(glfw.KeyG)
KeyH = Button(glfw.KeyH)
KeyI = Button(glfw.KeyI)
KeyJ = Button(glfw.KeyJ)
KeyK = Button(glfw.KeyK)
KeyL = Button(glfw.KeyL)
KeyM = Button(glfw.KeyM)
KeyN = Button(glfw.KeyN)
KeyO = Button(glfw.KeyO)
KeyP = Button(glfw.KeyP)
KeyQ = Button(glfw.KeyQ)
KeyR = Button(glfw.KeyR)
KeyS = Button(glfw.KeyS)
KeyT = Button(glfw.KeyT)
KeyU = Button(glfw.KeyU)
KeyV = Button(glfw.KeyV)
KeyW = Button(glfw.KeyW)
KeyX = Button(glfw.KeyX)
KeyY = Button(glfw.KeyY)
KeyZ = Button(glfw.KeyZ)
KeyLeftBracket = Button(glfw.KeyLeftBracket)
KeyBackslash = Button(glfw.KeyBackslash)
KeyRightBracket = Button(glfw.KeyRightBracket)
KeyGraveAccent = Button(glfw.KeyGraveAccent)
KeyWorld1 = Button(glfw.KeyWorld1)
KeyWorld2 = Button(glfw.KeyWorld2)
KeyEscape = Button(glfw.KeyEscape)
KeyEnter = Button(glfw.KeyEnter)
KeyTab = Button(glfw.KeyTab)
KeyBackspace = Button(glfw.KeyBackspace)
KeyInsert = Button(glfw.KeyInsert)
KeyDelete = Button(glfw.KeyDelete)
KeyRight = Button(glfw.KeyRight)
KeyLeft = Button(glfw.KeyLeft)
KeyDown = Button(glfw.KeyDown)
KeyUp = Button(glfw.KeyUp)
KeyPageUp = Button(glfw.KeyPageUp)
KeyPageDown = Button(glfw.KeyPageDown)
KeyHome = Button(glfw.KeyHome)
KeyEnd = Button(glfw.KeyEnd)
KeyCapsLock = Button(glfw.KeyCapsLock)
KeyScrollLock = Button(glfw.KeyScrollLock)
KeyNumLock = Button(glfw.KeyNumLock)
KeyPrintScreen = Button(glfw.KeyPrintScreen)
KeyPause = Button(glfw.KeyPause)
KeyF1 = Button(glfw.KeyF1)
KeyF2 = Button(glfw.KeyF2)
KeyF3 = Button(glfw.KeyF3)
KeyF4 = Button(glfw.KeyF4)
KeyF5 = Button(glfw.KeyF5)
KeyF6 = Button(glfw.KeyF6)
KeyF7 = Button(glfw.KeyF7)
KeyF8 = Button(glfw.KeyF8)
KeyF9 = Button(glfw.KeyF9)
KeyF10 = Button(glfw.KeyF10)
KeyF11 = Button(glfw.KeyF11)
KeyF12 = Button(glfw.KeyF12)
KeyF13 = Button(glfw.KeyF13)
KeyF14 = Button(glfw.KeyF14)
KeyF15 = Button(glfw.KeyF15)
KeyF16 = Button(glfw.KeyF16)
KeyF17 = Button(glfw.KeyF17)
KeyF18 = Button(glfw.KeyF18)
KeyF19 = Button(glfw.KeyF19)
KeyF20 = Button(glfw.KeyF20)
KeyF21 = Button(glfw.KeyF21)
KeyF22 = Button(glfw.KeyF22)
KeyF23 = Button(glfw.KeyF23)
KeyF24 = Button(glfw.KeyF24)
KeyF25 = Button(glfw.KeyF25)
KeyKP0 = Button(glfw.KeyKP0)
KeyKP1 = Button(glfw.KeyKP1)
KeyKP2 = Button(glfw.KeyKP2)
KeyKP3 = Button(glfw.KeyKP3)
KeyKP4 = Button(glfw.KeyKP4)
KeyKP5 = Button(glfw.KeyKP5)
KeyKP6 = Button(glfw.KeyKP6)
KeyKP7 = Button(glfw.KeyKP7)
KeyKP8 = Button(glfw.KeyKP8)
KeyKP9 = Button(glfw.KeyKP9)
KeyKPDecimal = Button(glfw.KeyKPDecimal)
KeyKPDivide = Button(glfw.KeyKPDivide)
KeyKPMultiply = Button(glfw.KeyKPMultiply)
KeyKPSubtract = Button(glfw.KeyKPSubtract)
KeyKPAdd = Button(glfw.KeyKPAdd)
KeyKPEnter = Button(glfw.KeyKPEnter)
KeyKPEqual = Button(glfw.KeyKPEqual)
KeyLeftShift = Button(glfw.KeyLeftShift)
KeyLeftControl = Button(glfw.KeyLeftControl)
KeyLeftAlt = Button(glfw.KeyLeftAlt)
KeyLeftSuper = Button(glfw.KeyLeftSuper)
KeyRightShift = Button(glfw.KeyRightShift)
KeyRightControl = Button(glfw.KeyRightControl)
KeyRightAlt = Button(glfw.KeyRightAlt)
KeyRightSuper = Button(glfw.KeyRightSuper)
KeyMenu = Button(glfw.KeyMenu)
KeyLast = Button(glfw.KeyLast)
)
// String returns a human-readable string describing the Button.
func (b Button) String() string {
name, ok := buttonNames[b]
if !ok {
return "Invalid"
}
return name
}
var buttonNames = map[Button]string{
MouseButton4: "MouseButton4",
MouseButton5: "MouseButton5",
MouseButton6: "MouseButton6",
MouseButton7: "MouseButton7",
MouseButton8: "MouseButton8",
MouseButtonLeft: "MouseButtonLeft",
MouseButtonRight: "MouseButtonRight",
MouseButtonMiddle: "MouseButtonMiddle",
KeyUnknown: "Unknown",
KeySpace: "Space",
KeyApostrophe: "Apostrophe",
KeyComma: "Comma",
KeyMinus: "Minus",
KeyPeriod: "Period",
KeySlash: "Slash",
Key0: "0",
Key1: "1",
Key2: "2",
Key3: "3",
Key4: "4",
Key5: "5",
Key6: "6",
Key7: "7",
Key8: "8",
Key9: "9",
KeySemicolon: "Semicolon",
KeyEqual: "Equal",
KeyA: "A",
KeyB: "B",
KeyC: "C",
KeyD: "D",
KeyE: "E",
KeyF: "F",
KeyG: "G",
KeyH: "H",
KeyI: "I",
KeyJ: "J",
KeyK: "K",
KeyL: "L",
KeyM: "M",
KeyN: "N",
KeyO: "O",
KeyP: "P",
KeyQ: "Q",
KeyR: "R",
KeyS: "S",
KeyT: "T",
KeyU: "U",
KeyV: "V",
KeyW: "W",
KeyX: "X",
KeyY: "Y",
KeyZ: "Z",
KeyLeftBracket: "LeftBracket",
KeyBackslash: "Backslash",
KeyRightBracket: "RightBracket",
KeyGraveAccent: "GraveAccent",
KeyWorld1: "World1",
KeyWorld2: "World2",
KeyEscape: "Escape",
KeyEnter: "Enter",
KeyTab: "Tab",
KeyBackspace: "Backspace",
KeyInsert: "Insert",
KeyDelete: "Delete",
KeyRight: "Right",
KeyLeft: "Left",
KeyDown: "Down",
KeyUp: "Up",
KeyPageUp: "PageUp",
KeyPageDown: "PageDown",
KeyHome: "Home",
KeyEnd: "End",
KeyCapsLock: "CapsLock",
KeyScrollLock: "ScrollLock",
KeyNumLock: "NumLock",
KeyPrintScreen: "PrintScreen",
KeyPause: "Pause",
KeyF1: "F1",
KeyF2: "F2",
KeyF3: "F3",
KeyF4: "F4",
KeyF5: "F5",
KeyF6: "F6",
KeyF7: "F7",
KeyF8: "F8",
KeyF9: "F9",
KeyF10: "F10",
KeyF11: "F11",
KeyF12: "F12",
KeyF13: "F13",
KeyF14: "F14",
KeyF15: "F15",
KeyF16: "F16",
KeyF17: "F17",
KeyF18: "F18",
KeyF19: "F19",
KeyF20: "F20",
KeyF21: "F21",
KeyF22: "F22",
KeyF23: "F23",
KeyF24: "F24",
KeyF25: "F25",
KeyKP0: "KP0",
KeyKP1: "KP1",
KeyKP2: "KP2",
KeyKP3: "KP3",
KeyKP4: "KP4",
KeyKP5: "KP5",
KeyKP6: "KP6",
KeyKP7: "KP7",
KeyKP8: "KP8",
KeyKP9: "KP9",
KeyKPDecimal: "KPDecimal",
KeyKPDivide: "KPDivide",
KeyKPMultiply: "KPMultiply",
KeyKPSubtract: "KPSubtract",
KeyKPAdd: "KPAdd",
KeyKPEnter: "KPEnter",
KeyKPEqual: "KPEqual",
KeyLeftShift: "LeftShift",
KeyLeftControl: "LeftControl",
KeyLeftAlt: "LeftAlt",
KeyLeftSuper: "LeftSuper",
KeyRightShift: "RightShift",
KeyRightControl: "RightControl",
KeyRightAlt: "RightAlt",
KeyRightSuper: "RightSuper",
KeyMenu: "Menu",
}
func (w *Window) initInput() {
mainthread.Call(func() {
w.window.SetMouseButtonCallback(func(_ *glfw.Window, button glfw.MouseButton, action glfw.Action, mod glfw.ModifierKey) {
switch action {
case glfw.Press:
w.tempInp.buttons[Button(button)] = true
case glfw.Release:
w.tempInp.buttons[Button(button)] = false
}
})
w.window.SetKeyCallback(func(_ *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
if key == glfw.KeyUnknown {
return
}
switch action {
case glfw.Press:
w.tempInp.buttons[Button(key)] = true
case glfw.Release:
w.tempInp.buttons[Button(key)] = false
case glfw.Repeat:
w.tempInp.repeat[Button(key)] = true
}
})
w.window.SetCursorPosCallback(func(_ *glfw.Window, x, y float64) {
w.tempInp.mouse = pixel.V(
x+w.bounds.Min.X,
(w.bounds.H()-y)+w.bounds.Min.Y,
)
})
w.window.SetScrollCallback(func(_ *glfw.Window, xoff, yoff float64) {
w.tempInp.scroll.X += xoff
w.tempInp.scroll.Y += yoff
})
w.window.SetCharCallback(func(_ *glfw.Window, r rune) {
w.tempInp.typed += string(r)
})
})
}
// UpdateInput polls window events. Call this function to poll window events
// without swapping buffers. Note that the Update method invokes UpdateInput.
func (w *Window) UpdateInput() {
mainthread.Call(func() {
glfw.PollEvents()
})
w.prevInp = w.currInp
w.currInp = w.tempInp
w.tempInp.repeat = [KeyLast + 1]bool{}
w.tempInp.scroll = pixel.ZV
w.tempInp.typed = ""
}

97
vendor/github.com/faiface/pixel/pixelgl/monitor.go generated vendored Normal file
View File

@@ -0,0 +1,97 @@
package pixelgl
import (
"github.com/faiface/mainthread"
"github.com/go-gl/glfw/v3.2/glfw"
)
// Monitor represents a physical display attached to your computer.
type Monitor struct {
monitor *glfw.Monitor
}
// PrimaryMonitor returns the main monitor (usually the one with the taskbar and stuff).
func PrimaryMonitor() *Monitor {
var monitor *glfw.Monitor
mainthread.Call(func() {
monitor = glfw.GetPrimaryMonitor()
})
return &Monitor{
monitor: monitor,
}
}
// Monitors returns a slice of all currently available monitors.
func Monitors() []*Monitor {
var monitors []*Monitor
mainthread.Call(func() {
for _, monitor := range glfw.GetMonitors() {
monitors = append(monitors, &Monitor{monitor: monitor})
}
})
return monitors
}
// Name returns a human-readable name of the Monitor.
func (m *Monitor) Name() string {
var name string
mainthread.Call(func() {
name = m.monitor.GetName()
})
return name
}
// PhysicalSize returns the size of the display area of the Monitor in millimeters.
func (m *Monitor) PhysicalSize() (width, height float64) {
var wi, hi int
mainthread.Call(func() {
wi, hi = m.monitor.GetPhysicalSize()
})
width = float64(wi)
height = float64(hi)
return
}
// Position returns the position of the upper-left corner of the Monitor in screen coordinates.
func (m *Monitor) Position() (x, y float64) {
var xi, yi int
mainthread.Call(func() {
xi, yi = m.monitor.GetPos()
})
x = float64(xi)
y = float64(yi)
return
}
// Size returns the resolution of the Monitor in pixels.
func (m *Monitor) Size() (width, height float64) {
var mode *glfw.VidMode
mainthread.Call(func() {
mode = m.monitor.GetVideoMode()
})
width = float64(mode.Width)
height = float64(mode.Height)
return
}
// BitDepth returns the number of bits per color of the Monitor.
func (m *Monitor) BitDepth() (red, green, blue int) {
var mode *glfw.VidMode
mainthread.Call(func() {
mode = m.monitor.GetVideoMode()
})
red = mode.RedBits
green = mode.GreenBits
blue = mode.BlueBits
return
}
// RefreshRate returns the refresh frequency of the Monitor in Hz (refreshes/second).
func (m *Monitor) RefreshRate() (rate float64) {
var mode *glfw.VidMode
mainthread.Call(func() {
mode = m.monitor.GetVideoMode()
})
rate = float64(mode.RefreshRate)
return
}

33
vendor/github.com/faiface/pixel/pixelgl/run.go generated vendored Normal file
View File

@@ -0,0 +1,33 @@
package pixelgl
import (
"github.com/faiface/mainthread"
"github.com/go-gl/glfw/v3.2/glfw"
"github.com/pkg/errors"
)
// Run is essentially the main function of PixelGL. It exists mainly due to the technical
// limitations of OpenGL and operating systems. In short, all graphics and window manipulating calls
// must be done from the main thread. Run makes this possible.
//
// Call this function from the main function of your application. This is necessary, so that Run
// runs on the main thread.
//
// func run() {
// // interact with Pixel and PixelGL from here (even concurrently)
// }
//
// func main() {
// pixel.Run(run)
// }
//
// You can spawn any number of goroutines from your run function and interact with PixelGL
// concurrently. The only condition is that the Run function is called from your main function.
func Run(run func()) {
err := glfw.Init()
if err != nil {
panic(errors.Wrap(err, "failed to initialize GLFW"))
}
defer glfw.Terminate()
mainthread.Run(run)
}

15
vendor/github.com/faiface/pixel/pixelgl/util.go generated vendored Normal file
View File

@@ -0,0 +1,15 @@
package pixelgl
import (
"math"
"github.com/faiface/pixel"
)
func intBounds(bounds pixel.Rect) (x, y, w, h int) {
x0 := int(math.Floor(bounds.Min.X))
y0 := int(math.Floor(bounds.Min.Y))
x1 := int(math.Ceil(bounds.Max.X))
y1 := int(math.Ceil(bounds.Max.Y))
return x0, y0, x1 - x0, y1 - y0
}

426
vendor/github.com/faiface/pixel/pixelgl/window.go generated vendored Normal file
View File

@@ -0,0 +1,426 @@
package pixelgl
import (
"image"
"image/color"
"runtime"
"github.com/faiface/glhf"
"github.com/faiface/mainthread"
"github.com/faiface/pixel"
"github.com/go-gl/glfw/v3.2/glfw"
"github.com/pkg/errors"
)
// WindowConfig is a structure for specifying all possible properties of a Window. Properties are
// chosen in such a way, that you usually only need to set a few of them - defaults (zeros) should
// usually be sensible.
//
// Note that you always need to set the Bounds of a Window.
type WindowConfig struct {
// Title at the top of the Window.
Title string
// Icon specifies the icon images available to be used by the window. This is usually
// displayed in the top bar of the window or in the task bar of the desktop environment.
//
// If passed one image, it will use that image, if passed an array of images those of or
// closest to the sizes desired by the system are selected. The desired image sizes varies
// depending on platform and system settings. The selected images will be rescaled as
// needed. Good sizes include 16x16, 32x32 and 48x48.
//
// Note: Setting this value doesn't have an effect on OSX. You'll need to set the icon when
// bundling your application for release.
Icon []pixel.Picture
// Bounds specify the bounds of the Window in pixels.
Bounds pixel.Rect
// If set to nil, the Window will be windowed. Otherwise it will be fullscreen on the
// specified Monitor.
Monitor *Monitor
// Whether the Window is resizable.
Resizable bool
// Undecorated Window ommits the borders and decorations (close button, etc.).
Undecorated bool
// VSync (vertical synchronization) synchronizes Window's framerate with the framerate of
// the monitor.
VSync bool
}
// Window is a window handler. Use this type to manipulate a window (input, drawing, etc.).
type Window struct {
window *glfw.Window
bounds pixel.Rect
canvas *Canvas
vsync bool
cursorVisible bool
// need to save these to correctly restore a fullscreen window
restore struct {
xpos, ypos, width, height int
}
prevInp, currInp, tempInp struct {
mouse pixel.Vec
buttons [KeyLast + 1]bool
repeat [KeyLast + 1]bool
scroll pixel.Vec
typed string
}
}
var currWin *Window
// NewWindow creates a new Window with it's properties specified in the provided config.
//
// If Window creation fails, an error is returned (e.g. due to unavailable graphics device).
func NewWindow(cfg WindowConfig) (*Window, error) {
bool2int := map[bool]int{
true: glfw.True,
false: glfw.False,
}
w := &Window{bounds: cfg.Bounds, cursorVisible: true}
err := mainthread.CallErr(func() error {
var err error
glfw.WindowHint(glfw.ContextVersionMajor, 3)
glfw.WindowHint(glfw.ContextVersionMinor, 3)
glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
glfw.WindowHint(glfw.Resizable, bool2int[cfg.Resizable])
glfw.WindowHint(glfw.Decorated, bool2int[!cfg.Undecorated])
var share *glfw.Window
if currWin != nil {
share = currWin.window
}
_, _, width, height := intBounds(cfg.Bounds)
w.window, err = glfw.CreateWindow(
width,
height,
cfg.Title,
nil,
share,
)
if err != nil {
return err
}
// enter the OpenGL context
w.begin()
w.end()
return nil
})
if err != nil {
return nil, errors.Wrap(err, "creating window failed")
}
if len(cfg.Icon) > 0 {
imgs := make([]image.Image, len(cfg.Icon))
for i, icon := range cfg.Icon {
pic := pixel.PictureDataFromPicture(icon)
imgs[i] = pic.Image()
}
mainthread.Call(func() {
w.window.SetIcon(imgs)
})
}
w.SetVSync(cfg.VSync)
w.initInput()
w.SetMonitor(cfg.Monitor)
w.canvas = NewCanvas(cfg.Bounds)
w.Update()
runtime.SetFinalizer(w, (*Window).Destroy)
return w, nil
}
// Destroy destroys the Window. The Window can't be used any further.
func (w *Window) Destroy() {
mainthread.Call(func() {
w.window.Destroy()
})
}
// Update swaps buffers and polls events. Call this method at the end of each frame.
func (w *Window) Update() {
mainthread.Call(func() {
_, _, oldW, oldH := intBounds(w.bounds)
newW, newH := w.window.GetSize()
w.bounds = w.bounds.ResizedMin(w.bounds.Size().Add(pixel.V(
float64(newW-oldW),
float64(newH-oldH),
)))
})
w.canvas.SetBounds(w.bounds)
mainthread.Call(func() {
w.begin()
framebufferWidth, framebufferHeight := w.window.GetFramebufferSize()
glhf.Bounds(0, 0, framebufferWidth, framebufferHeight)
glhf.Clear(0, 0, 0, 0)
w.canvas.gf.Frame().Begin()
w.canvas.gf.Frame().Blit(
nil,
0, 0, w.canvas.Texture().Width(), w.canvas.Texture().Height(),
0, 0, framebufferWidth, framebufferHeight,
)
w.canvas.gf.Frame().End()
if w.vsync {
glfw.SwapInterval(1)
} else {
glfw.SwapInterval(0)
}
w.window.SwapBuffers()
w.end()
})
w.UpdateInput()
}
// SetClosed sets the closed flag of the Window.
//
// This is useful when overriding the user's attempt to close the Window, or just to close the
// Window from within the program.
func (w *Window) SetClosed(closed bool) {
mainthread.Call(func() {
w.window.SetShouldClose(closed)
})
}
// Closed returns the closed flag of the Window, which reports whether the Window should be closed.
//
// The closed flag is automatically set when a user attempts to close the Window.
func (w *Window) Closed() bool {
var closed bool
mainthread.Call(func() {
closed = w.window.ShouldClose()
})
return closed
}
// SetTitle changes the title of the Window.
func (w *Window) SetTitle(title string) {
mainthread.Call(func() {
w.window.SetTitle(title)
})
}
// SetBounds sets the bounds of the Window in pixels. Bounds can be fractional, but the actual size
// of the window will be rounded to integers.
func (w *Window) SetBounds(bounds pixel.Rect) {
w.bounds = bounds
mainthread.Call(func() {
_, _, width, height := intBounds(bounds)
w.window.SetSize(width, height)
})
}
// SetPos sets the position, in screen coordinates, of the upper-left corner
// of the client area of the window. Position can be fractional, but the actual position
// of the window will be rounded to integers.
//
// If it is a full screen window, this function does nothing.
func (w *Window) SetPos(pos pixel.Vec) {
mainthread.Call(func() {
left, top := int(pos.X), int(pos.Y)
w.window.SetPos(left, top)
})
}
// GetPos gets the position, in screen coordinates, of the upper-left corner
// of the client area of the window. The position is rounded to integers.
func (w *Window) GetPos() pixel.Vec {
var v pixel.Vec
mainthread.Call(func() {
x, y := w.window.GetPos()
v = pixel.V(float64(x), float64(y))
})
return v
}
// Bounds returns the current bounds of the Window.
func (w *Window) Bounds() pixel.Rect {
return w.bounds
}
func (w *Window) setFullscreen(monitor *Monitor) {
mainthread.Call(func() {
w.restore.xpos, w.restore.ypos = w.window.GetPos()
w.restore.width, w.restore.height = w.window.GetSize()
mode := monitor.monitor.GetVideoMode()
w.window.SetMonitor(
monitor.monitor,
0,
0,
mode.Width,
mode.Height,
mode.RefreshRate,
)
})
}
func (w *Window) setWindowed() {
mainthread.Call(func() {
w.window.SetMonitor(
nil,
w.restore.xpos,
w.restore.ypos,
w.restore.width,
w.restore.height,
0,
)
})
}
// SetMonitor sets the Window fullscreen on the given Monitor. If the Monitor is nil, the Window
// will be restored to windowed state instead.
//
// The Window will be automatically set to the Monitor's resolution. If you want a different
// resolution, you will need to set it manually with SetBounds method.
func (w *Window) SetMonitor(monitor *Monitor) {
if w.Monitor() != monitor {
if monitor != nil {
w.setFullscreen(monitor)
} else {
w.setWindowed()
}
}
}
// Monitor returns a monitor the Window is fullscreen on. If the Window is not fullscreen, this
// function returns nil.
func (w *Window) Monitor() *Monitor {
var monitor *glfw.Monitor
mainthread.Call(func() {
monitor = w.window.GetMonitor()
})
if monitor == nil {
return nil
}
return &Monitor{
monitor: monitor,
}
}
// Focused returns true if the Window has input focus.
func (w *Window) Focused() bool {
var focused bool
mainthread.Call(func() {
focused = w.window.GetAttrib(glfw.Focused) == glfw.True
})
return focused
}
// SetVSync sets whether the Window's Update should synchronize with the monitor refresh rate.
func (w *Window) SetVSync(vsync bool) {
w.vsync = vsync
}
// VSync returns whether the Window is set to synchronize with the monitor refresh rate.
func (w *Window) VSync() bool {
return w.vsync
}
// SetCursorVisible sets the visibility of the mouse cursor inside the Window client area.
func (w *Window) SetCursorVisible(visible bool) {
w.cursorVisible = visible
mainthread.Call(func() {
if visible {
w.window.SetInputMode(glfw.CursorMode, glfw.CursorNormal)
} else {
w.window.SetInputMode(glfw.CursorMode, glfw.CursorHidden)
}
})
}
// CursorVisible returns the visibility status of the mouse cursor.
func (w *Window) CursorVisible() bool {
return w.cursorVisible
}
// Note: must be called inside the main thread.
func (w *Window) begin() {
if currWin != w {
w.window.MakeContextCurrent()
glhf.Init()
currWin = w
}
}
// Note: must be called inside the main thread.
func (w *Window) end() {
// nothing, really
}
// MakeTriangles generates a specialized copy of the supplied Triangles that will draw onto this
// Window.
//
// Window supports TrianglesPosition, TrianglesColor and TrianglesPicture.
func (w *Window) MakeTriangles(t pixel.Triangles) pixel.TargetTriangles {
return w.canvas.MakeTriangles(t)
}
// MakePicture generates a specialized copy of the supplied Picture that will draw onto this Window.
//
// Window supports PictureColor.
func (w *Window) MakePicture(p pixel.Picture) pixel.TargetPicture {
return w.canvas.MakePicture(p)
}
// SetMatrix sets a Matrix that every point will be projected by.
func (w *Window) SetMatrix(m pixel.Matrix) {
w.canvas.SetMatrix(m)
}
// SetColorMask sets a global color mask for the Window.
func (w *Window) SetColorMask(c color.Color) {
w.canvas.SetColorMask(c)
}
// SetComposeMethod sets a Porter-Duff composition method to be used in the following draws onto
// this Window.
func (w *Window) SetComposeMethod(cmp pixel.ComposeMethod) {
w.canvas.SetComposeMethod(cmp)
}
// SetSmooth sets whether the stretched Pictures drawn onto this Window should be drawn smooth or
// pixely.
func (w *Window) SetSmooth(smooth bool) {
w.canvas.SetSmooth(smooth)
}
// Smooth returns whether the stretched Pictures drawn onto this Window are set to be drawn smooth
// or pixely.
func (w *Window) Smooth() bool {
return w.canvas.Smooth()
}
// Clear clears the Window with a single color.
func (w *Window) Clear(c color.Color) {
w.canvas.Clear(c)
}
// Color returns the color of the pixel over the given position inside the Window.
func (w *Window) Color(at pixel.Vec) pixel.RGBA {
return w.canvas.Color(at)
}