graphics: Compiled (but can't run yet)

This commit is contained in:
Hajime Hoshi 2016-02-19 03:06:23 +09:00
parent 5c61284c84
commit 93450b1664

View File

@ -17,85 +17,91 @@
package opengl package opengl
import ( import (
"bytes"
"encoding/binary"
"errors" "errors"
"fmt" "fmt"
"github.com/go-gl/gl/v2.1/gl" mgl "golang.org/x/mobile/gl"
) )
type Texture uint32 type Texture mgl.Texture
type Framebuffer uint32 type Framebuffer mgl.Framebuffer
type Shader uint32 type Shader mgl.Shader
type Program uint32 type Program mgl.Program
type Buffer uint32 type Buffer mgl.Texture
var ZeroFramebuffer Framebuffer = 0 var ZeroFramebuffer Framebuffer
// TODO: Remove this after the GopherJS bug was fixed (#159) // TODO: Remove this after the GopherJS bug was fixed (#159)
func (p Program) Equals(other Program) bool { func (p Program) Equals(other Program) bool {
return p == other return p == other
} }
type UniformLocation int32 type UniformLocation mgl.Uniform
type AttribLocation int32 type AttribLocation mgl.Attrib
type ProgramID int type ProgramID uint32
func GetProgramID(p Program) ProgramID { func GetProgramID(p Program) ProgramID {
return ProgramID(p) return ProgramID(p.Value)
} }
type context struct{} type context struct{}
func NewContext() *Context { func NewContext() *Context {
c := &Context{ c := &Context{
Nearest: gl.NEAREST, Nearest: mgl.NEAREST,
Linear: gl.LINEAR, Linear: mgl.LINEAR,
VertexShader: gl.VERTEX_SHADER, VertexShader: mgl.VERTEX_SHADER,
FragmentShader: gl.FRAGMENT_SHADER, FragmentShader: mgl.FRAGMENT_SHADER,
ArrayBuffer: gl.ARRAY_BUFFER, ArrayBuffer: mgl.ARRAY_BUFFER,
ElementArrayBuffer: gl.ELEMENT_ARRAY_BUFFER, ElementArrayBuffer: mgl.ELEMENT_ARRAY_BUFFER,
DynamicDraw: gl.DYNAMIC_DRAW, DynamicDraw: mgl.DYNAMIC_DRAW,
StaticDraw: gl.STATIC_DRAW, StaticDraw: mgl.STATIC_DRAW,
Triangles: gl.TRIANGLES, Triangles: mgl.TRIANGLES,
Lines: gl.LINES, Lines: mgl.LINES,
} }
c.init() c.init()
return c return c
} }
var (
gl mgl.Context
worker mgl.Worker
)
// TODO: Implement updating Worker
func (c *Context) init() { func (c *Context) init() {
if err := gl.Init(); err != nil { gl, worker = mgl.NewContext()
panic(err)
}
// Textures' pixel formats are alpha premultiplied. // Textures' pixel formats are alpha premultiplied.
gl.Enable(gl.BLEND) gl.Enable(mgl.BLEND)
gl.BlendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA) gl.BlendFunc(mgl.ONE, mgl.ONE_MINUS_SRC_ALPHA)
} }
func (c *Context) Check() { func (c *Context) Check() {
if e := gl.GetError(); e != gl.NO_ERROR { if e := gl.GetError(); e != mgl.NO_ERROR {
panic(fmt.Sprintf("check failed: %d", e)) panic(fmt.Sprintf("check failed: %d", e))
} }
} }
func (c *Context) NewTexture(width, height int, pixels []uint8, filter Filter) (Texture, error) { func (c *Context) NewTexture(width, height int, pixels []uint8, filter Filter) (Texture, error) {
var t uint32 t := gl.CreateTexture()
gl.GenTextures(1, &t) if t.Value < 0 {
if t < 0 { return Texture{}, errors.New("graphics: glGenTexture failed")
return 0, errors.New("glGenTexture failed")
} }
gl.PixelStorei(gl.UNPACK_ALIGNMENT, 4) gl.PixelStorei(mgl.UNPACK_ALIGNMENT, 4)
gl.BindTexture(gl.TEXTURE_2D, t) gl.BindTexture(mgl.TEXTURE_2D, t)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, int32(filter)) gl.TexParameteri(mgl.TEXTURE_2D, mgl.TEXTURE_MAG_FILTER, int(filter))
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, int32(filter)) gl.TexParameteri(mgl.TEXTURE_2D, mgl.TEXTURE_MIN_FILTER, int(filter))
var p interface{} var p []uint8
if pixels != nil { if pixels != nil {
p = pixels p = pixels
} }
gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, int32(width), int32(height), 0, gl.RGBA, gl.UNSIGNED_BYTE, gl.Ptr(p)) gl.TexImage2D(mgl.TEXTURE_2D, 0, width, height, mgl.RGBA, mgl.UNSIGNED_BYTE, p)
return Texture(t), nil return Texture(t), nil
} }
@ -103,44 +109,42 @@ func (c *Context) NewTexture(width, height int, pixels []uint8, filter Filter) (
func (c *Context) FramebufferPixels(f Framebuffer, width, height int) ([]uint8, error) { func (c *Context) FramebufferPixels(f Framebuffer, width, height int) ([]uint8, error) {
gl.Flush() gl.Flush()
gl.BindFramebuffer(gl.FRAMEBUFFER, uint32(f)) gl.BindFramebuffer(mgl.FRAMEBUFFER, mgl.Framebuffer(f))
pixels := make([]uint8, 4*width*height) pixels := make([]uint8, 4*width*height)
gl.ReadPixels(0, 0, int32(width), int32(height), gl.RGBA, gl.UNSIGNED_BYTE, gl.Ptr(pixels)) gl.ReadPixels(pixels, 0, 0, width, height, mgl.RGBA, mgl.UNSIGNED_BYTE)
if e := gl.GetError(); e != gl.NO_ERROR { if e := gl.GetError(); e != mgl.NO_ERROR {
return nil, errors.New(fmt.Sprintf("glReadPixels: %d", e)) return nil, errors.New(fmt.Sprintf("graphics: glReadPixels: %d", e))
} }
return pixels, nil return pixels, nil
} }
func (c *Context) BindTexture(t Texture) { func (c *Context) BindTexture(t Texture) {
gl.BindTexture(gl.TEXTURE_2D, uint32(t)) gl.BindTexture(mgl.TEXTURE_2D, mgl.Texture(t))
} }
func (c *Context) DeleteTexture(t Texture) { func (c *Context) DeleteTexture(t Texture) {
tt := uint32(t) gl.DeleteTexture(mgl.Texture(t))
gl.DeleteTextures(1, &tt)
} }
func (c *Context) TexSubImage2D(p []uint8, width, height int) { func (c *Context) TexSubImage2D(p []uint8, width, height int) {
gl.TexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, int32(width), int32(height), gl.RGBA, gl.UNSIGNED_BYTE, gl.Ptr(p)) gl.TexSubImage2D(mgl.TEXTURE_2D, 0, 0, 0, width, height, mgl.RGBA, mgl.UNSIGNED_BYTE, p)
} }
func (c *Context) NewFramebuffer(texture Texture) (Framebuffer, error) { func (c *Context) NewFramebuffer(texture Texture) (Framebuffer, error) {
var f uint32 f := gl.CreateFramebuffer()
gl.GenFramebuffers(1, &f) gl.BindFramebuffer(mgl.FRAMEBUFFER, f)
gl.BindFramebuffer(gl.FRAMEBUFFER, f)
gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, uint32(texture), 0) gl.FramebufferTexture2D(mgl.FRAMEBUFFER, mgl.COLOR_ATTACHMENT0, mgl.TEXTURE_2D, mgl.Texture(texture), 0)
s := gl.CheckFramebufferStatus(gl.FRAMEBUFFER) s := gl.CheckFramebufferStatus(mgl.FRAMEBUFFER)
if s != gl.FRAMEBUFFER_COMPLETE { if s != mgl.FRAMEBUFFER_COMPLETE {
if s != 0 { if s != 0 {
return 0, errors.New(fmt.Sprintf("creating framebuffer failed: %d", s)) return Framebuffer{}, errors.New(fmt.Sprintf("graphics: creating framebuffer failed: %v", s))
} }
if e := gl.GetError(); e != gl.NO_ERROR { if e := gl.GetError(); e != mgl.NO_ERROR {
return 0, errors.New(fmt.Sprintf("creating framebuffer failed: (glGetError) %d", e)) return Framebuffer{}, errors.New(fmt.Sprintf("graphics: creating framebuffer failed: (glGetError) %d", e))
} }
return 0, errors.New(fmt.Sprintf("creating framebuffer failed: unknown error")) return Framebuffer{}, errors.New(fmt.Sprintf("graphics: creating framebuffer failed: unknown error"))
} }
return Framebuffer(f), nil return Framebuffer(f), nil
@ -148,54 +152,45 @@ func (c *Context) NewFramebuffer(texture Texture) (Framebuffer, error) {
func (c *Context) SetViewport(f Framebuffer, width, height int) error { func (c *Context) SetViewport(f Framebuffer, width, height int) error {
gl.Flush() gl.Flush()
gl.BindFramebuffer(gl.FRAMEBUFFER, uint32(f)) gl.BindFramebuffer(mgl.FRAMEBUFFER, mgl.Framebuffer(f))
if err := gl.CheckFramebufferStatus(gl.FRAMEBUFFER); err != gl.FRAMEBUFFER_COMPLETE { if err := gl.CheckFramebufferStatus(mgl.FRAMEBUFFER); err != mgl.FRAMEBUFFER_COMPLETE {
if e := gl.GetError(); e != 0 { if e := gl.GetError(); e != 0 {
return errors.New(fmt.Sprintf("glBindFramebuffer failed: %d", e)) return errors.New(fmt.Sprintf("graphics: glBindFramebuffer failed: %d", e))
} }
return errors.New("glBindFramebuffer failed: the context is different?") return errors.New("graphics: glBindFramebuffer failed: the context is different?")
} }
gl.Viewport(0, 0, int32(width), int32(height)) gl.Viewport(0, 0, width, height)
return nil return nil
} }
func (c *Context) FillFramebuffer(r, g, b, a float64) error { func (c *Context) FillFramebuffer(r, g, b, a float64) error {
gl.ClearColor(float32(r), float32(g), float32(b), float32(a)) gl.ClearColor(float32(r), float32(g), float32(b), float32(a))
gl.Clear(gl.COLOR_BUFFER_BIT) gl.Clear(mgl.COLOR_BUFFER_BIT)
return nil return nil
} }
func (c *Context) DeleteFramebuffer(f Framebuffer) { func (c *Context) DeleteFramebuffer(f Framebuffer) {
ff := uint32(f) gl.DeleteFramebuffer(mgl.Framebuffer(f))
gl.DeleteFramebuffers(1, &ff)
} }
func (c *Context) NewShader(shaderType ShaderType, source string) (Shader, error) { func (c *Context) NewShader(shaderType ShaderType, source string) (Shader, error) {
s := gl.CreateShader(uint32(shaderType)) s := gl.CreateShader(mgl.Enum(shaderType))
if s == 0 { if s.Value == 0 {
return 0, errors.New("glCreateShader failed") return Shader{}, errors.New("graphics: glCreateShader failed")
} }
gl.ShaderSource(s, source)
glSource := gl.Str(source + "\x00")
gl.ShaderSource(uint32(s), 1, &glSource, nil)
gl.CompileShader(s) gl.CompileShader(s)
var v int32 v := gl.GetShaderi(s, mgl.COMPILE_STATUS)
gl.GetShaderiv(s, gl.COMPILE_STATUS, &v) if v == mgl.FALSE {
if v == gl.FALSE { log := gl.GetShaderInfoLog(s)
log := []uint8{} return Shader{}, errors.New(fmt.Sprintf("graphics: shader compile failed: %s", log))
gl.GetShaderiv(uint32(s), gl.INFO_LOG_LENGTH, &v)
if v != 0 {
log = make([]uint8, int(v))
gl.GetShaderInfoLog(uint32(s), v, nil, (*uint8)(gl.Ptr(log)))
}
return 0, errors.New(fmt.Sprintf("shader compile failed: %s", string(log)))
} }
return Shader(s), nil return Shader(s), nil
} }
func (c *Context) DeleteShader(s Shader) { func (c *Context) DeleteShader(s Shader) {
gl.DeleteShader(uint32(s)) gl.DeleteShader(mgl.Shader(s))
} }
func (c *Context) GlslHighpSupported() bool { func (c *Context) GlslHighpSupported() bool {
@ -204,104 +199,104 @@ func (c *Context) GlslHighpSupported() bool {
func (c *Context) NewProgram(shaders []Shader) (Program, error) { func (c *Context) NewProgram(shaders []Shader) (Program, error) {
p := gl.CreateProgram() p := gl.CreateProgram()
if p == 0 { if p.Value == 0 {
return 0, errors.New("glCreateProgram failed") return Program{}, errors.New("graphics: glCreateProgram failed")
} }
for _, shader := range shaders { for _, shader := range shaders {
gl.AttachShader(p, uint32(shader)) gl.AttachShader(p, mgl.Shader(shader))
} }
gl.LinkProgram(p) gl.LinkProgram(p)
var v int32 v := gl.GetProgrami(p, mgl.LINK_STATUS)
gl.GetProgramiv(p, gl.LINK_STATUS, &v) if v == mgl.FALSE {
if v == gl.FALSE { return Program{}, errors.New("graphics: program error")
return 0, errors.New("program error")
} }
return Program(p), nil return Program(p), nil
} }
func (c *Context) UseProgram(p Program) { func (c *Context) UseProgram(p Program) {
gl.UseProgram(uint32(p)) gl.UseProgram(mgl.Program(p))
} }
func (c *Context) GetUniformLocation(p Program, location string) UniformLocation { func (c *Context) GetUniformLocation(p Program, location string) UniformLocation {
u := UniformLocation(gl.GetUniformLocation(uint32(p), gl.Str(location+"\x00"))) u := UniformLocation(gl.GetUniformLocation(mgl.Program(p), location))
if u == -1 { if u.Value == -1 {
panic("invalid uniform location: " + location) panic("invalid uniform location: " + location)
} }
return u return u
} }
func (c *Context) UniformInt(p Program, location string, v int) { func (c *Context) UniformInt(p Program, location string, v int) {
l := int32(GetUniformLocation(c, p, location)) gl.Uniform1i(gl.GetUniformLocation(mgl.Program(p), location), v)
gl.Uniform1i(l, int32(v))
} }
func (c *Context) UniformFloats(p Program, location string, v []float32) { func (c *Context) UniformFloats(p Program, location string, v []float32) {
l := int32(GetUniformLocation(c, p, location)) l := gl.GetUniformLocation(mgl.Program(p), location)
switch len(v) { switch len(v) {
case 4: case 4:
gl.Uniform4fv(l, 1, (*float32)(gl.Ptr(v))) gl.Uniform4fv(l, v)
case 16: case 16:
gl.UniformMatrix4fv(l, 1, false, (*float32)(gl.Ptr(v))) gl.UniformMatrix4fv(l, v)
default: default:
panic("not reach") panic("not reach")
} }
} }
func (c *Context) GetAttribLocation(p Program, location string) AttribLocation { func (c *Context) GetAttribLocation(p Program, location string) AttribLocation {
a := AttribLocation(gl.GetAttribLocation(uint32(p), gl.Str(location+"\x00"))) a := AttribLocation(gl.GetAttribLocation(mgl.Program(p), location))
if a == -1 { if a.Value == ^uint(0) {
panic("invalid attrib location: " + location) panic("invalid attrib location: " + location)
} }
return a return a
} }
func (c *Context) VertexAttribPointer(p Program, location string, normalize bool, stride int, size int, v int) { func (c *Context) VertexAttribPointer(p Program, location string, normalize bool, stride int, size int, v int) {
l := GetAttribLocation(c, p, location) l := c.GetAttribLocation(p, location)
gl.VertexAttribPointer(uint32(l), int32(size), gl.SHORT, normalize, int32(stride), gl.PtrOffset(v)) gl.VertexAttribPointer(mgl.Attrib(l), size, mgl.SHORT, normalize, stride, v)
} }
func (c *Context) EnableVertexAttribArray(p Program, location string) { func (c *Context) EnableVertexAttribArray(p Program, location string) {
l := GetAttribLocation(c, p, location) l := c.GetAttribLocation(p, location)
gl.EnableVertexAttribArray(uint32(l)) gl.EnableVertexAttribArray(mgl.Attrib(l))
} }
func (c *Context) DisableVertexAttribArray(p Program, location string) { func (c *Context) DisableVertexAttribArray(p Program, location string) {
l := GetAttribLocation(c, p, location) l := c.GetAttribLocation(p, location)
gl.DisableVertexAttribArray(uint32(l)) gl.DisableVertexAttribArray(mgl.Attrib(l))
} }
func (c *Context) NewBuffer(bufferType BufferType, v interface{}, bufferUsage BufferUsage) Buffer { func (c *Context) NewBuffer(bufferType BufferType, v interface{}, bufferUsage BufferUsage) Buffer {
var b uint32 b := gl.CreateBuffer()
gl.GenBuffers(1, &b) gl.BindBuffer(mgl.Enum(bufferType), b)
gl.BindBuffer(uint32(bufferType), b)
size := 0
ptr := v
switch v := v.(type) { switch v := v.(type) {
case int: case int:
size = v gl.BufferInit(mgl.Enum(bufferType), v, mgl.Enum(bufferUsage))
ptr = nil return Buffer(b)
case []uint16: case []uint16:
size = 2 * len(v)
case []float32: case []float32:
size = 4 * len(v)
default: default:
panic("not reach") panic("not reach")
} }
gl.BufferData(uint32(bufferType), size, gl.Ptr(ptr), uint32(bufferUsage)) bt := &bytes.Buffer{}
if err := binary.Write(bt, binary.LittleEndian, v); err != nil {
panic(fmt.Sprintf("graphics: Binary error: %v", err))
}
gl.BufferData(mgl.Enum(bufferType), bt.Bytes(), mgl.Enum(bufferUsage))
return Buffer(b) return Buffer(b)
} }
func (c *Context) BindElementArrayBuffer(b Buffer) { func (c *Context) BindElementArrayBuffer(b Buffer) {
gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, uint32(b)) gl.BindBuffer(mgl.ELEMENT_ARRAY_BUFFER, mgl.Buffer(b))
} }
func (c *Context) BufferSubData(bufferType BufferType, data []int16) { func (c *Context) BufferSubData(bufferType BufferType, data []int16) {
const int16Size = 2 bt := &bytes.Buffer{}
gl.BufferSubData(uint32(bufferType), 0, int16Size*len(data), gl.Ptr(data)) if err := binary.Write(bt, binary.LittleEndian, data); err != nil {
panic(fmt.Sprintf("graphics: Binary error: %v", err))
}
gl.BufferSubData(mgl.Enum(bufferType), 0, bt.Bytes())
} }
func (c *Context) DrawElements(mode Mode, len int) { func (c *Context) DrawElements(mode Mode, len int) {
gl.DrawElements(uint32(mode), int32(len), gl.UNSIGNED_SHORT, gl.PtrOffset(0)) gl.DrawElements(mgl.Enum(mode), len, mgl.UNSIGNED_SHORT, 0)
} }