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 (
|
||||
"image/color"
|
||||
|
||||
"github.com/faiface/glhf"
|
||||
"github.com/faiface/mainthread"
|
||||
"github.com/faiface/pixel/pixelgl"
|
||||
"github.com/go-gl/mathgl/mgl32"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
@ -13,10 +13,10 @@ import (
|
|||
//
|
||||
// Canvas supports TrianglesPosition, TrianglesColor and TrianglesTexture.
|
||||
type Canvas struct {
|
||||
f *pixelgl.Frame
|
||||
s *pixelgl.Shader
|
||||
f *glhf.Frame
|
||||
s *glhf.Shader
|
||||
|
||||
copyVs *pixelgl.VertexSlice
|
||||
copyVs *glhf.VertexSlice
|
||||
smooth bool
|
||||
|
||||
drawTd TrianglesDrawer
|
||||
|
@ -32,8 +32,8 @@ func NewCanvas(width, height float64, smooth bool) *Canvas {
|
|||
c := &Canvas{smooth: smooth}
|
||||
mainthread.Call(func() {
|
||||
var err error
|
||||
c.f = pixelgl.NewFrame(int(width), int(height), smooth)
|
||||
c.s, err = pixelgl.NewShader(
|
||||
c.f = glhf.NewFrame(int(width), int(height), smooth)
|
||||
c.s, err = glhf.NewShader(
|
||||
canvasVertexFormat,
|
||||
canvasUniformFormat,
|
||||
canvasVertexShader,
|
||||
|
@ -43,7 +43,7 @@ func NewCanvas(width, height float64, smooth bool) *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.SetVertexData([]float32{
|
||||
-1, -1, 1, 1, 1, 1, 0, 0,
|
||||
|
@ -79,7 +79,7 @@ func (c *Canvas) SetSize(width, height float64) {
|
|||
}
|
||||
mainthread.Call(func() {
|
||||
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.s.Begin()
|
||||
|
@ -116,7 +116,7 @@ func (c *Canvas) Clear(col color.Color) {
|
|||
mainthread.CallNonBlock(func() {
|
||||
c.f.Begin()
|
||||
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()
|
||||
})
|
||||
}
|
||||
|
@ -209,10 +209,10 @@ const (
|
|||
canvasTextureVec2
|
||||
)
|
||||
|
||||
var canvasVertexFormat = pixelgl.AttrFormat{
|
||||
canvasPositionVec2: {Name: "position", Type: pixelgl.Vec2},
|
||||
canvasColorVec4: {Name: "color", Type: pixelgl.Vec4},
|
||||
canvasTextureVec2: {Name: "texture", Type: pixelgl.Vec2},
|
||||
var canvasVertexFormat = glhf.AttrFormat{
|
||||
canvasPositionVec2: {Name: "position", Type: glhf.Vec2},
|
||||
canvasColorVec4: {Name: "color", Type: glhf.Vec4},
|
||||
canvasTextureVec2: {Name: "texture", Type: glhf.Vec2},
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -221,10 +221,10 @@ const (
|
|||
canvasBoundsVec4
|
||||
)
|
||||
|
||||
var canvasUniformFormat = pixelgl.AttrFormat{
|
||||
{Name: "maskColor", Type: pixelgl.Vec4},
|
||||
{Name: "transform", Type: pixelgl.Mat3},
|
||||
{Name: "bounds", Type: pixelgl.Vec4},
|
||||
var canvasUniformFormat = glhf.AttrFormat{
|
||||
{Name: "maskColor", Type: glhf.Vec4},
|
||||
{Name: "transform", Type: glhf.Mat3},
|
||||
{Name: "bounds", Type: glhf.Vec4},
|
||||
}
|
||||
|
||||
var canvasVertexShader = `
|
||||
|
|
|
@ -3,23 +3,23 @@ package pixel
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/faiface/glhf"
|
||||
"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
|
||||
// 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
|
||||
// uniform attributes.
|
||||
func NewGLTriangles(shader *pixelgl.Shader, t Triangles) TargetTriangles {
|
||||
func NewGLTriangles(shader *glhf.Shader, t Triangles) TargetTriangles {
|
||||
var gt *glTriangles
|
||||
mainthread.Call(func() {
|
||||
gt = &glTriangles{
|
||||
vs: pixelgl.MakeVertexSlice(shader, 0, t.Len()),
|
||||
vs: glhf.MakeVertexSlice(shader, 0, t.Len()),
|
||||
shader: shader,
|
||||
}
|
||||
})
|
||||
|
@ -29,9 +29,9 @@ func NewGLTriangles(shader *pixelgl.Shader, t Triangles) TargetTriangles {
|
|||
}
|
||||
|
||||
type glTriangles struct {
|
||||
vs *pixelgl.VertexSlice
|
||||
vs *glhf.VertexSlice
|
||||
data []float32
|
||||
shader *pixelgl.Shader
|
||||
shader *glhf.Shader
|
||||
}
|
||||
|
||||
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.
|
||||
func (p *Polygon) SetPoints(points ...Vec) {
|
||||
p.data.SetLen(len(points))
|
||||
for i, pt := range points {
|
||||
p.data[i].Position = pt
|
||||
p.data.SetLen(3 * (len(points) - 2))
|
||||
for i := 2; i < len(points); i++ {
|
||||
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.td.Dirty()
|
||||
|
|
12
picture.go
12
picture.go
|
@ -4,8 +4,8 @@ import (
|
|||
"image"
|
||||
"image/draw"
|
||||
|
||||
"github.com/faiface/glhf"
|
||||
"github.com/faiface/mainthread"
|
||||
"github.com/faiface/pixel/pixelgl"
|
||||
)
|
||||
|
||||
// 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"
|
||||
// from a Picture) into smaller Pictures.
|
||||
type Picture struct {
|
||||
tex *pixelgl.Texture
|
||||
tex *glhf.Texture
|
||||
bounds Rect
|
||||
}
|
||||
|
||||
|
@ -35,9 +35,9 @@ func NewPicture(img image.Image, smooth bool) *Picture {
|
|||
copy(jSlice, tmp)
|
||||
}
|
||||
|
||||
var tex *pixelgl.Texture
|
||||
var tex *glhf.Texture
|
||||
mainthread.Call(func() {
|
||||
tex = pixelgl.NewTexture(
|
||||
tex = glhf.NewTexture(
|
||||
img.Bounds().Dx(),
|
||||
img.Bounds().Dy(),
|
||||
smooth,
|
||||
|
@ -49,7 +49,7 @@ func NewPicture(img image.Image, smooth bool) *Picture {
|
|||
}
|
||||
|
||||
// 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{
|
||||
tex: tex,
|
||||
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.
|
||||
func (p *Picture) Texture() *pixelgl.Texture {
|
||||
func (p *Picture) Texture() *glhf.Texture {
|
||||
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"
|
||||
|
||||
"github.com/faiface/glhf"
|
||||
"github.com/faiface/mainthread"
|
||||
"github.com/faiface/pixel/pixelgl"
|
||||
"github.com/go-gl/glfw/v3.2/glfw"
|
||||
"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, ...).
|
||||
type Window struct {
|
||||
window *glfw.Window
|
||||
config WindowConfig
|
||||
window *glfw.Window
|
||||
config WindowConfig
|
||||
|
||||
canvas *Canvas
|
||||
canvasVs *pixelgl.VertexSlice
|
||||
shader *pixelgl.Shader
|
||||
canvasVs *glhf.VertexSlice
|
||||
shader *glhf.Shader
|
||||
|
||||
// need to save these to correctly restore a fullscreen window
|
||||
restore struct {
|
||||
|
@ -121,7 +121,7 @@ func NewWindow(config WindowConfig) (*Window, error) {
|
|||
w.begin()
|
||||
w.end()
|
||||
|
||||
w.shader, err = pixelgl.NewShader(
|
||||
w.shader, err = glhf.NewShader(
|
||||
windowVertexFormat,
|
||||
windowUniformFormat,
|
||||
windowVertexShader,
|
||||
|
@ -131,7 +131,7 @@ func NewWindow(config WindowConfig) (*Window, error) {
|
|||
return err
|
||||
}
|
||||
|
||||
w.canvasVs = pixelgl.MakeVertexSlice(w.shader, 6, 6)
|
||||
w.canvasVs = glhf.MakeVertexSlice(w.shader, 6, 6)
|
||||
w.canvasVs.Begin()
|
||||
w.canvasVs.SetVertexData([]float32{
|
||||
-1, -1, 0, 0,
|
||||
|
@ -179,7 +179,7 @@ func (w *Window) Update() {
|
|||
mainthread.Call(func() {
|
||||
w.begin()
|
||||
|
||||
pixelgl.Clear(0, 0, 0, 0)
|
||||
glhf.Clear(0, 0, 0, 0)
|
||||
w.shader.Begin()
|
||||
w.canvas.f.Texture().Begin()
|
||||
w.canvasVs.Begin()
|
||||
|
@ -354,7 +354,7 @@ func (w *Window) Restore() {
|
|||
func (w *Window) begin() {
|
||||
if currentWindow != w {
|
||||
w.window.MakeContextCurrent()
|
||||
pixelgl.Init()
|
||||
glhf.Init()
|
||||
currentWindow = w
|
||||
}
|
||||
}
|
||||
|
@ -394,12 +394,12 @@ const (
|
|||
windowTextureVec2
|
||||
)
|
||||
|
||||
var windowVertexFormat = pixelgl.AttrFormat{
|
||||
windowPositionVec2: {Name: "position", Type: pixelgl.Vec2},
|
||||
windowTextureVec2: {Name: "texture", Type: pixelgl.Vec2},
|
||||
var windowVertexFormat = glhf.AttrFormat{
|
||||
windowPositionVec2: {Name: "position", Type: glhf.Vec2},
|
||||
windowTextureVec2: {Name: "texture", Type: glhf.Vec2},
|
||||
}
|
||||
|
||||
var windowUniformFormat = pixelgl.AttrFormat{}
|
||||
var windowUniformFormat = glhf.AttrFormat{}
|
||||
|
||||
var windowVertexShader = `
|
||||
#version 330 core
|
||||
|
|
Loading…
Reference in New Issue