backup before reinstall

This commit is contained in:
faiface 2017-01-01 22:12:12 +01:00
parent 69032cdcf3
commit cafda2cfae
4 changed files with 180 additions and 219 deletions

View File

@ -9,72 +9,6 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
// Drawer is anything that can be drawn. It's by no means a drawer inside your table.
//
// Drawer consists of a single methods: Draw. Draw methods takes any number of Transform
// arguments. It applies these transforms in the reverse order and finally draws something
// transformed by these transforms.
//
// Example:
//
// // object is a drawer
// object.Draw(pixel.Position(pixel.V(100, 100).Rotate(math.Pi / 2)))
// camera := pixel.Camera(pixel.V(0, 0), pixel.V(500, 500), pixel.V(window.Size()))
// object.Draw(camera, pixel.Position(0).Scale(0.5))
type Drawer interface {
Draw(t ...Transform)
}
// Group is used to effeciently handle a collection of objects with a common parent. Usually many
// objects share a parent, using a group can significantly increase performance in these cases.
//
// To use a group, first, create a group and as it's parent use the common parent of the
// collection of objects:
//
// group := pixel.NewGroup(commonParent)
//
// Then, when creating the objects, use the group as their parent, instead of the original
// common parent, but, don't forget to put everything into a With block, like this:
//
// group.With(func() {
// object := newArbitratyObject(group, ...) // group is the parent of the object
// })
//
// When dealing with objects associated with a group, it's always necessary to wrap that into
// a With block:
//
// group.With(func() {
// for _, obj := range objectsWithCommonParent {
// // do something with obj
// }
// })
//
// That's all!
type Group struct {
parent pixelgl.Doer
context pixelgl.Context
}
// NewGroup creates a new group with the specified parent.
func NewGroup(parent pixelgl.Doer) *Group {
return &Group{
parent: parent,
}
}
// With enables the parent of a group and executes sub.
func (g *Group) With(sub func()) {
g.parent.Do(func(ctx pixelgl.Context) {
g.context = ctx
sub()
})
}
// Do just passes a cached context to sub.
func (g *Group) Do(sub func(pixelgl.Context)) {
sub(g.context)
}
// Shape is a general drawable shape constructed from vertices. // Shape is a general drawable shape constructed from vertices.
// //
// Vertices are specified in the vertex array of a shape. A shape can have a picture, a color // Vertices are specified in the vertex array of a shape. A shape can have a picture, a color
@ -83,21 +17,21 @@ func (g *Group) Do(sub func(pixelgl.Context)) {
// Usually you use this type only indirectly throught other specific shapes (sprites, polygons, // Usually you use this type only indirectly throught other specific shapes (sprites, polygons,
// ...) embedding it. // ...) embedding it.
type Shape struct { type Shape struct {
parent pixelgl.Doer
picture *Picture picture *Picture
color color.Color color color.Color
transform Transform transform Transform
va *pixelgl.VertexArray vertices []map[pixelgl.Attr]interface{}
vas map[Target]*pixelgl.VertexArray
} }
// NewShape creates a new shape with specified parent, picture, color, transform and vertex array. // NewShape creates a new shape with specified parent, picture, color, transform and vertex array.
func NewShape(parent pixelgl.Doer, picture *Picture, c color.Color, transform Transform, va *pixelgl.VertexArray) *Shape { func NewShape(picture *Picture, c color.Color, transform Transform, vertices []map[pixelgl.Attr]interface{}) *Shape {
return &Shape{ return &Shape{
parent: parent,
picture: picture, picture: picture,
color: c, color: c,
transform: transform, transform: transform,
va: va, vertices: vertices,
vas: make(map[Target]*pixelgl.VertexArray),
} }
} }
@ -131,30 +65,45 @@ func (s *Shape) Transform() Transform {
return s.transform return s.transform
} }
// VertexArray changes the underlying vertex array of a shape. // Vertices returns the vertex attribute values of all vertices in a shape.
func (s *Shape) VertexArray() *pixelgl.VertexArray { //
return s.va // Do not change!
func (s *Shape) Vertices() []map[pixelgl.Attr]interface{} {
return s.vertices
} }
// Draw draws a sprite transformed by the supplied transforms applied in the reverse order. // Draw draws a sprite transformed by the supplied transforms applied in the reverse order.
func (s *Shape) Draw(t ...Transform) { func (s *Shape) Draw(target Target, t ...Transform) {
mat := mgl32.Ident3() mat := mgl32.Ident3()
for i := range t { for i := range t {
mat = mat.Mul3(t[i].Mat()) mat = mat.Mul3(t[i].Mat())
} }
mat = mat.Mul3(s.transform.Mat()) mat = mat.Mul3(s.transform.Mat())
s.parent.Do(func(ctx pixelgl.Context) { c := NRGBAModel.Convert(s.color).(NRGBA)
c := NRGBAModel.Convert(s.color).(NRGBA)
ctx.Shader().SetUniformAttr(maskColorVec4, mgl32.Vec4{float32(c.R), float32(c.G), float32(c.B), float32(c.A)}) if s.vas[target] == nil {
ctx.Shader().SetUniformAttr(transformMat3, mat) s.vas[target] = target.MakeVertexArray(s.vertices)
}
va := s.vas[target]
pixelgl.Do(func() {
target.Begin()
defer target.End()
target.Shader().SetUniformAttr(maskColorVec4, mgl32.Vec4{float32(c.R), float32(c.G), float32(c.B), float32(c.A)})
target.Shader().SetUniformAttr(transformMat3, mat)
if s.picture != nil { if s.picture != nil {
s.picture.Texture().Do(func(pixelgl.Context) { s.picture.Texture().Begin()
s.va.Draw() va.Begin()
}) va.Draw()
va.End()
s.picture.Texture().End()
} else { } else {
s.va.Draw() va.Begin()
va.Draw()
va.End()
} }
}) })
} }
@ -173,7 +122,7 @@ type MultiShape struct {
// NewMultiShape creates a new multishape from several other shapes. // NewMultiShape creates a new multishape from several other shapes.
// //
// If two of the supplied shapes have different pictures, this function panics. // If two of the supplied shapes have different pictures, this function panics.
func NewMultiShape(parent pixelgl.Doer, shapes ...*Shape) *MultiShape { func NewMultiShape(shapes ...*Shape) *MultiShape {
var picture *Picture var picture *Picture
for _, shape := range shapes { for _, shape := range shapes {
if picture != nil && shape.Picture() != nil && shape.Picture().Texture().ID() != picture.Texture().ID() { if picture != nil && shape.Picture() != nil && shape.Picture().Texture().ID() != picture.Texture().ID() {
@ -184,20 +133,9 @@ func NewMultiShape(parent pixelgl.Doer, shapes ...*Shape) *MultiShape {
} }
} }
var va *pixelgl.VertexArray
var indices []int
offset := 0
for _, shape := range shapes {
for _, i := range shape.va.Indices() {
indices = append(indices, offset+i)
}
offset += shape.VertexArray().NumVertices()
}
var vertices []map[pixelgl.Attr]interface{} var vertices []map[pixelgl.Attr]interface{}
for _, shape := range shapes { for _, shape := range shapes {
shapeVertices := shape.VertexArray().Vertices() shapeVertices := shape.Vertices()
for vertex := range shapeVertices { for vertex := range shapeVertices {
if pos, ok := shapeVertices[vertex][positionVec2]; ok { if pos, ok := shapeVertices[vertex][positionVec2]; ok {
@ -221,22 +159,7 @@ func NewMultiShape(parent pixelgl.Doer, shapes ...*Shape) *MultiShape {
vertices = append(vertices, shapeVertices...) vertices = append(vertices, shapeVertices...)
} }
parent.Do(func(ctx pixelgl.Context) { return &MultiShape{NewShape(picture, color.White, Position(0), vertices)}
var err error
va, err = pixelgl.NewVertexArray(
pixelgl.ContextHolder{Context: ctx},
ctx.Shader().VertexFormat(),
len(vertices),
indices,
)
if err != nil {
panic(errors.Wrap(err, "failed to create multishape"))
}
})
va.SetVertices(vertices)
return &MultiShape{NewShape(parent, picture, color.White, Position(0), va)}
} }
// Sprite is a picture that can be drawn on the screen. Optionally it can be color masked // Sprite is a picture that can be drawn on the screen. Optionally it can be color masked
@ -252,25 +175,10 @@ type Sprite struct {
// NewSprite creates a new sprite with the supplied picture. The sprite's size is the size of // NewSprite creates a new sprite with the supplied picture. The sprite's size is the size of
// the supplied picture. If you want to change the sprite's size, change it's transform. // the supplied picture. If you want to change the sprite's size, change it's transform.
func NewSprite(parent pixelgl.Doer, picture *Picture) *Sprite { func NewSprite(picture *Picture) *Sprite {
var va *pixelgl.VertexArray w, h := picture.Bounds().Size.XY()
parent.Do(func(ctx pixelgl.Context) {
var err error
va, err = pixelgl.NewVertexArray(
pixelgl.ContextHolder{Context: ctx},
ctx.Shader().VertexFormat(),
4,
[]int{0, 1, 2, 0, 2, 3},
)
if err != nil {
panic(errors.Wrap(err, "failed to create sprite"))
}
})
vertices := make([]map[pixelgl.Attr]interface{}, 4) vertices := make([]map[pixelgl.Attr]interface{}, 4)
w, h := picture.Bounds().Size.XY()
for i, p := range []Vec{V(0, 0), V(w, 0), V(w, h), V(0, h)} { for i, p := range []Vec{V(0, 0), V(w, 0), V(w, h), V(0, h)} {
texCoord := V( texCoord := V(
(picture.Bounds().X()+p.X())/float64(picture.Texture().Width()), (picture.Bounds().X()+p.X())/float64(picture.Texture().Width()),
@ -284,9 +192,16 @@ func NewSprite(parent pixelgl.Doer, picture *Picture) *Sprite {
} }
} }
va.SetVertices(vertices) vertices = []map[pixelgl.Attr]interface{}{
vertices[0],
vertices[1],
vertices[2],
vertices[0],
vertices[2],
vertices[3],
}
return &Sprite{NewShape(parent, picture, color.White, Position(0), va)} return &Sprite{NewShape(picture, color.White, Position(0), vertices)}
} }
// LineColor a line shape (with sharp ends) filled with a single color. // LineColor a line shape (with sharp ends) filled with a single color.
@ -296,26 +211,9 @@ type LineColor struct {
width float64 width float64
} }
// NewLineColor creates a new line shape between points A and B filled with a single color. Parent // NewLineColor creates a new line shape between points A and B filled with a single color.
// is an object that this shape belongs to, such as a window, or a graphics effect. func NewLineColor(c color.Color, a, b Vec, width float64) *LineColor {
func NewLineColor(parent pixelgl.Doer, c color.Color, a, b Vec, width float64) *LineColor {
var va *pixelgl.VertexArray
parent.Do(func(ctx pixelgl.Context) {
var err error
va, err = pixelgl.NewVertexArray(
pixelgl.ContextHolder{Context: ctx},
ctx.Shader().VertexFormat(),
4,
[]int{0, 1, 2, 1, 2, 3},
)
if err != nil {
panic(errors.Wrap(err, "failed to create line"))
}
})
vertices := make([]map[pixelgl.Attr]interface{}, 4) vertices := make([]map[pixelgl.Attr]interface{}, 4)
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
vertices[i] = map[pixelgl.Attr]interface{}{ vertices[i] = map[pixelgl.Attr]interface{}{
colorVec4: mgl32.Vec4{1, 1, 1, 1}, colorVec4: mgl32.Vec4{1, 1, 1, 1},
@ -323,9 +221,16 @@ func NewLineColor(parent pixelgl.Doer, c color.Color, a, b Vec, width float64) *
} }
} }
va.SetVertices(vertices) vertices = []map[pixelgl.Attr]interface{}{
vertices[0],
vertices[1],
vertices[2],
vertices[1],
vertices[2],
vertices[3],
}
lc := &LineColor{NewShape(parent, nil, c, Position(0), va), a, b, width} lc := &LineColor{NewShape(nil, c, Position(0), vertices), a, b, width}
lc.setPoints() lc.setPoints()
return lc return lc
} }

21
interface.go Normal file
View File

@ -0,0 +1,21 @@
package pixel
import "github.com/faiface/pixel/pixelgl"
// Target is an OpenGL graphics destination such as a window, a canvas, and so on. Something that
// you can draw on.
type Target interface {
pixelgl.BeginEnder
Shader() *pixelgl.Shader
// MakeVertexArray returns a new vertex array drawable on the Target.
MakeVertexArray(vertices []map[pixelgl.Attr]interface{}) *pixelgl.VertexArray
}
// Drawer is anything that can be drawn. It's by no means a drawer inside your table.
//
// Drawer consists of a single methods: Draw. Draw takes a target and any number of transform
// arguments. It's up to a Drawer to make sure that it draws correctly onto the provided target.
type Drawer interface {
Draw(target Target, t ...Transform)
}

View File

@ -24,16 +24,19 @@ func NewPicture(img image.Image, smooth bool) *Picture {
rgba := image.NewRGBA(image.Rect(0, 0, img.Bounds().Dx(), img.Bounds().Dy())) rgba := image.NewRGBA(image.Rect(0, 0, img.Bounds().Dx(), img.Bounds().Dy()))
draw.Draw(rgba, rgba.Bounds(), img, img.Bounds().Min, draw.Src) draw.Draw(rgba, rgba.Bounds(), img, img.Bounds().Min, draw.Src)
texture, err := pixelgl.NewTexture( var texture *pixelgl.Texture
pixelgl.NoOpDoer, pixelgl.Do(func() {
img.Bounds().Dx(), var err error
img.Bounds().Dy(), texture, err = pixelgl.NewTexture(
smooth, img.Bounds().Dx(),
rgba.Pix, img.Bounds().Dy(),
) smooth,
if err != nil { rgba.Pix,
panic(errors.Wrap(err, "failed to create picture")) )
} if err != nil {
panic(errors.Wrap(err, "failed to create picture"))
}
})
return &Picture{ return &Picture{
texture: texture, texture: texture,

146
window.go
View File

@ -2,7 +2,6 @@ package pixel
import ( import (
"image/color" "image/color"
"sync"
"runtime" "runtime"
@ -58,10 +57,10 @@ type WindowConfig struct {
// Window is a window handler. Use this type to manipulate a window (input, drawing, ...). // Window is a window handler. Use this type to manipulate a window (input, drawing, ...).
type Window struct { type Window struct {
enabled bool enabled bool
window *glfw.Window window *glfw.Window
config WindowConfig config WindowConfig
defaultShader *pixelgl.Shader shader *pixelgl.Shader
// need to save these to correctly restore a fullscreen window // need to save these to correctly restore a fullscreen window
restore struct { restore struct {
@ -74,6 +73,8 @@ type Window struct {
} }
} }
var currentWindow *Window
// NewWindow creates a new window with it's properties specified in the provided config. // NewWindow creates a new window with it's properties specified in the provided config.
// //
// If window creation fails, an error is returned. // If window creation fails, an error is returned.
@ -103,7 +104,11 @@ func NewWindow(config WindowConfig) (*Window, error) {
glfw.WindowHint(glfw.Maximized, bool2int[config.Maximized]) glfw.WindowHint(glfw.Maximized, bool2int[config.Maximized])
glfw.WindowHint(glfw.Samples, config.MSAASamples) glfw.WindowHint(glfw.Samples, config.MSAASamples)
w.window, err = glfw.CreateWindow(int(config.Width), int(config.Height), config.Title, nil, nil) var share *glfw.Window
if currentWindow != nil {
share = currentWindow.window
}
w.window, err = glfw.CreateWindow(int(config.Width), int(config.Height), config.Title, nil, share)
if err != nil { if err != nil {
return err return err
} }
@ -114,13 +119,11 @@ func NewWindow(config WindowConfig) (*Window, error) {
return nil, errors.Wrap(err, "creating window failed") return nil, errors.Wrap(err, "creating window failed")
} }
w.initInput() pixelgl.Do(func() {
w.Begin()
defer w.End()
w.SetFullscreen(config.Fullscreen) w.shader, err = pixelgl.NewShader(
w.Do(func(pixelgl.Context) {
w.defaultShader, err = pixelgl.NewShader(
pixelgl.NoOpDoer,
defaultVertexFormat, defaultVertexFormat,
defaultUniformFormat, defaultUniformFormat,
defaultVertexShader, defaultVertexShader,
@ -128,14 +131,21 @@ func NewWindow(config WindowConfig) (*Window, error) {
) )
// default uniforms // default uniforms
w.defaultShader.SetUniformAttr(maskColorVec4, mgl32.Vec4{1, 1, 1, 1}) w.shader.Begin()
w.defaultShader.SetUniformAttr(transformMat3, mgl32.Ident3()) w.shader.SetUniformAttr(maskColorVec4, mgl32.Vec4{1, 1, 1, 1})
w.shader.SetUniformAttr(transformMat3, mgl32.Ident3())
// this is tricky, w.shader.End() is not needed here, because it will
// actually be ended by a deferred w.End() call
}) })
if err != nil { if err != nil {
w.Destroy() w.Destroy()
return nil, errors.Wrap(err, "creating window failed") return nil, errors.Wrap(err, "creating window failed")
} }
w.initInput()
w.SetFullscreen(config.Fullscreen)
runtime.SetFinalizer(w, (*Window).Destroy) runtime.SetFinalizer(w, (*Window).Destroy)
return w, nil return w, nil
@ -150,37 +160,42 @@ func (w *Window) Destroy() {
// Clear clears the window with a color. // Clear clears the window with a color.
func (w *Window) Clear(c color.Color) { func (w *Window) Clear(c color.Color) {
w.Do(func(pixelgl.Context) { pixelgl.DoNoBlock(func() {
pixelgl.DoNoBlock(func() { w.Begin()
c := NRGBAModel.Convert(c).(NRGBA) defer w.End()
gl.ClearColor(float32(c.R), float32(c.G), float32(c.B), float32(c.A))
gl.Clear(gl.COLOR_BUFFER_BIT) c := NRGBAModel.Convert(c).(NRGBA)
}) gl.ClearColor(float32(c.R), float32(c.G), float32(c.B), float32(c.A))
gl.Clear(gl.COLOR_BUFFER_BIT)
}) })
} }
// Update swaps buffers and polls events. // Update swaps buffers and polls events.
func (w *Window) Update() { func (w *Window) Update() {
w.Do(func(pixelgl.Context) { pixelgl.Do(func() {
pixelgl.Do(func() { w.Begin()
if w.config.VSync { defer w.End()
glfw.SwapInterval(1)
}
w.window.SwapBuffers()
})
w.updateInput() if w.config.VSync {
glfw.SwapInterval(1)
}
w.window.SwapBuffers()
})
pixelgl.Do(func() { w.updateInput()
w, h := w.window.GetSize()
gl.Viewport(0, 0, int32(w), int32(h)) pixelgl.Do(func() {
}) w.Begin()
defer w.End()
w, h := w.window.GetSize()
gl.Viewport(0, 0, int32(w), int32(h))
}) })
} }
// DefaultShader returns the default shader used by a window. // Shader returns the default shader used by a window.
func (w *Window) DefaultShader() *pixelgl.Shader { func (w *Window) Shader() *pixelgl.Shader {
return w.defaultShader return w.shader
} }
// SetClosed sets the closed flag of a window. // SetClosed sets the closed flag of a window.
@ -327,33 +342,50 @@ func (w *Window) Restore() {
}) })
} }
var currentWindow struct { // Begin makes the OpenGL context of a window current and binds it's shader.
sync.Mutex //
handler *Window // You usually do not need to use this method, however, you have to use it when you're
// directly using this window's context (such as drawing on it using OpenGL).
//
// Note, that this method must be called inside the main OpenGL thread (pixelgl.Do/DoNoBlock/DoErr/DoVal).
func (w *Window) Begin() {
if currentWindow != w {
w.window.MakeContextCurrent()
pixelgl.Init()
currentWindow = w
}
if w.shader != nil {
w.shader.Begin()
}
} }
// Do makes the context of this window current, if it's not already, and executes sub. // End unbinds the shader of a window.
func (w *Window) Do(sub func(pixelgl.Context)) { func (w *Window) End() {
if !w.enabled { if w.shader != nil {
currentWindow.Lock() w.shader.End()
defer currentWindow.Unlock() }
}
if currentWindow.handler != w { // MakeVertexArray implements Target.
pixelgl.Do(func() { func (w *Window) MakeVertexArray(vertices []map[pixelgl.Attr]interface{}) *pixelgl.VertexArray {
w.window.MakeContextCurrent() var va *pixelgl.VertexArray
pixelgl.Init()
}) pixelgl.Do(func() {
currentWindow.handler = w w.Begin()
defer w.End()
var err error
va, err = pixelgl.NewVertexArray(w.Shader(), len(vertices))
if err != nil {
panic(err)
} }
}
w.enabled = true va.Begin()
if w.defaultShader != nil { va.SetVertices(vertices)
w.defaultShader.Do(sub) va.End()
} else { })
sub(pixelgl.Context{})
} return va
w.enabled = false
} }
var defaultVertexFormat = pixelgl.AttrFormat{ var defaultVertexFormat = pixelgl.AttrFormat{