From 3300f02d21f86fad18445d2fc58c77528a01f6f7 Mon Sep 17 00:00:00 2001 From: faiface Date: Sat, 11 Feb 2017 14:09:47 +0100 Subject: [PATCH] adopt github.com/faiface/glhf --- canvas.go | 34 +++--- gltriangles.go | 14 +-- graphics.go | 10 +- picture.go | 12 +- pixelgl/attr.go | 80 ------------ pixelgl/doc.go | 8 -- pixelgl/frame.go | 75 ------------ pixelgl/interface.go | 11 -- pixelgl/orphan.go | 24 ---- pixelgl/shader.go | 219 --------------------------------- pixelgl/texture.go | 128 ------------------- pixelgl/util.go | 31 ----- pixelgl/vertex.go | 285 ------------------------------------------- window.go | 26 ++-- 14 files changed, 50 insertions(+), 907 deletions(-) delete mode 100644 pixelgl/attr.go delete mode 100644 pixelgl/doc.go delete mode 100644 pixelgl/frame.go delete mode 100644 pixelgl/interface.go delete mode 100644 pixelgl/orphan.go delete mode 100644 pixelgl/shader.go delete mode 100644 pixelgl/texture.go delete mode 100644 pixelgl/util.go delete mode 100644 pixelgl/vertex.go diff --git a/canvas.go b/canvas.go index c472283..b2860fa 100644 --- a/canvas.go +++ b/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 = ` diff --git a/gltriangles.go b/gltriangles.go index 73654dd..b2648a3 100644 --- a/gltriangles.go +++ b/gltriangles.go @@ -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 { diff --git a/graphics.go b/graphics.go index 85c5a26..ded74b3 100644 --- a/graphics.go +++ b/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() diff --git a/picture.go b/picture.go index db35f28..2a6129a 100644 --- a/picture.go +++ b/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 } diff --git a/pixelgl/attr.go b/pixelgl/attr.go deleted file mode 100644 index 7f78d23..0000000 --- a/pixelgl/attr.go +++ /dev/null @@ -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") - } -} diff --git a/pixelgl/doc.go b/pixelgl/doc.go deleted file mode 100644 index e28bdfb..0000000 --- a/pixelgl/doc.go +++ /dev/null @@ -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 diff --git a/pixelgl/frame.go b/pixelgl/frame.go deleted file mode 100644 index c2ca761..0000000 --- a/pixelgl/frame.go +++ /dev/null @@ -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 -} diff --git a/pixelgl/interface.go b/pixelgl/interface.go deleted file mode 100644 index f651189..0000000 --- a/pixelgl/interface.go +++ /dev/null @@ -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() -} diff --git a/pixelgl/orphan.go b/pixelgl/orphan.go deleted file mode 100644 index eba99bc..0000000 --- a/pixelgl/orphan.go +++ /dev/null @@ -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) -} diff --git a/pixelgl/shader.go b/pixelgl/shader.go deleted file mode 100644 index 81f8218..0000000 --- a/pixelgl/shader.go +++ /dev/null @@ -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() -} diff --git a/pixelgl/texture.go b/pixelgl/texture.go deleted file mode 100644 index eba9fef..0000000 --- a/pixelgl/texture.go +++ /dev/null @@ -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() -} diff --git a/pixelgl/util.go b/pixelgl/util.go deleted file mode 100644 index 4792d55..0000000 --- a/pixelgl/util.go +++ /dev/null @@ -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 -} diff --git a/pixelgl/vertex.go b/pixelgl/vertex.go deleted file mode 100644 index a1d70e1..0000000 --- a/pixelgl/vertex.go +++ /dev/null @@ -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 -} diff --git a/window.go b/window.go index c962602..5600f25 100644 --- a/window.go +++ b/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