adoprt universal AttrFormat
This commit is contained in:
parent
4ae2d2c7ad
commit
2aaab88e07
|
@ -191,7 +191,7 @@ func NewSprite(parent pixelgl.Doer, picture Picture) *Sprite {
|
|||
parent.Do(func(ctx pixelgl.Context) {
|
||||
var err error
|
||||
va, err = pixelgl.NewVertexArray(
|
||||
picture.Texture(),
|
||||
pixelgl.ContextHolder{Context: ctx},
|
||||
ctx.Shader().VertexFormat(),
|
||||
pixelgl.DynamicUsage,
|
||||
4,
|
||||
|
@ -232,7 +232,7 @@ func NewLineColor(parent pixelgl.Doer, c color.Color, a, b Vec, width float64) *
|
|||
parent.Do(func(ctx pixelgl.Context) {
|
||||
var err error
|
||||
va, err = pixelgl.NewVertexArray(
|
||||
parent,
|
||||
pixelgl.ContextHolder{Context: ctx},
|
||||
ctx.Shader().VertexFormat(),
|
||||
pixelgl.DynamicUsage,
|
||||
4,
|
||||
|
@ -313,7 +313,7 @@ func NewPolygonColor(parent pixelgl.Doer, c color.Color, points ...Vec) *Polygon
|
|||
parent.Do(func(ctx pixelgl.Context) {
|
||||
var err error
|
||||
va, err = pixelgl.NewVertexArray(
|
||||
parent,
|
||||
pixelgl.ContextHolder{Context: ctx},
|
||||
ctx.Shader().VertexFormat(),
|
||||
pixelgl.DynamicUsage,
|
||||
len(points),
|
||||
|
@ -377,7 +377,7 @@ func NewEllipseColor(parent pixelgl.Doer, c color.Color, radius Vec, fill float6
|
|||
parent.Do(func(ctx pixelgl.Context) {
|
||||
var err error
|
||||
va, err = pixelgl.NewVertexArray(
|
||||
parent,
|
||||
pixelgl.ContextHolder{Context: ctx},
|
||||
ctx.Shader().VertexFormat(),
|
||||
pixelgl.DynamicUsage,
|
||||
(n+1)*2,
|
||||
|
|
|
@ -1,29 +1,41 @@
|
|||
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 map[string]AttrType
|
||||
|
||||
// Contains checks whether a format contains a specific attribute.
|
||||
//
|
||||
// It does a little more than a hard check: e.g. if you query a Vec2 attribute, but the format contains Vec3,
|
||||
// Contains returns true, because Vec2 is assignable to Vec3. Specifically, Float -> Vec2 -> Vec3 -> Vec4 (transitively).
|
||||
// This however does not work for matrices or ints.
|
||||
func (af AttrFormat) Contains(attr Attr) bool {
|
||||
if typ, ok := af[attr.Name]; ok {
|
||||
if (Float <= typ && typ <= Vec4) && (Float <= attr.Type && attr.Type <= typ) {
|
||||
return true
|
||||
}
|
||||
return attr.Type == typ
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Size returns the total size of all attributes of an attribute format.
|
||||
func (af AttrFormat) Size() int {
|
||||
total := 0
|
||||
for _, typ := range af {
|
||||
total += typ.Size()
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
// Attr represents an arbitrary OpenGL attribute, such as a vertex attribute or a shader uniform attribute.
|
||||
type Attr struct {
|
||||
Purpose AttrPurpose
|
||||
Type AttrType
|
||||
Name string
|
||||
Type AttrType
|
||||
}
|
||||
|
||||
// AttrPurpose specified a purpose of an attribute. Feel free to create your own purposes for your own needs.
|
||||
type AttrPurpose int
|
||||
|
||||
const (
|
||||
// Position of a vertex
|
||||
Position AttrPurpose = iota
|
||||
// Color of a vertex
|
||||
Color
|
||||
// TexCoord are texture coordinates
|
||||
TexCoord
|
||||
// Transform is an object transformation matrix
|
||||
Transform
|
||||
// MaskColor is a masking color. When drawing, each color gets multiplied by this color.
|
||||
MaskColor
|
||||
// NumStandardAttrPurposes is the number of standard attribute purposes
|
||||
NumStandardAttrPurposes
|
||||
)
|
||||
|
||||
// AttrType represents the type of an OpenGL attribute.
|
||||
type AttrType int
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ type ContextHolder struct {
|
|||
}
|
||||
|
||||
// Do calls sub and passes it the held context.
|
||||
func (ch *ContextHolder) Do(sub func(ctx Context)) {
|
||||
func (ch ContextHolder) Do(sub func(ctx Context)) {
|
||||
sub(ch.Context)
|
||||
}
|
||||
|
||||
|
|
|
@ -7,26 +7,19 @@ import (
|
|||
"github.com/go-gl/mathgl/mgl32"
|
||||
)
|
||||
|
||||
// UniformFormat defines names, purposes and types of uniform variables inside a shader.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// UniformFormat{"transform": {Transform, Mat3}, "camera": {Camera, Mat3}}
|
||||
type UniformFormat map[string]Attr
|
||||
|
||||
// Shader is an OpenGL shader program.
|
||||
type Shader struct {
|
||||
parent Doer
|
||||
program binder
|
||||
vertexFormat VertexFormat
|
||||
uniformFormat UniformFormat
|
||||
uniforms map[Attr]int32
|
||||
parent Doer
|
||||
program binder
|
||||
vertexFmt AttrFormat
|
||||
uniformFmt AttrFormat
|
||||
uniforms map[string]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(parent Doer, vertexFormat VertexFormat, uniformFormat UniformFormat, vertexShader, fragmentShader string) (*Shader, error) {
|
||||
func NewShader(parent Doer, vertexFmt, uniformFmt AttrFormat, vertexShader, fragmentShader string) (*Shader, error) {
|
||||
shader := &Shader{
|
||||
parent: parent,
|
||||
program: binder{
|
||||
|
@ -35,9 +28,9 @@ func NewShader(parent Doer, vertexFormat VertexFormat, uniformFormat UniformForm
|
|||
gl.UseProgram(obj)
|
||||
},
|
||||
},
|
||||
vertexFormat: vertexFormat,
|
||||
uniformFormat: uniformFormat,
|
||||
uniforms: make(map[Attr]int32),
|
||||
vertexFmt: vertexFmt,
|
||||
uniformFmt: uniformFmt,
|
||||
uniforms: make(map[string]int32),
|
||||
}
|
||||
|
||||
var err error
|
||||
|
@ -108,17 +101,9 @@ func NewShader(parent Doer, vertexFormat VertexFormat, uniformFormat UniformForm
|
|||
}
|
||||
|
||||
// uniforms
|
||||
for uname, utype := range uniformFormat {
|
||||
ulocation := gl.GetUniformLocation(shader.program.obj, gl.Str(uname+"\x00"))
|
||||
if ulocation == -1 {
|
||||
gl.DeleteProgram(shader.program.obj)
|
||||
return fmt.Errorf("shader does not contain uniform '%s'", uname)
|
||||
}
|
||||
if _, ok := shader.uniforms[utype]; ok {
|
||||
gl.DeleteProgram(shader.program.obj)
|
||||
return fmt.Errorf("failed to create shader: invalid uniform format: duplicate uniform attribute")
|
||||
}
|
||||
shader.uniforms[utype] = ulocation
|
||||
for name := range uniformFmt {
|
||||
loc := gl.GetUniformLocation(shader.program.obj, gl.Str(name+"\x00"))
|
||||
shader.uniforms[name] = loc
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -146,13 +131,13 @@ func (s *Shader) ID() uint32 {
|
|||
}
|
||||
|
||||
// VertexFormat returns the vertex attribute format of this shader. Do not change it.
|
||||
func (s *Shader) VertexFormat() VertexFormat {
|
||||
return s.vertexFormat
|
||||
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() UniformFormat {
|
||||
return s.uniformFormat
|
||||
func (s *Shader) UniformFormat() AttrFormat {
|
||||
return s.uniformFmt
|
||||
}
|
||||
|
||||
// SetUniformAttr sets the value of a uniform attribute of a shader.
|
||||
|
@ -176,7 +161,7 @@ func (s *Shader) UniformFormat() UniformFormat {
|
|||
// Attr{Type: Mat43}: mgl32.Mat4x3
|
||||
// No other types are supported.
|
||||
func (s *Shader) SetUniformAttr(attr Attr, value interface{}) (ok bool) {
|
||||
if _, ok := s.uniforms[attr]; !ok {
|
||||
if !s.uniformFmt.Contains(attr) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -186,46 +171,46 @@ func (s *Shader) SetUniformAttr(attr Attr, value interface{}) (ok bool) {
|
|||
switch attr.Type {
|
||||
case Int:
|
||||
value := value.(int32)
|
||||
gl.Uniform1iv(s.uniforms[attr], 1, &value)
|
||||
gl.Uniform1iv(s.uniforms[attr.Name], 1, &value)
|
||||
case Float:
|
||||
value := value.(float32)
|
||||
gl.Uniform1fv(s.uniforms[attr], 1, &value)
|
||||
gl.Uniform1fv(s.uniforms[attr.Name], 1, &value)
|
||||
case Vec2:
|
||||
value := value.(mgl32.Vec2)
|
||||
gl.Uniform2fv(s.uniforms[attr], 1, &value[0])
|
||||
gl.Uniform2fv(s.uniforms[attr.Name], 1, &value[0])
|
||||
case Vec3:
|
||||
value := value.(mgl32.Vec3)
|
||||
gl.Uniform3fv(s.uniforms[attr], 1, &value[0])
|
||||
gl.Uniform3fv(s.uniforms[attr.Name], 1, &value[0])
|
||||
case Vec4:
|
||||
value := value.(mgl32.Vec4)
|
||||
gl.Uniform4fv(s.uniforms[attr], 1, &value[0])
|
||||
gl.Uniform4fv(s.uniforms[attr.Name], 1, &value[0])
|
||||
case Mat2:
|
||||
value := value.(mgl32.Mat2)
|
||||
gl.UniformMatrix2fv(s.uniforms[attr], 1, false, &value[0])
|
||||
gl.UniformMatrix2fv(s.uniforms[attr.Name], 1, false, &value[0])
|
||||
case Mat23:
|
||||
value := value.(mgl32.Mat2x3)
|
||||
gl.UniformMatrix2x3fv(s.uniforms[attr], 1, false, &value[0])
|
||||
gl.UniformMatrix2x3fv(s.uniforms[attr.Name], 1, false, &value[0])
|
||||
case Mat24:
|
||||
value := value.(mgl32.Mat2x4)
|
||||
gl.UniformMatrix2x4fv(s.uniforms[attr], 1, false, &value[0])
|
||||
gl.UniformMatrix2x4fv(s.uniforms[attr.Name], 1, false, &value[0])
|
||||
case Mat3:
|
||||
value := value.(mgl32.Mat3)
|
||||
gl.UniformMatrix3fv(s.uniforms[attr], 1, false, &value[0])
|
||||
gl.UniformMatrix3fv(s.uniforms[attr.Name], 1, false, &value[0])
|
||||
case Mat32:
|
||||
value := value.(mgl32.Mat3x2)
|
||||
gl.UniformMatrix3x2fv(s.uniforms[attr], 1, false, &value[0])
|
||||
gl.UniformMatrix3x2fv(s.uniforms[attr.Name], 1, false, &value[0])
|
||||
case Mat34:
|
||||
value := value.(mgl32.Mat3x4)
|
||||
gl.UniformMatrix3x4fv(s.uniforms[attr], 1, false, &value[0])
|
||||
gl.UniformMatrix3x4fv(s.uniforms[attr.Name], 1, false, &value[0])
|
||||
case Mat4:
|
||||
value := value.(mgl32.Mat4)
|
||||
gl.UniformMatrix4fv(s.uniforms[attr], 1, false, &value[0])
|
||||
gl.UniformMatrix4fv(s.uniforms[attr.Name], 1, false, &value[0])
|
||||
case Mat42:
|
||||
value := value.(mgl32.Mat4x2)
|
||||
gl.UniformMatrix4x2fv(s.uniforms[attr], 1, false, &value[0])
|
||||
gl.UniformMatrix4x2fv(s.uniforms[attr.Name], 1, false, &value[0])
|
||||
case Mat43:
|
||||
value := value.(mgl32.Mat4x3)
|
||||
gl.UniformMatrix4x3fv(s.uniforms[attr], 1, false, &value[0])
|
||||
gl.UniformMatrix4x3fv(s.uniforms[attr.Name], 1, false, &value[0])
|
||||
default:
|
||||
panic("set uniform attr: invalid attribute type")
|
||||
}
|
||||
|
|
|
@ -8,24 +8,6 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// VertexFormat defines a data format in a vertex buffer.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// VertexFormat{"position": {Position, Vec2}, "colr": {Color, Vec4}, "texCoord": {TexCoord, Vec2}}
|
||||
//
|
||||
// Note: vertex array currently doesn't support matrices in vertex format.
|
||||
type VertexFormat []Attr
|
||||
|
||||
// Size calculates the total size of a single vertex in this vertex format (sum of the sizes of all vertex attributes).
|
||||
func (vf VertexFormat) Size() int {
|
||||
total := 0
|
||||
for _, attr := range vf {
|
||||
total += attr.Type.Size()
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
// VertexUsage specifies how often the vertex array data will be updated.
|
||||
type VertexUsage int
|
||||
|
||||
|
@ -46,17 +28,17 @@ type VertexArray struct {
|
|||
parent Doer
|
||||
vao, vbo, ebo binder
|
||||
vertexNum, indexNum int
|
||||
format VertexFormat
|
||||
format AttrFormat
|
||||
usage VertexUsage
|
||||
stride int
|
||||
attrs map[Attr]int
|
||||
offset map[string]int
|
||||
}
|
||||
|
||||
// NewVertexArray creates a new empty vertex array and wraps another Doer around it.
|
||||
//
|
||||
// You cannot specify vertex attributes in this constructor, only their count. Use SetVertexAttribute* methods to
|
||||
// set the vertex attributes. Use indices to specify how you want to combine vertices into triangles.
|
||||
func NewVertexArray(parent Doer, format VertexFormat, usage VertexUsage, vertexNum int, indices []int) (*VertexArray, error) {
|
||||
func NewVertexArray(parent Doer, format AttrFormat, usage VertexUsage, vertexNum int, indices []int) (*VertexArray, error) {
|
||||
va := &VertexArray{
|
||||
parent: parent,
|
||||
vao: binder{
|
||||
|
@ -81,21 +63,18 @@ func NewVertexArray(parent Doer, format VertexFormat, usage VertexUsage, vertexN
|
|||
format: format,
|
||||
usage: usage,
|
||||
stride: format.Size(),
|
||||
attrs: make(map[Attr]int),
|
||||
offset: make(map[string]int),
|
||||
}
|
||||
|
||||
offset := 0
|
||||
for _, attr := range format {
|
||||
switch attr.Type {
|
||||
for name, typ := range format {
|
||||
switch typ {
|
||||
case Float, Vec2, Vec3, Vec4:
|
||||
default:
|
||||
return nil, errors.New("failed to create vertex array: invalid vertex format: invalid attribute type")
|
||||
}
|
||||
if _, ok := va.attrs[attr]; ok {
|
||||
return nil, errors.New("failed to create vertex array: invalid vertex format: duplicate vertex attribute")
|
||||
}
|
||||
va.attrs[attr] = offset
|
||||
offset += attr.Type.Size()
|
||||
va.offset[name] = offset
|
||||
offset += typ.Size()
|
||||
}
|
||||
|
||||
parent.Do(func(ctx Context) {
|
||||
|
@ -112,10 +91,11 @@ func NewVertexArray(parent Doer, format VertexFormat, usage VertexUsage, vertexN
|
|||
gl.GenBuffers(1, &va.ebo.obj)
|
||||
defer va.ebo.bind().restore()
|
||||
|
||||
offset := 0
|
||||
for i, attr := range format {
|
||||
for name, typ := range format {
|
||||
loc := gl.GetAttribLocation(ctx.Shader().ID(), gl.Str(name+"\x00"))
|
||||
|
||||
var size int32
|
||||
switch attr.Type {
|
||||
switch typ {
|
||||
case Float:
|
||||
size = 1
|
||||
case Vec2:
|
||||
|
@ -127,15 +107,14 @@ func NewVertexArray(parent Doer, format VertexFormat, usage VertexUsage, vertexN
|
|||
}
|
||||
|
||||
gl.VertexAttribPointer(
|
||||
uint32(i),
|
||||
uint32(loc),
|
||||
size,
|
||||
gl.FLOAT,
|
||||
false,
|
||||
int32(va.stride),
|
||||
gl.PtrOffset(offset),
|
||||
gl.PtrOffset(va.offset[name]),
|
||||
)
|
||||
gl.EnableVertexAttribArray(uint32(i))
|
||||
offset += attr.Type.Size()
|
||||
gl.EnableVertexAttribArray(uint32(loc))
|
||||
}
|
||||
|
||||
va.vao.restore()
|
||||
|
@ -153,6 +132,7 @@ func (va *VertexArray) Delete() {
|
|||
DoNoBlock(func() {
|
||||
gl.DeleteVertexArrays(1, &va.vao.obj)
|
||||
gl.DeleteBuffers(1, &va.vbo.obj)
|
||||
gl.DeleteBuffers(1, &va.ebo.obj)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -170,7 +150,7 @@ func (va *VertexArray) VertexNum() int {
|
|||
// VertexFormat returns the format of the vertices inside a vertex array.
|
||||
//
|
||||
// Do not change this format!
|
||||
func (va *VertexArray) VertexFormat() VertexFormat {
|
||||
func (va *VertexArray) VertexFormat() AttrFormat {
|
||||
return va.format
|
||||
}
|
||||
|
||||
|
@ -219,14 +199,14 @@ func (va *VertexArray) SetVertexAttr(vertex int, attr Attr, value interface{}) (
|
|||
panic("set vertex attr: invalid vertex index")
|
||||
}
|
||||
|
||||
if _, ok := va.attrs[attr]; !ok {
|
||||
if !va.format.Contains(attr) {
|
||||
return false
|
||||
}
|
||||
|
||||
DoNoBlock(func() {
|
||||
va.vbo.bind()
|
||||
|
||||
offset := va.stride*vertex + va.attrs[attr]
|
||||
offset := va.stride*vertex + va.offset[attr.Name]
|
||||
|
||||
switch attr.Type {
|
||||
case Float:
|
||||
|
@ -262,14 +242,14 @@ func (va *VertexArray) VertexAttr(vertex int, attr Attr) (value interface{}, ok
|
|||
panic("vertex attr: invalid vertex index")
|
||||
}
|
||||
|
||||
if _, ok := va.attrs[attr]; !ok {
|
||||
if !va.format.Contains(attr) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
Do(func() {
|
||||
va.vbo.bind()
|
||||
|
||||
offset := va.stride*vertex + va.attrs[attr]
|
||||
offset := va.stride*vertex + va.offset[attr.Name]
|
||||
|
||||
switch attr.Type {
|
||||
case Float:
|
||||
|
|
40
window.go
40
window.go
|
@ -337,23 +337,23 @@ func (w *Window) Do(sub func(pixelgl.Context)) {
|
|||
w.enabled = false
|
||||
}
|
||||
|
||||
var defaultVertexFormat = pixelgl.VertexFormat{
|
||||
{Purpose: pixelgl.Position, Type: pixelgl.Vec2},
|
||||
{Purpose: pixelgl.Color, Type: pixelgl.Vec4},
|
||||
{Purpose: pixelgl.TexCoord, Type: pixelgl.Vec2},
|
||||
var defaultVertexFormat = pixelgl.AttrFormat{
|
||||
"position": pixelgl.Vec2,
|
||||
"color": pixelgl.Vec4,
|
||||
"texCoord": pixelgl.Vec2,
|
||||
}
|
||||
|
||||
var defaultUniformFormat = pixelgl.UniformFormat{
|
||||
"maskColor": {Purpose: pixelgl.MaskColor, Type: pixelgl.Vec4},
|
||||
"transform": {Purpose: pixelgl.Transform, Type: pixelgl.Mat3},
|
||||
var defaultUniformFormat = pixelgl.AttrFormat{
|
||||
"maskColor": pixelgl.Vec4,
|
||||
"transform": pixelgl.Mat3,
|
||||
}
|
||||
|
||||
var defaultVertexShader = `
|
||||
#version 330 core
|
||||
|
||||
layout (location = 0) in vec2 position;
|
||||
layout (location = 1) in vec4 color;
|
||||
layout (location = 2) in vec2 texCoord;
|
||||
in vec2 position;
|
||||
in vec4 color;
|
||||
in vec2 texCoord;
|
||||
|
||||
out vec4 Color;
|
||||
out vec2 TexCoord;
|
||||
|
@ -389,23 +389,23 @@ void main() {
|
|||
|
||||
var (
|
||||
positionVec2 = pixelgl.Attr{
|
||||
Purpose: pixelgl.Position,
|
||||
Type: pixelgl.Vec2,
|
||||
Name: "position",
|
||||
Type: pixelgl.Vec2,
|
||||
}
|
||||
colorVec4 = pixelgl.Attr{
|
||||
Purpose: pixelgl.Color,
|
||||
Type: pixelgl.Vec4,
|
||||
Name: "color",
|
||||
Type: pixelgl.Vec4,
|
||||
}
|
||||
texCoordVec2 = pixelgl.Attr{
|
||||
Purpose: pixelgl.TexCoord,
|
||||
Type: pixelgl.Vec2,
|
||||
Name: "texCoord",
|
||||
Type: pixelgl.Vec2,
|
||||
}
|
||||
maskColorVec4 = pixelgl.Attr{
|
||||
Purpose: pixelgl.MaskColor,
|
||||
Type: pixelgl.Vec4,
|
||||
Name: "maskColor",
|
||||
Type: pixelgl.Vec4,
|
||||
}
|
||||
transformMat3 = pixelgl.Attr{
|
||||
Purpose: pixelgl.Transform,
|
||||
Type: pixelgl.Mat3,
|
||||
Name: "transform",
|
||||
Type: pixelgl.Mat3,
|
||||
}
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue