adopt github.com/faiface/glhf
This commit is contained in:
parent
ef76333994
commit
3300f02d21
34
canvas.go
34
canvas.go
|
@ -3,8 +3,8 @@ package pixel
|
||||||
import (
|
import (
|
||||||
"image/color"
|
"image/color"
|
||||||
|
|
||||||
|
"github.com/faiface/glhf"
|
||||||
"github.com/faiface/mainthread"
|
"github.com/faiface/mainthread"
|
||||||
"github.com/faiface/pixel/pixelgl"
|
|
||||||
"github.com/go-gl/mathgl/mgl32"
|
"github.com/go-gl/mathgl/mgl32"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
@ -13,10 +13,10 @@ import (
|
||||||
//
|
//
|
||||||
// Canvas supports TrianglesPosition, TrianglesColor and TrianglesTexture.
|
// Canvas supports TrianglesPosition, TrianglesColor and TrianglesTexture.
|
||||||
type Canvas struct {
|
type Canvas struct {
|
||||||
f *pixelgl.Frame
|
f *glhf.Frame
|
||||||
s *pixelgl.Shader
|
s *glhf.Shader
|
||||||
|
|
||||||
copyVs *pixelgl.VertexSlice
|
copyVs *glhf.VertexSlice
|
||||||
smooth bool
|
smooth bool
|
||||||
|
|
||||||
drawTd TrianglesDrawer
|
drawTd TrianglesDrawer
|
||||||
|
@ -32,8 +32,8 @@ func NewCanvas(width, height float64, smooth bool) *Canvas {
|
||||||
c := &Canvas{smooth: smooth}
|
c := &Canvas{smooth: smooth}
|
||||||
mainthread.Call(func() {
|
mainthread.Call(func() {
|
||||||
var err error
|
var err error
|
||||||
c.f = pixelgl.NewFrame(int(width), int(height), smooth)
|
c.f = glhf.NewFrame(int(width), int(height), smooth)
|
||||||
c.s, err = pixelgl.NewShader(
|
c.s, err = glhf.NewShader(
|
||||||
canvasVertexFormat,
|
canvasVertexFormat,
|
||||||
canvasUniformFormat,
|
canvasUniformFormat,
|
||||||
canvasVertexShader,
|
canvasVertexShader,
|
||||||
|
@ -43,7 +43,7 @@ func NewCanvas(width, height float64, smooth bool) *Canvas {
|
||||||
panic(errors.Wrap(err, "failed to create canvas"))
|
panic(errors.Wrap(err, "failed to create canvas"))
|
||||||
}
|
}
|
||||||
|
|
||||||
c.copyVs = pixelgl.MakeVertexSlice(c.s, 6, 6)
|
c.copyVs = glhf.MakeVertexSlice(c.s, 6, 6)
|
||||||
c.copyVs.Begin()
|
c.copyVs.Begin()
|
||||||
c.copyVs.SetVertexData([]float32{
|
c.copyVs.SetVertexData([]float32{
|
||||||
-1, -1, 1, 1, 1, 1, 0, 0,
|
-1, -1, 1, 1, 1, 1, 0, 0,
|
||||||
|
@ -79,7 +79,7 @@ func (c *Canvas) SetSize(width, height float64) {
|
||||||
}
|
}
|
||||||
mainthread.Call(func() {
|
mainthread.Call(func() {
|
||||||
oldF := c.f
|
oldF := c.f
|
||||||
c.f = pixelgl.NewFrame(int(width), int(height), c.smooth)
|
c.f = glhf.NewFrame(int(width), int(height), c.smooth)
|
||||||
|
|
||||||
c.f.Begin()
|
c.f.Begin()
|
||||||
c.s.Begin()
|
c.s.Begin()
|
||||||
|
@ -116,7 +116,7 @@ func (c *Canvas) Clear(col color.Color) {
|
||||||
mainthread.CallNonBlock(func() {
|
mainthread.CallNonBlock(func() {
|
||||||
c.f.Begin()
|
c.f.Begin()
|
||||||
col := NRGBAModel.Convert(col).(NRGBA)
|
col := NRGBAModel.Convert(col).(NRGBA)
|
||||||
pixelgl.Clear(float32(col.R), float32(col.G), float32(col.B), float32(col.A))
|
glhf.Clear(float32(col.R), float32(col.G), float32(col.B), float32(col.A))
|
||||||
c.f.End()
|
c.f.End()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -209,10 +209,10 @@ const (
|
||||||
canvasTextureVec2
|
canvasTextureVec2
|
||||||
)
|
)
|
||||||
|
|
||||||
var canvasVertexFormat = pixelgl.AttrFormat{
|
var canvasVertexFormat = glhf.AttrFormat{
|
||||||
canvasPositionVec2: {Name: "position", Type: pixelgl.Vec2},
|
canvasPositionVec2: {Name: "position", Type: glhf.Vec2},
|
||||||
canvasColorVec4: {Name: "color", Type: pixelgl.Vec4},
|
canvasColorVec4: {Name: "color", Type: glhf.Vec4},
|
||||||
canvasTextureVec2: {Name: "texture", Type: pixelgl.Vec2},
|
canvasTextureVec2: {Name: "texture", Type: glhf.Vec2},
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -221,10 +221,10 @@ const (
|
||||||
canvasBoundsVec4
|
canvasBoundsVec4
|
||||||
)
|
)
|
||||||
|
|
||||||
var canvasUniformFormat = pixelgl.AttrFormat{
|
var canvasUniformFormat = glhf.AttrFormat{
|
||||||
{Name: "maskColor", Type: pixelgl.Vec4},
|
{Name: "maskColor", Type: glhf.Vec4},
|
||||||
{Name: "transform", Type: pixelgl.Mat3},
|
{Name: "transform", Type: glhf.Mat3},
|
||||||
{Name: "bounds", Type: pixelgl.Vec4},
|
{Name: "bounds", Type: glhf.Vec4},
|
||||||
}
|
}
|
||||||
|
|
||||||
var canvasVertexShader = `
|
var canvasVertexShader = `
|
||||||
|
|
|
@ -3,23 +3,23 @@ package pixel
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/faiface/glhf"
|
||||||
"github.com/faiface/mainthread"
|
"github.com/faiface/mainthread"
|
||||||
"github.com/faiface/pixel/pixelgl"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewGLTriangles returns OpenGL triangles implemented using pixelgl.VertexSlice. A few notes.
|
// NewGLTriangles returns OpenGL triangles implemented using glhf.VertexSlice. A few notes.
|
||||||
//
|
//
|
||||||
// Triangles returned from this function support TrianglesPosition, TrianglesColor and
|
// Triangles returned from this function support TrianglesPosition, TrianglesColor and
|
||||||
// TrianglesTexture. If you need to support more, you can "override" SetLen and Update method.
|
// TrianglesTexture. If you need to support more, you can "override" SetLen and Update method.
|
||||||
//
|
//
|
||||||
// Draw method simply draws the underlying pixelgl.VertexSlice. It needs to be called in the main
|
// Draw method simply draws the underlying glhf.VertexSlice. It needs to be called in the main
|
||||||
// thread manually. Also, you need to take care of additional Target initialization or setting of
|
// thread manually. Also, you need to take care of additional Target initialization or setting of
|
||||||
// uniform attributes.
|
// uniform attributes.
|
||||||
func NewGLTriangles(shader *pixelgl.Shader, t Triangles) TargetTriangles {
|
func NewGLTriangles(shader *glhf.Shader, t Triangles) TargetTriangles {
|
||||||
var gt *glTriangles
|
var gt *glTriangles
|
||||||
mainthread.Call(func() {
|
mainthread.Call(func() {
|
||||||
gt = &glTriangles{
|
gt = &glTriangles{
|
||||||
vs: pixelgl.MakeVertexSlice(shader, 0, t.Len()),
|
vs: glhf.MakeVertexSlice(shader, 0, t.Len()),
|
||||||
shader: shader,
|
shader: shader,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -29,9 +29,9 @@ func NewGLTriangles(shader *pixelgl.Shader, t Triangles) TargetTriangles {
|
||||||
}
|
}
|
||||||
|
|
||||||
type glTriangles struct {
|
type glTriangles struct {
|
||||||
vs *pixelgl.VertexSlice
|
vs *glhf.VertexSlice
|
||||||
data []float32
|
data []float32
|
||||||
shader *pixelgl.Shader
|
shader *glhf.Shader
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gt *glTriangles) Len() int {
|
func (gt *glTriangles) Len() int {
|
||||||
|
|
10
graphics.go
10
graphics.go
|
@ -254,9 +254,13 @@ func (p *Polygon) Color() NRGBA {
|
||||||
//
|
//
|
||||||
// However, it is less expensive than using a transform on a Target.
|
// However, it is less expensive than using a transform on a Target.
|
||||||
func (p *Polygon) SetPoints(points ...Vec) {
|
func (p *Polygon) SetPoints(points ...Vec) {
|
||||||
p.data.SetLen(len(points))
|
p.data.SetLen(3 * (len(points) - 2))
|
||||||
for i, pt := range points {
|
for i := 2; i < len(points); i++ {
|
||||||
p.data[i].Position = pt
|
p.data[(i-2)*3+0].Position = points[0]
|
||||||
|
p.data[(i-2)*3+1].Position = points[i-1]
|
||||||
|
p.data[(i-2)*3+2].Position = points[i]
|
||||||
|
}
|
||||||
|
for i := range p.data {
|
||||||
p.data[i].Color = p.col
|
p.data[i].Color = p.col
|
||||||
}
|
}
|
||||||
p.td.Dirty()
|
p.td.Dirty()
|
||||||
|
|
12
picture.go
12
picture.go
|
@ -4,8 +4,8 @@ import (
|
||||||
"image"
|
"image"
|
||||||
"image/draw"
|
"image/draw"
|
||||||
|
|
||||||
|
"github.com/faiface/glhf"
|
||||||
"github.com/faiface/mainthread"
|
"github.com/faiface/mainthread"
|
||||||
"github.com/faiface/pixel/pixelgl"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Picture is a raster picture. It is usually used with sprites.
|
// Picture is a raster picture. It is usually used with sprites.
|
||||||
|
@ -14,7 +14,7 @@ import (
|
||||||
// generated. After the creation, Pictures can be sliced (slicing creates a "sub-Picture"
|
// generated. After the creation, Pictures can be sliced (slicing creates a "sub-Picture"
|
||||||
// from a Picture) into smaller Pictures.
|
// from a Picture) into smaller Pictures.
|
||||||
type Picture struct {
|
type Picture struct {
|
||||||
tex *pixelgl.Texture
|
tex *glhf.Texture
|
||||||
bounds Rect
|
bounds Rect
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,9 +35,9 @@ func NewPicture(img image.Image, smooth bool) *Picture {
|
||||||
copy(jSlice, tmp)
|
copy(jSlice, tmp)
|
||||||
}
|
}
|
||||||
|
|
||||||
var tex *pixelgl.Texture
|
var tex *glhf.Texture
|
||||||
mainthread.Call(func() {
|
mainthread.Call(func() {
|
||||||
tex = pixelgl.NewTexture(
|
tex = glhf.NewTexture(
|
||||||
img.Bounds().Dx(),
|
img.Bounds().Dx(),
|
||||||
img.Bounds().Dy(),
|
img.Bounds().Dy(),
|
||||||
smooth,
|
smooth,
|
||||||
|
@ -49,7 +49,7 @@ func NewPicture(img image.Image, smooth bool) *Picture {
|
||||||
}
|
}
|
||||||
|
|
||||||
// PictureFromTexture returns a new Picture that spans the whole supplied Texture.
|
// PictureFromTexture returns a new Picture that spans the whole supplied Texture.
|
||||||
func PictureFromTexture(tex *pixelgl.Texture) *Picture {
|
func PictureFromTexture(tex *glhf.Texture) *Picture {
|
||||||
return &Picture{
|
return &Picture{
|
||||||
tex: tex,
|
tex: tex,
|
||||||
bounds: R(0, 0, float64(tex.Width()), float64(tex.Height())),
|
bounds: R(0, 0, float64(tex.Width()), float64(tex.Height())),
|
||||||
|
@ -88,7 +88,7 @@ func (p *Picture) Image() *image.NRGBA {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Texture returns a pointer to the underlying OpenGL texture of the Picture.
|
// Texture returns a pointer to the underlying OpenGL texture of the Picture.
|
||||||
func (p *Picture) Texture() *pixelgl.Texture {
|
func (p *Picture) Texture() *glhf.Texture {
|
||||||
return p.tex
|
return p.tex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,80 +0,0 @@
|
||||||
package pixelgl
|
|
||||||
|
|
||||||
// AttrFormat defines names and types of OpenGL attributes (vertex format, uniform format, etc.).
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
// AttrFormat{{"position", Vec2}, {"color", Vec4}, {"texCoord": Vec2}}
|
|
||||||
type AttrFormat []Attr
|
|
||||||
|
|
||||||
// Size returns the total size of all attributes of the AttrFormat.
|
|
||||||
func (af AttrFormat) Size() int {
|
|
||||||
total := 0
|
|
||||||
for _, attr := range af {
|
|
||||||
total += attr.Type.Size()
|
|
||||||
}
|
|
||||||
return total
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attr represents an arbitrary OpenGL attribute, such as a vertex attribute or a shader
|
|
||||||
// uniform attribute.
|
|
||||||
type Attr struct {
|
|
||||||
Name string
|
|
||||||
Type AttrType
|
|
||||||
}
|
|
||||||
|
|
||||||
// AttrType represents the type of an OpenGL attribute.
|
|
||||||
type AttrType int
|
|
||||||
|
|
||||||
// List of all possible attribute types.
|
|
||||||
const (
|
|
||||||
Int AttrType = iota
|
|
||||||
Float
|
|
||||||
Vec2
|
|
||||||
Vec3
|
|
||||||
Vec4
|
|
||||||
Mat2
|
|
||||||
Mat23
|
|
||||||
Mat24
|
|
||||||
Mat3
|
|
||||||
Mat32
|
|
||||||
Mat34
|
|
||||||
Mat4
|
|
||||||
Mat42
|
|
||||||
Mat43
|
|
||||||
)
|
|
||||||
|
|
||||||
// Size returns the size of a type in bytes.
|
|
||||||
func (at AttrType) Size() int {
|
|
||||||
switch at {
|
|
||||||
case Int:
|
|
||||||
return 4
|
|
||||||
case Float:
|
|
||||||
return 4
|
|
||||||
case Vec2:
|
|
||||||
return 2 * 4
|
|
||||||
case Vec3:
|
|
||||||
return 3 * 4
|
|
||||||
case Vec4:
|
|
||||||
return 4 * 4
|
|
||||||
case Mat2:
|
|
||||||
return 2 * 2 * 4
|
|
||||||
case Mat23:
|
|
||||||
return 2 * 3 * 4
|
|
||||||
case Mat24:
|
|
||||||
return 2 * 4 * 4
|
|
||||||
case Mat3:
|
|
||||||
return 3 * 3 * 4
|
|
||||||
case Mat32:
|
|
||||||
return 3 * 2 * 4
|
|
||||||
case Mat34:
|
|
||||||
return 3 * 4 * 4
|
|
||||||
case Mat4:
|
|
||||||
return 4 * 4 * 4
|
|
||||||
case Mat42:
|
|
||||||
return 4 * 2 * 4
|
|
||||||
case Mat43:
|
|
||||||
return 4 * 3 * 4
|
|
||||||
default:
|
|
||||||
panic("size of vertex attribute type: invalid type")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
// Package pixelgl provides some abstractions around the basic OpenGL primitives and
|
|
||||||
// operations.
|
|
||||||
//
|
|
||||||
// All calls should be done from the main thread using "github.com/faiface/mainthread" package.
|
|
||||||
//
|
|
||||||
// This package deliberately does not handle nor report OpenGL errors, it's up to you to
|
|
||||||
// cause none.
|
|
||||||
package pixelgl
|
|
|
@ -1,75 +0,0 @@
|
||||||
package pixelgl
|
|
||||||
|
|
||||||
import (
|
|
||||||
"runtime"
|
|
||||||
|
|
||||||
"github.com/faiface/mainthread"
|
|
||||||
"github.com/go-gl/gl/v3.3-core/gl"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Frame is a fixed resolution texture that you can draw on.
|
|
||||||
type Frame struct {
|
|
||||||
fb binder
|
|
||||||
tex *Texture
|
|
||||||
width, height int
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFrame creates a new fully transparent Frame with given dimensions in pixels.
|
|
||||||
func NewFrame(width, height int, smooth bool) *Frame {
|
|
||||||
f := &Frame{
|
|
||||||
fb: binder{
|
|
||||||
restoreLoc: gl.FRAMEBUFFER_BINDING,
|
|
||||||
bindFunc: func(obj uint32) {
|
|
||||||
gl.BindFramebuffer(gl.FRAMEBUFFER, obj)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
width: width,
|
|
||||||
height: height,
|
|
||||||
}
|
|
||||||
|
|
||||||
gl.GenFramebuffers(1, &f.fb.obj)
|
|
||||||
|
|
||||||
f.tex = NewTexture(width, height, smooth, make([]uint8, width*height*4))
|
|
||||||
|
|
||||||
f.fb.bind()
|
|
||||||
gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, f.tex.tex.obj, 0)
|
|
||||||
f.fb.restore()
|
|
||||||
|
|
||||||
runtime.SetFinalizer(f, (*Frame).delete)
|
|
||||||
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Frame) delete() {
|
|
||||||
mainthread.CallNonBlock(func() {
|
|
||||||
gl.DeleteFramebuffers(1, &f.fb.obj)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Width returns the width of the Frame in pixels.
|
|
||||||
func (f *Frame) Width() int {
|
|
||||||
return f.width
|
|
||||||
}
|
|
||||||
|
|
||||||
// Height returns the height of the Frame in pixels.
|
|
||||||
func (f *Frame) Height() int {
|
|
||||||
return f.height
|
|
||||||
}
|
|
||||||
|
|
||||||
// Begin binds the Frame. All draw operations will target this Frame until End is called.
|
|
||||||
func (f *Frame) Begin() {
|
|
||||||
f.fb.bind()
|
|
||||||
gl.Viewport(0, 0, int32(f.width), int32(f.height))
|
|
||||||
}
|
|
||||||
|
|
||||||
// End unbinds the Frame. All draw operations will go to whatever was bound before this Frame.
|
|
||||||
func (f *Frame) End() {
|
|
||||||
f.fb.restore()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Texture returns the Texture that this Frame draws to. The Texture changes as you use the Frame.
|
|
||||||
//
|
|
||||||
// The Texture pointer returned from this method is always the same.
|
|
||||||
func (f *Frame) Texture() *Texture {
|
|
||||||
return f.tex
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
package pixelgl
|
|
||||||
|
|
||||||
// BeginEnder is an interface for manipulating OpenGL state.
|
|
||||||
//
|
|
||||||
// OpenGL is a state machine. Every object can 'enter' it's state and 'leave' it's state. For
|
|
||||||
// example, you can bind a buffer and unbind a buffer, bind a texture and unbind it, use shader
|
|
||||||
// and unuse it, and so on.
|
|
||||||
type BeginEnder interface {
|
|
||||||
Begin()
|
|
||||||
End()
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
package pixelgl
|
|
||||||
|
|
||||||
import "github.com/go-gl/gl/v3.3-core/gl"
|
|
||||||
|
|
||||||
// Init initializes OpenGL by loading function pointers from the active OpenGL context.
|
|
||||||
// This function must be manually run inside the main thread (using "github.com/faiface/mainthread"
|
|
||||||
// package).
|
|
||||||
//
|
|
||||||
// It must be called under the presence of an active OpenGL context, e.g., always after calling
|
|
||||||
// window.MakeContextCurrent(). Also, always call this function when switching contexts.
|
|
||||||
func Init() {
|
|
||||||
err := gl.Init()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
gl.Enable(gl.BLEND)
|
|
||||||
gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear clears the current framebuffer or window with the given color.
|
|
||||||
func Clear(r, g, b, a float32) {
|
|
||||||
gl.ClearColor(r, g, b, a)
|
|
||||||
gl.Clear(gl.COLOR_BUFFER_BIT)
|
|
||||||
}
|
|
|
@ -1,219 +0,0 @@
|
||||||
package pixelgl
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"runtime"
|
|
||||||
|
|
||||||
"github.com/faiface/mainthread"
|
|
||||||
"github.com/go-gl/gl/v3.3-core/gl"
|
|
||||||
"github.com/go-gl/mathgl/mgl32"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Shader is an OpenGL shader program.
|
|
||||||
type Shader struct {
|
|
||||||
program binder
|
|
||||||
vertexFmt AttrFormat
|
|
||||||
uniformFmt AttrFormat
|
|
||||||
uniformLoc []int32
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewShader creates a new shader program from the specified vertex shader and fragment shader
|
|
||||||
// sources.
|
|
||||||
//
|
|
||||||
// Note that vertexShader and fragmentShader parameters must contain the source code, they're
|
|
||||||
// not filenames.
|
|
||||||
func NewShader(vertexFmt, uniformFmt AttrFormat, vertexShader, fragmentShader string) (*Shader, error) {
|
|
||||||
shader := &Shader{
|
|
||||||
program: binder{
|
|
||||||
restoreLoc: gl.CURRENT_PROGRAM,
|
|
||||||
bindFunc: func(obj uint32) {
|
|
||||||
gl.UseProgram(obj)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
vertexFmt: vertexFmt,
|
|
||||||
uniformFmt: uniformFmt,
|
|
||||||
uniformLoc: make([]int32, len(uniformFmt)),
|
|
||||||
}
|
|
||||||
|
|
||||||
var vshader, fshader uint32
|
|
||||||
|
|
||||||
// vertex shader
|
|
||||||
{
|
|
||||||
vshader = gl.CreateShader(gl.VERTEX_SHADER)
|
|
||||||
src, free := gl.Strs(vertexShader)
|
|
||||||
defer free()
|
|
||||||
length := int32(len(vertexShader))
|
|
||||||
gl.ShaderSource(vshader, 1, src, &length)
|
|
||||||
gl.CompileShader(vshader)
|
|
||||||
|
|
||||||
var success int32
|
|
||||||
gl.GetShaderiv(vshader, gl.COMPILE_STATUS, &success)
|
|
||||||
if success == gl.FALSE {
|
|
||||||
var logLen int32
|
|
||||||
gl.GetShaderiv(vshader, gl.INFO_LOG_LENGTH, &logLen)
|
|
||||||
|
|
||||||
infoLog := make([]byte, logLen)
|
|
||||||
gl.GetShaderInfoLog(vshader, logLen, nil, &infoLog[0])
|
|
||||||
return nil, fmt.Errorf("error compiling vertex shader: %s", string(infoLog))
|
|
||||||
}
|
|
||||||
|
|
||||||
defer gl.DeleteShader(vshader)
|
|
||||||
}
|
|
||||||
|
|
||||||
// fragment shader
|
|
||||||
{
|
|
||||||
fshader = gl.CreateShader(gl.FRAGMENT_SHADER)
|
|
||||||
src, free := gl.Strs(fragmentShader)
|
|
||||||
defer free()
|
|
||||||
length := int32(len(fragmentShader))
|
|
||||||
gl.ShaderSource(fshader, 1, src, &length)
|
|
||||||
gl.CompileShader(fshader)
|
|
||||||
|
|
||||||
var success int32
|
|
||||||
gl.GetShaderiv(fshader, gl.COMPILE_STATUS, &success)
|
|
||||||
if success == gl.FALSE {
|
|
||||||
var logLen int32
|
|
||||||
gl.GetShaderiv(fshader, gl.INFO_LOG_LENGTH, &logLen)
|
|
||||||
|
|
||||||
infoLog := make([]byte, logLen)
|
|
||||||
gl.GetShaderInfoLog(fshader, logLen, nil, &infoLog[0])
|
|
||||||
return nil, fmt.Errorf("error compiling fragment shader: %s", string(infoLog))
|
|
||||||
}
|
|
||||||
|
|
||||||
defer gl.DeleteShader(fshader)
|
|
||||||
}
|
|
||||||
|
|
||||||
// shader program
|
|
||||||
{
|
|
||||||
shader.program.obj = gl.CreateProgram()
|
|
||||||
gl.AttachShader(shader.program.obj, vshader)
|
|
||||||
gl.AttachShader(shader.program.obj, fshader)
|
|
||||||
gl.LinkProgram(shader.program.obj)
|
|
||||||
|
|
||||||
var success int32
|
|
||||||
gl.GetProgramiv(shader.program.obj, gl.LINK_STATUS, &success)
|
|
||||||
if success == gl.FALSE {
|
|
||||||
var logLen int32
|
|
||||||
gl.GetProgramiv(shader.program.obj, gl.INFO_LOG_LENGTH, &logLen)
|
|
||||||
|
|
||||||
infoLog := make([]byte, logLen)
|
|
||||||
gl.GetProgramInfoLog(shader.program.obj, logLen, nil, &infoLog[0])
|
|
||||||
return nil, fmt.Errorf("error linking shader program: %s", string(infoLog))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// uniforms
|
|
||||||
for i, uniform := range uniformFmt {
|
|
||||||
loc := gl.GetUniformLocation(shader.program.obj, gl.Str(uniform.Name+"\x00"))
|
|
||||||
shader.uniformLoc[i] = loc
|
|
||||||
}
|
|
||||||
|
|
||||||
runtime.SetFinalizer(shader, (*Shader).delete)
|
|
||||||
|
|
||||||
return shader, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Shader) delete() {
|
|
||||||
mainthread.CallNonBlock(func() {
|
|
||||||
gl.DeleteProgram(s.program.obj)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// VertexFormat returns the vertex attribute format of this Shader. Do not change it.
|
|
||||||
func (s *Shader) VertexFormat() AttrFormat {
|
|
||||||
return s.vertexFmt
|
|
||||||
}
|
|
||||||
|
|
||||||
// UniformFormat returns the uniform attribute format of this Shader. Do not change it.
|
|
||||||
func (s *Shader) UniformFormat() AttrFormat {
|
|
||||||
return s.uniformFmt
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetUniformAttr sets the value of a uniform attribute of this Shader. The attribute is
|
|
||||||
// specified by the index in the Shader's uniform format.
|
|
||||||
//
|
|
||||||
// If the uniform attribute does not exist in the Shader, this method returns false.
|
|
||||||
//
|
|
||||||
// Supplied value must correspond to the type of the attribute. Correct types are these
|
|
||||||
// (right-hand is the type of the value):
|
|
||||||
// Attr{Type: Int}: int32
|
|
||||||
// Attr{Type: Float}: float32
|
|
||||||
// Attr{Type: Vec2}: mgl32.Vec2
|
|
||||||
// Attr{Type: Vec3}: mgl32.Vec3
|
|
||||||
// Attr{Type: Vec4}: mgl32.Vec4
|
|
||||||
// Attr{Type: Mat2}: mgl32.Mat2
|
|
||||||
// Attr{Type: Mat23}: mgl32.Mat2x3
|
|
||||||
// Attr{Type: Mat24}: mgl32.Mat2x4
|
|
||||||
// Attr{Type: Mat3}: mgl32.Mat3
|
|
||||||
// Attr{Type: Mat32}: mgl32.Mat3x2
|
|
||||||
// Attr{Type: Mat34}: mgl32.Mat3x4
|
|
||||||
// Attr{Type: Mat4}: mgl32.Mat4
|
|
||||||
// Attr{Type: Mat42}: mgl32.Mat4x2
|
|
||||||
// Attr{Type: Mat43}: mgl32.Mat4x3
|
|
||||||
// No other types are supported.
|
|
||||||
//
|
|
||||||
// The Shader must be bound before calling this method.
|
|
||||||
func (s *Shader) SetUniformAttr(uniform int, value interface{}) (ok bool) {
|
|
||||||
if s.uniformLoc[uniform] < 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
switch s.uniformFmt[uniform].Type {
|
|
||||||
case Int:
|
|
||||||
value := value.(int32)
|
|
||||||
gl.Uniform1iv(s.uniformLoc[uniform], 1, &value)
|
|
||||||
case Float:
|
|
||||||
value := value.(float32)
|
|
||||||
gl.Uniform1fv(s.uniformLoc[uniform], 1, &value)
|
|
||||||
case Vec2:
|
|
||||||
value := value.(mgl32.Vec2)
|
|
||||||
gl.Uniform2fv(s.uniformLoc[uniform], 1, &value[0])
|
|
||||||
case Vec3:
|
|
||||||
value := value.(mgl32.Vec3)
|
|
||||||
gl.Uniform3fv(s.uniformLoc[uniform], 1, &value[0])
|
|
||||||
case Vec4:
|
|
||||||
value := value.(mgl32.Vec4)
|
|
||||||
gl.Uniform4fv(s.uniformLoc[uniform], 1, &value[0])
|
|
||||||
case Mat2:
|
|
||||||
value := value.(mgl32.Mat2)
|
|
||||||
gl.UniformMatrix2fv(s.uniformLoc[uniform], 1, false, &value[0])
|
|
||||||
case Mat23:
|
|
||||||
value := value.(mgl32.Mat2x3)
|
|
||||||
gl.UniformMatrix2x3fv(s.uniformLoc[uniform], 1, false, &value[0])
|
|
||||||
case Mat24:
|
|
||||||
value := value.(mgl32.Mat2x4)
|
|
||||||
gl.UniformMatrix2x4fv(s.uniformLoc[uniform], 1, false, &value[0])
|
|
||||||
case Mat3:
|
|
||||||
value := value.(mgl32.Mat3)
|
|
||||||
gl.UniformMatrix3fv(s.uniformLoc[uniform], 1, false, &value[0])
|
|
||||||
case Mat32:
|
|
||||||
value := value.(mgl32.Mat3x2)
|
|
||||||
gl.UniformMatrix3x2fv(s.uniformLoc[uniform], 1, false, &value[0])
|
|
||||||
case Mat34:
|
|
||||||
value := value.(mgl32.Mat3x4)
|
|
||||||
gl.UniformMatrix3x4fv(s.uniformLoc[uniform], 1, false, &value[0])
|
|
||||||
case Mat4:
|
|
||||||
value := value.(mgl32.Mat4)
|
|
||||||
gl.UniformMatrix4fv(s.uniformLoc[uniform], 1, false, &value[0])
|
|
||||||
case Mat42:
|
|
||||||
value := value.(mgl32.Mat4x2)
|
|
||||||
gl.UniformMatrix4x2fv(s.uniformLoc[uniform], 1, false, &value[0])
|
|
||||||
case Mat43:
|
|
||||||
value := value.(mgl32.Mat4x3)
|
|
||||||
gl.UniformMatrix4x3fv(s.uniformLoc[uniform], 1, false, &value[0])
|
|
||||||
default:
|
|
||||||
panic("set uniform attr: invalid attribute type")
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Begin binds the Shader program. This is necessary before using the Shader.
|
|
||||||
func (s *Shader) Begin() {
|
|
||||||
s.program.bind()
|
|
||||||
}
|
|
||||||
|
|
||||||
// End unbinds the Shader program and restores the previous one.
|
|
||||||
func (s *Shader) End() {
|
|
||||||
s.program.restore()
|
|
||||||
}
|
|
|
@ -1,128 +0,0 @@
|
||||||
package pixelgl
|
|
||||||
|
|
||||||
import (
|
|
||||||
"runtime"
|
|
||||||
|
|
||||||
"github.com/faiface/mainthread"
|
|
||||||
"github.com/go-gl/gl/v3.3-core/gl"
|
|
||||||
"github.com/go-gl/mathgl/mgl32"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Texture is an OpenGL texture.
|
|
||||||
type Texture struct {
|
|
||||||
tex binder
|
|
||||||
width, height int
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewTexture creates a new texture with the specified width and height with some initial
|
|
||||||
// pixel values. The pixels must be a sequence of RGBA values (one byte per component).
|
|
||||||
func NewTexture(width, height int, smooth bool, pixels []uint8) *Texture {
|
|
||||||
tex := &Texture{
|
|
||||||
tex: binder{
|
|
||||||
restoreLoc: gl.TEXTURE_BINDING_2D,
|
|
||||||
bindFunc: func(obj uint32) {
|
|
||||||
gl.BindTexture(gl.TEXTURE_2D, obj)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
width: width,
|
|
||||||
height: height,
|
|
||||||
}
|
|
||||||
|
|
||||||
gl.GenTextures(1, &tex.tex.obj)
|
|
||||||
|
|
||||||
tex.Begin()
|
|
||||||
defer tex.End()
|
|
||||||
|
|
||||||
// initial data
|
|
||||||
gl.TexImage2D(
|
|
||||||
gl.TEXTURE_2D,
|
|
||||||
0,
|
|
||||||
gl.RGBA,
|
|
||||||
int32(width),
|
|
||||||
int32(height),
|
|
||||||
0,
|
|
||||||
gl.RGBA,
|
|
||||||
gl.UNSIGNED_BYTE,
|
|
||||||
gl.Ptr(pixels),
|
|
||||||
)
|
|
||||||
|
|
||||||
borderColor := mgl32.Vec4{0, 0, 0, 0}
|
|
||||||
gl.TexParameterfv(gl.TEXTURE_2D, gl.TEXTURE_BORDER_COLOR, &borderColor[0])
|
|
||||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_BORDER)
|
|
||||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_BORDER)
|
|
||||||
|
|
||||||
if smooth {
|
|
||||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
|
|
||||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
|
|
||||||
} else {
|
|
||||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
|
|
||||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
|
|
||||||
}
|
|
||||||
|
|
||||||
runtime.SetFinalizer(tex, (*Texture).delete)
|
|
||||||
|
|
||||||
return tex
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Texture) delete() {
|
|
||||||
mainthread.CallNonBlock(func() {
|
|
||||||
gl.DeleteTextures(1, &t.tex.obj)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Width returns the width of the Texture in pixels.
|
|
||||||
func (t *Texture) Width() int {
|
|
||||||
return t.width
|
|
||||||
}
|
|
||||||
|
|
||||||
// Height returns the height of the Texture in pixels.
|
|
||||||
func (t *Texture) Height() int {
|
|
||||||
return t.height
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetPixels sets the content of a sub-region of the Texture. Pixels must be an RGBA byte sequence.
|
|
||||||
func (t *Texture) SetPixels(x, y, w, h int, pixels []uint8) {
|
|
||||||
if len(pixels) != w*h*4 {
|
|
||||||
panic("set pixels: wrong number of pixels")
|
|
||||||
}
|
|
||||||
gl.TexSubImage2D(
|
|
||||||
gl.TEXTURE_2D,
|
|
||||||
0,
|
|
||||||
int32(x),
|
|
||||||
int32(y),
|
|
||||||
int32(w),
|
|
||||||
int32(h),
|
|
||||||
gl.RGBA,
|
|
||||||
gl.UNSIGNED_BYTE,
|
|
||||||
gl.Ptr(pixels),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pixels returns the content of a sub-region of the Texture as an RGBA byte sequence.
|
|
||||||
func (t *Texture) Pixels(x, y, w, h int) []uint8 {
|
|
||||||
pixels := make([]uint8, t.width*t.height*4)
|
|
||||||
gl.GetTexImage(
|
|
||||||
gl.TEXTURE_2D,
|
|
||||||
0,
|
|
||||||
gl.RGBA,
|
|
||||||
gl.UNSIGNED_BYTE,
|
|
||||||
gl.Ptr(pixels),
|
|
||||||
)
|
|
||||||
subPixels := make([]uint8, w*h*4)
|
|
||||||
for i := 0; i < h; i++ {
|
|
||||||
row := pixels[(i+y)*t.width*4+x*4 : (i+y)*t.width*4+(x+w)*4]
|
|
||||||
subRow := subPixels[i*w*4 : (i+1)*w*4]
|
|
||||||
copy(subRow, row)
|
|
||||||
}
|
|
||||||
return subPixels
|
|
||||||
}
|
|
||||||
|
|
||||||
// Begin binds the Texture. This is necessary before using the Texture.
|
|
||||||
func (t *Texture) Begin() {
|
|
||||||
t.tex.bind()
|
|
||||||
}
|
|
||||||
|
|
||||||
// End unbinds the Texture and restores the previous one.
|
|
||||||
func (t *Texture) End() {
|
|
||||||
t.tex.restore()
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
package pixelgl
|
|
||||||
|
|
||||||
import "github.com/go-gl/gl/v3.3-core/gl"
|
|
||||||
|
|
||||||
type binder struct {
|
|
||||||
restoreLoc uint32
|
|
||||||
bindFunc func(uint32)
|
|
||||||
|
|
||||||
obj uint32
|
|
||||||
|
|
||||||
prev []uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *binder) bind() *binder {
|
|
||||||
var prev int32
|
|
||||||
gl.GetIntegerv(b.restoreLoc, &prev)
|
|
||||||
b.prev = append(b.prev, uint32(prev))
|
|
||||||
|
|
||||||
if b.prev[len(b.prev)-1] != b.obj {
|
|
||||||
b.bindFunc(b.obj)
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *binder) restore() *binder {
|
|
||||||
if b.prev[len(b.prev)-1] != b.obj {
|
|
||||||
b.bindFunc(b.prev[len(b.prev)-1])
|
|
||||||
}
|
|
||||||
b.prev = b.prev[:len(b.prev)-1]
|
|
||||||
return b
|
|
||||||
}
|
|
|
@ -1,285 +0,0 @@
|
||||||
package pixelgl
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"runtime"
|
|
||||||
|
|
||||||
"github.com/faiface/mainthread"
|
|
||||||
"github.com/go-gl/gl/v3.3-core/gl"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// VertexSlice points to a portion of (or possibly whole) vertex array. It is used as a pointer,
|
|
||||||
// contrary to Go's builtin slices. This is, so that append can be 'in-place'. That's for the good,
|
|
||||||
// because Begin/End-ing a VertexSlice would become super confusing, if append returned a new
|
|
||||||
// VertexSlice.
|
|
||||||
//
|
|
||||||
// It also implements all basic slice-like operations: appending, sub-slicing, etc.
|
|
||||||
//
|
|
||||||
// Note that you need to Begin a VertexSlice before getting or updating it's elements or drawing it.
|
|
||||||
// After you're done with it, you need to End it.
|
|
||||||
type VertexSlice struct {
|
|
||||||
va *vertexArray
|
|
||||||
i, j int
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeVertexSlice allocates a new vertex array with specified capacity and returns a VertexSlice
|
|
||||||
// that points to it's first len elements.
|
|
||||||
//
|
|
||||||
// Note, that a vertex array is specialized for a specific shader and can't be used with another
|
|
||||||
// shader.
|
|
||||||
func MakeVertexSlice(shader *Shader, len, cap int) *VertexSlice {
|
|
||||||
if len > cap {
|
|
||||||
panic("failed to make vertex slice: len > cap")
|
|
||||||
}
|
|
||||||
return &VertexSlice{
|
|
||||||
va: newVertexArray(shader, cap),
|
|
||||||
i: 0,
|
|
||||||
j: len,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// VertexFormat returns the format of vertex attributes inside the underlying vertex array of this
|
|
||||||
// VertexSlice.
|
|
||||||
func (vs *VertexSlice) VertexFormat() AttrFormat {
|
|
||||||
return vs.va.format
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stride returns the number of float32 elements occupied by one vertex.
|
|
||||||
func (vs *VertexSlice) Stride() int {
|
|
||||||
return vs.va.stride / 4
|
|
||||||
}
|
|
||||||
|
|
||||||
// Len returns the length of the VertexSlice (number of vertices).
|
|
||||||
func (vs *VertexSlice) Len() int {
|
|
||||||
return vs.j - vs.i
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cap returns the capacity of an underlying vertex array.
|
|
||||||
func (vs *VertexSlice) Cap() int {
|
|
||||||
return vs.va.cap - vs.i
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetLen resizes the VertexSlice to length len.
|
|
||||||
func (vs *VertexSlice) SetLen(len int) {
|
|
||||||
vs.End() // vs must have been Begin-ed before calling this method
|
|
||||||
*vs = vs.grow(len)
|
|
||||||
vs.Begin()
|
|
||||||
}
|
|
||||||
|
|
||||||
// grow returns supplied vs with length changed to len. Allocates new underlying vertex array if
|
|
||||||
// necessary. The original content is preserved.
|
|
||||||
func (vs VertexSlice) grow(len int) VertexSlice {
|
|
||||||
if len <= vs.Cap() {
|
|
||||||
// capacity sufficient
|
|
||||||
return VertexSlice{
|
|
||||||
va: vs.va,
|
|
||||||
i: vs.i,
|
|
||||||
j: vs.i + len,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// grow the capacity
|
|
||||||
newCap := vs.Cap()
|
|
||||||
if newCap < 1024 {
|
|
||||||
newCap += newCap
|
|
||||||
} else {
|
|
||||||
newCap += newCap / 4
|
|
||||||
}
|
|
||||||
if newCap < len {
|
|
||||||
newCap = len
|
|
||||||
}
|
|
||||||
newVs := VertexSlice{
|
|
||||||
va: newVertexArray(vs.va.shader, newCap),
|
|
||||||
i: 0,
|
|
||||||
j: len,
|
|
||||||
}
|
|
||||||
// preserve the original content
|
|
||||||
newVs.Begin()
|
|
||||||
newVs.Slice(0, vs.Len()).SetVertexData(vs.VertexData())
|
|
||||||
newVs.End()
|
|
||||||
return newVs
|
|
||||||
}
|
|
||||||
|
|
||||||
// Slice returns a sub-slice of this VertexSlice covering the range [i, j) (relative to this
|
|
||||||
// VertexSlice).
|
|
||||||
//
|
|
||||||
// Note, that the returned VertexSlice shares an underlying vertex array with the original
|
|
||||||
// VertexSlice. Modifying the contents of one modifies corresponding contents of the other.
|
|
||||||
func (vs *VertexSlice) Slice(i, j int) *VertexSlice {
|
|
||||||
if i < 0 || j < i || j > vs.va.cap {
|
|
||||||
panic("failed to slice vertex slice: index out of range")
|
|
||||||
}
|
|
||||||
return &VertexSlice{
|
|
||||||
va: vs.va,
|
|
||||||
i: vs.i + i,
|
|
||||||
j: vs.i + j,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetVertexData sets the contents of the VertexSlice.
|
|
||||||
//
|
|
||||||
// The data is a slice of float32's, where each vertex attribute occupies a certain number of
|
|
||||||
// elements. Namely, Float occupies 1, Vec2 occupies 2, Vec3 occupies 3 and Vec4 occupies 4. The
|
|
||||||
// attribues in the data slice must be in the same order as in the vertex format of this Vertex
|
|
||||||
// Slice.
|
|
||||||
//
|
|
||||||
// If the length of vertices does not match the length of the VertexSlice, this methdo panics.
|
|
||||||
func (vs *VertexSlice) SetVertexData(data []float32) {
|
|
||||||
if len(data)/vs.Stride() != vs.Len() {
|
|
||||||
fmt.Println(len(data)/vs.Stride(), vs.Len())
|
|
||||||
panic("set vertex data: wrong length of vertices")
|
|
||||||
}
|
|
||||||
vs.va.setVertexData(vs.i, vs.j, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// VertexData returns the contents of the VertexSlice.
|
|
||||||
//
|
|
||||||
// The data is in the same format as with SetVertexData.
|
|
||||||
func (vs *VertexSlice) VertexData() []float32 {
|
|
||||||
return vs.va.vertexData(vs.i, vs.j)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw draws the content of the VertexSlice.
|
|
||||||
func (vs *VertexSlice) Draw() {
|
|
||||||
vs.va.draw(vs.i, vs.j)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Begin binds the underlying vertex array. Calling this method is necessary before using the VertexSlice.
|
|
||||||
func (vs *VertexSlice) Begin() {
|
|
||||||
vs.va.begin()
|
|
||||||
}
|
|
||||||
|
|
||||||
// End unbinds the underlying vertex array. Call this method when you're done with VertexSlice.
|
|
||||||
func (vs *VertexSlice) End() {
|
|
||||||
vs.va.end()
|
|
||||||
}
|
|
||||||
|
|
||||||
type vertexArray struct {
|
|
||||||
vao, vbo binder
|
|
||||||
cap int
|
|
||||||
format AttrFormat
|
|
||||||
stride int
|
|
||||||
offset []int
|
|
||||||
shader *Shader
|
|
||||||
}
|
|
||||||
|
|
||||||
const vertexArrayMinCap = 4
|
|
||||||
|
|
||||||
func newVertexArray(shader *Shader, cap int) *vertexArray {
|
|
||||||
if cap < vertexArrayMinCap {
|
|
||||||
cap = vertexArrayMinCap
|
|
||||||
}
|
|
||||||
|
|
||||||
va := &vertexArray{
|
|
||||||
vao: binder{
|
|
||||||
restoreLoc: gl.VERTEX_ARRAY_BINDING,
|
|
||||||
bindFunc: func(obj uint32) {
|
|
||||||
gl.BindVertexArray(obj)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
vbo: binder{
|
|
||||||
restoreLoc: gl.ARRAY_BUFFER_BINDING,
|
|
||||||
bindFunc: func(obj uint32) {
|
|
||||||
gl.BindBuffer(gl.ARRAY_BUFFER, obj)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
cap: cap,
|
|
||||||
format: shader.VertexFormat(),
|
|
||||||
stride: shader.VertexFormat().Size(),
|
|
||||||
offset: make([]int, len(shader.VertexFormat())),
|
|
||||||
shader: shader,
|
|
||||||
}
|
|
||||||
|
|
||||||
offset := 0
|
|
||||||
for i, attr := range va.format {
|
|
||||||
switch attr.Type {
|
|
||||||
case Float, Vec2, Vec3, Vec4:
|
|
||||||
default:
|
|
||||||
panic(errors.New("failed to create vertex array: invalid attribute type"))
|
|
||||||
}
|
|
||||||
va.offset[i] = offset
|
|
||||||
offset += attr.Type.Size()
|
|
||||||
}
|
|
||||||
|
|
||||||
gl.GenVertexArrays(1, &va.vao.obj)
|
|
||||||
|
|
||||||
va.vao.bind()
|
|
||||||
|
|
||||||
gl.GenBuffers(1, &va.vbo.obj)
|
|
||||||
defer va.vbo.bind().restore()
|
|
||||||
|
|
||||||
emptyData := make([]byte, cap*va.stride)
|
|
||||||
gl.BufferData(gl.ARRAY_BUFFER, len(emptyData), gl.Ptr(emptyData), gl.DYNAMIC_DRAW)
|
|
||||||
|
|
||||||
for i, attr := range va.format {
|
|
||||||
loc := gl.GetAttribLocation(shader.program.obj, gl.Str(attr.Name+"\x00"))
|
|
||||||
|
|
||||||
var size int32
|
|
||||||
switch attr.Type {
|
|
||||||
case Float:
|
|
||||||
size = 1
|
|
||||||
case Vec2:
|
|
||||||
size = 2
|
|
||||||
case Vec3:
|
|
||||||
size = 3
|
|
||||||
case Vec4:
|
|
||||||
size = 4
|
|
||||||
}
|
|
||||||
|
|
||||||
gl.VertexAttribPointer(
|
|
||||||
uint32(loc),
|
|
||||||
size,
|
|
||||||
gl.FLOAT,
|
|
||||||
false,
|
|
||||||
int32(va.stride),
|
|
||||||
gl.PtrOffset(va.offset[i]),
|
|
||||||
)
|
|
||||||
gl.EnableVertexAttribArray(uint32(loc))
|
|
||||||
}
|
|
||||||
|
|
||||||
va.vao.restore()
|
|
||||||
|
|
||||||
runtime.SetFinalizer(va, (*vertexArray).delete)
|
|
||||||
|
|
||||||
return va
|
|
||||||
}
|
|
||||||
|
|
||||||
func (va *vertexArray) delete() {
|
|
||||||
mainthread.CallNonBlock(func() {
|
|
||||||
gl.DeleteVertexArrays(1, &va.vao.obj)
|
|
||||||
gl.DeleteBuffers(1, &va.vbo.obj)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (va *vertexArray) begin() {
|
|
||||||
va.vao.bind()
|
|
||||||
va.vbo.bind()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (va *vertexArray) end() {
|
|
||||||
va.vbo.restore()
|
|
||||||
va.vao.restore()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (va *vertexArray) draw(i, j int) {
|
|
||||||
gl.DrawArrays(gl.TRIANGLES, int32(i), int32(i+j))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (va *vertexArray) setVertexData(i, j int, data []float32) {
|
|
||||||
if j-i == 0 {
|
|
||||||
// avoid setting 0 bytes of buffer data
|
|
||||||
return
|
|
||||||
}
|
|
||||||
gl.BufferSubData(gl.ARRAY_BUFFER, i*va.stride, len(data)*4, gl.Ptr(data))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (va *vertexArray) vertexData(i, j int) []float32 {
|
|
||||||
if j-i == 0 {
|
|
||||||
// avoid getting 0 bytes of buffer data
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
data := make([]float32, (j-i)*va.stride/4)
|
|
||||||
gl.GetBufferSubData(gl.ARRAY_BUFFER, i*va.stride, len(data)*4, gl.Ptr(data))
|
|
||||||
return data
|
|
||||||
}
|
|
26
window.go
26
window.go
|
@ -5,8 +5,8 @@ import (
|
||||||
|
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/faiface/glhf"
|
||||||
"github.com/faiface/mainthread"
|
"github.com/faiface/mainthread"
|
||||||
"github.com/faiface/pixel/pixelgl"
|
|
||||||
"github.com/go-gl/glfw/v3.2/glfw"
|
"github.com/go-gl/glfw/v3.2/glfw"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
@ -56,12 +56,12 @@ 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 {
|
||||||
window *glfw.Window
|
window *glfw.Window
|
||||||
config WindowConfig
|
config WindowConfig
|
||||||
|
|
||||||
canvas *Canvas
|
canvas *Canvas
|
||||||
canvasVs *pixelgl.VertexSlice
|
canvasVs *glhf.VertexSlice
|
||||||
shader *pixelgl.Shader
|
shader *glhf.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 {
|
||||||
|
@ -121,7 +121,7 @@ func NewWindow(config WindowConfig) (*Window, error) {
|
||||||
w.begin()
|
w.begin()
|
||||||
w.end()
|
w.end()
|
||||||
|
|
||||||
w.shader, err = pixelgl.NewShader(
|
w.shader, err = glhf.NewShader(
|
||||||
windowVertexFormat,
|
windowVertexFormat,
|
||||||
windowUniformFormat,
|
windowUniformFormat,
|
||||||
windowVertexShader,
|
windowVertexShader,
|
||||||
|
@ -131,7 +131,7 @@ func NewWindow(config WindowConfig) (*Window, error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
w.canvasVs = pixelgl.MakeVertexSlice(w.shader, 6, 6)
|
w.canvasVs = glhf.MakeVertexSlice(w.shader, 6, 6)
|
||||||
w.canvasVs.Begin()
|
w.canvasVs.Begin()
|
||||||
w.canvasVs.SetVertexData([]float32{
|
w.canvasVs.SetVertexData([]float32{
|
||||||
-1, -1, 0, 0,
|
-1, -1, 0, 0,
|
||||||
|
@ -179,7 +179,7 @@ func (w *Window) Update() {
|
||||||
mainthread.Call(func() {
|
mainthread.Call(func() {
|
||||||
w.begin()
|
w.begin()
|
||||||
|
|
||||||
pixelgl.Clear(0, 0, 0, 0)
|
glhf.Clear(0, 0, 0, 0)
|
||||||
w.shader.Begin()
|
w.shader.Begin()
|
||||||
w.canvas.f.Texture().Begin()
|
w.canvas.f.Texture().Begin()
|
||||||
w.canvasVs.Begin()
|
w.canvasVs.Begin()
|
||||||
|
@ -354,7 +354,7 @@ func (w *Window) Restore() {
|
||||||
func (w *Window) begin() {
|
func (w *Window) begin() {
|
||||||
if currentWindow != w {
|
if currentWindow != w {
|
||||||
w.window.MakeContextCurrent()
|
w.window.MakeContextCurrent()
|
||||||
pixelgl.Init()
|
glhf.Init()
|
||||||
currentWindow = w
|
currentWindow = w
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -394,12 +394,12 @@ const (
|
||||||
windowTextureVec2
|
windowTextureVec2
|
||||||
)
|
)
|
||||||
|
|
||||||
var windowVertexFormat = pixelgl.AttrFormat{
|
var windowVertexFormat = glhf.AttrFormat{
|
||||||
windowPositionVec2: {Name: "position", Type: pixelgl.Vec2},
|
windowPositionVec2: {Name: "position", Type: glhf.Vec2},
|
||||||
windowTextureVec2: {Name: "texture", Type: pixelgl.Vec2},
|
windowTextureVec2: {Name: "texture", Type: glhf.Vec2},
|
||||||
}
|
}
|
||||||
|
|
||||||
var windowUniformFormat = pixelgl.AttrFormat{}
|
var windowUniformFormat = glhf.AttrFormat{}
|
||||||
|
|
||||||
var windowVertexShader = `
|
var windowVertexShader = `
|
||||||
#version 330 core
|
#version 330 core
|
||||||
|
|
Loading…
Reference in New Issue