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