|
|
@@ -1,62 +1,62 @@
|
|
|
// Copyright 2016 The G3N Authors. All rights reserved.
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
// license that can be found in the LICENSE file.
|
|
|
-
|
|
|
-// Package gls allows access to the OpenGL functions.
|
|
|
package gls
|
|
|
|
|
|
+// #include <stdlib.h>
|
|
|
+// #include "glcorearb.h"
|
|
|
+// #include "glapi.h"
|
|
|
+import "C"
|
|
|
+
|
|
|
import (
|
|
|
- "github.com/g3n/engine/util/logger"
|
|
|
- "github.com/go-gl/gl/v3.3-core/gl"
|
|
|
+ "fmt"
|
|
|
"math"
|
|
|
+ "reflect"
|
|
|
+ "unsafe"
|
|
|
)
|
|
|
|
|
|
-// GLS allows access to the OpenGL functions and keeps state to
|
|
|
-// minimize functions calling.
|
|
|
-// It also keeps some statistics of some OpenGL objects currently allocated
|
|
|
+// GLS encapsulates the state of an OpenGL context and contains
|
|
|
+// methods to call OpenGL functions.
|
|
|
type GLS struct {
|
|
|
- // Statistics
|
|
|
- Stats struct {
|
|
|
- Vaos int // Number of Vertex Array Objects
|
|
|
- Vbos int // Number of Vertex Buffer Objects
|
|
|
- Textures int // Number of Textures
|
|
|
- }
|
|
|
- Prog *Program // Current active program
|
|
|
- programs map[*Program]bool // Programs cache
|
|
|
- checkErrors bool // Check openGL API errors flag
|
|
|
- viewportX int32
|
|
|
- viewportY int32
|
|
|
- viewportWidth int32
|
|
|
- viewportHeight int32
|
|
|
- lineWidth float32
|
|
|
- sideView int
|
|
|
- depthFunc uint32
|
|
|
- depthMask int
|
|
|
- capabilities map[int]int
|
|
|
- blendEquation uint32
|
|
|
- blendSrc uint32
|
|
|
- blendDst uint32
|
|
|
- blendEquationRGB uint32
|
|
|
- blendEquationAlpha uint32
|
|
|
- blendSrcRGB uint32
|
|
|
- blendSrcAlpha uint32
|
|
|
- blendDstRGB uint32
|
|
|
- blendDstAlpha uint32
|
|
|
- polygonOffsetFactor float32
|
|
|
- polygonOffsetUnits float32
|
|
|
+ stats Stats // statistics
|
|
|
+ Prog *Program // current active program
|
|
|
+ programs map[*Program]bool // programs cache
|
|
|
+ checkErrors bool // check openGL API errors flag
|
|
|
+ viewportX int32 // cached last set viewport x
|
|
|
+ viewportY int32 // cached last set viewport y
|
|
|
+ viewportWidth int32 // cached last set viewport width
|
|
|
+ viewportHeight int32 // cached last set viewport height
|
|
|
+ lineWidth float32 // cached last set line width
|
|
|
+ sideView int // cached last set triangle side view mode
|
|
|
+ depthFunc uint32 // cached last set depth function
|
|
|
+ depthMask int // cached last set depth mask
|
|
|
+ capabilities map[int]int // cached capabilities (Enable/Disable)
|
|
|
+ blendEquation uint32 // cached last set blend equation value
|
|
|
+ blendSrc uint32 // cached last set blend src value
|
|
|
+ blendDst uint32 // cached last set blend equation destination value
|
|
|
+ blendEquationRGB uint32 // cached last set blend equation rgb value
|
|
|
+ blendEquationAlpha uint32 // cached last set blend equation alpha value
|
|
|
+ blendSrcRGB uint32 // cached last set blend src rgb
|
|
|
+ blendSrcAlpha uint32 // cached last set blend src alpha value
|
|
|
+ blendDstRGB uint32 // cached last set blend destination rgb value
|
|
|
+ blendDstAlpha uint32 // cached last set blend destination alpha value
|
|
|
+ polygonOffsetFactor float32 // cached last set polygon offset factor
|
|
|
+ polygonOffsetUnits float32 // cached last set polygon offset units
|
|
|
+ gobuf []byte // conversion buffer with GO memory
|
|
|
+ cbuf []byte // conversion buffer with C memory
|
|
|
+}
|
|
|
+
|
|
|
+// Stats contains counters of OpenGL resources being used as well
|
|
|
+// the cummulative numbers of some OpenGL calls for performance evaluation.
|
|
|
+type Stats struct {
|
|
|
+ Vaos int // Number of Vertex Array Objects
|
|
|
+ Vbos int // Number of Vertex Buffer Objects
|
|
|
+ Textures int // Number of Textures
|
|
|
+ Caphits uint64 // Cummulative number of hits for Enable/Disable
|
|
|
+ Unisets uint64 // Cummulative number of uniform sets
|
|
|
+ Drawcalls uint64 // Cummulative number of draw calls
|
|
|
}
|
|
|
|
|
|
-const (
|
|
|
- capUndef = 0
|
|
|
- capDisabled = 1
|
|
|
- capEnabled = 2
|
|
|
-)
|
|
|
-const (
|
|
|
- uintUndef = math.MaxUint32
|
|
|
- intFalse = 0
|
|
|
- intTrue = 1
|
|
|
-)
|
|
|
-
|
|
|
// Polygon side view.
|
|
|
const (
|
|
|
FrontSide = iota + 1
|
|
|
@@ -64,8 +64,14 @@ const (
|
|
|
DoubleSide
|
|
|
)
|
|
|
|
|
|
-// Package logger
|
|
|
-var log = logger.New("GLS", logger.Default)
|
|
|
+const (
|
|
|
+ capUndef = 0
|
|
|
+ capDisabled = 1
|
|
|
+ capEnabled = 2
|
|
|
+ uintUndef = math.MaxUint32
|
|
|
+ intFalse = 0
|
|
|
+ intTrue = 1
|
|
|
+)
|
|
|
|
|
|
// New creates and returns a new instance of an GLS object
|
|
|
// which encapsulates the state of an OpenGL context
|
|
|
@@ -74,15 +80,21 @@ var log = logger.New("GLS", logger.Default)
|
|
|
func New() (*GLS, error) {
|
|
|
|
|
|
gs := new(GLS)
|
|
|
- gs.Reset()
|
|
|
-
|
|
|
- // Initialize GL
|
|
|
- err := gl.Init()
|
|
|
- if err != nil {
|
|
|
- return nil, err
|
|
|
+ gs.reset()
|
|
|
+ // Load OpenGL functions
|
|
|
+ err := C.glapiLoad()
|
|
|
+ if err != 0 {
|
|
|
+ return nil, fmt.Errorf("Error loading OpenGL")
|
|
|
}
|
|
|
- gs.SetDefaultState()
|
|
|
+ gs.setDefaultState()
|
|
|
gs.checkErrors = true
|
|
|
+
|
|
|
+ // Preallocates conversion buffers
|
|
|
+ size := 1 * 1024
|
|
|
+ gs.gobuf = make([]byte, size)
|
|
|
+ p := C.malloc(C.size_t(size))
|
|
|
+ gs.cbuf = (*[1 << 30]byte)(unsafe.Pointer(p))[:size:size]
|
|
|
+
|
|
|
return gs, nil
|
|
|
}
|
|
|
|
|
|
@@ -91,6 +103,11 @@ func New() (*GLS, error) {
|
|
|
// could be disabled after an application is stable to improve the performance.
|
|
|
func (gs *GLS) SetCheckErrors(enable bool) {
|
|
|
|
|
|
+ if enable {
|
|
|
+ C.glapiCheckError(1)
|
|
|
+ } else {
|
|
|
+ C.glapiCheckError(1)
|
|
|
+ }
|
|
|
gs.checkErrors = enable
|
|
|
}
|
|
|
|
|
|
@@ -100,8 +117,8 @@ func (gs *GLS) CheckErrors() bool {
|
|
|
return gs.checkErrors
|
|
|
}
|
|
|
|
|
|
-// Reset resets the internal state kept of the OpenGL
|
|
|
-func (gs *GLS) Reset() {
|
|
|
+// reset resets the internal state kept of the OpenGL
|
|
|
+func (gs *GLS) reset() {
|
|
|
|
|
|
gs.lineWidth = 0.0
|
|
|
gs.sideView = uintUndef
|
|
|
@@ -124,49 +141,59 @@ func (gs *GLS) Reset() {
|
|
|
gs.polygonOffsetUnits = -1
|
|
|
}
|
|
|
|
|
|
-func (gs *GLS) SetDefaultState() {
|
|
|
+// setDefaultState is used internally to set the initial state of OpenGL
|
|
|
+// for this context.
|
|
|
+func (gs *GLS) setDefaultState() {
|
|
|
+
|
|
|
+ C.glClearColor(0, 0, 0, 1)
|
|
|
+ C.glClearDepth(1)
|
|
|
+ C.glClearStencil(0)
|
|
|
+ gs.Enable(DEPTH_TEST)
|
|
|
+ gs.DepthFunc(LEQUAL)
|
|
|
+ gs.FrontFace(CCW)
|
|
|
+ gs.CullFace(BACK)
|
|
|
+ gs.Enable(CULL_FACE)
|
|
|
+ gs.Enable(BLEND)
|
|
|
+ gs.BlendEquation(FUNC_ADD)
|
|
|
+ gs.BlendFunc(SRC_ALPHA, ONE_MINUS_SRC_ALPHA)
|
|
|
+ gs.Enable(VERTEX_PROGRAM_POINT_SIZE)
|
|
|
+ gs.Enable(PROGRAM_POINT_SIZE)
|
|
|
+ gs.Enable(MULTISAMPLE)
|
|
|
+ gs.Enable(POLYGON_OFFSET_FILL)
|
|
|
+ gs.Enable(POLYGON_OFFSET_LINE)
|
|
|
+ gs.Enable(POLYGON_OFFSET_POINT)
|
|
|
+}
|
|
|
+
|
|
|
+// Stats copy the current values of the internal statistics structure
|
|
|
+// to the specified pointer.
|
|
|
+func (gs *GLS) Stats(s *Stats) {
|
|
|
|
|
|
- gl.ClearColor(0, 0, 0, 1)
|
|
|
- gl.ClearDepth(1)
|
|
|
- gl.ClearStencil(0)
|
|
|
- gs.Enable(gl.DEPTH_TEST)
|
|
|
- gs.DepthFunc(gl.LEQUAL)
|
|
|
- gl.FrontFace(gl.CCW)
|
|
|
- gl.CullFace(gl.BACK)
|
|
|
- gs.Enable(gl.CULL_FACE)
|
|
|
- gs.Enable(gl.BLEND)
|
|
|
- gs.BlendEquation(gl.FUNC_ADD)
|
|
|
- gs.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
|
|
|
- gs.Enable(gl.VERTEX_PROGRAM_POINT_SIZE)
|
|
|
- gs.Enable(gl.PROGRAM_POINT_SIZE)
|
|
|
- gs.Enable(gl.MULTISAMPLE)
|
|
|
- gs.Enable(gl.POLYGON_OFFSET_FILL)
|
|
|
- gs.Enable(gl.POLYGON_OFFSET_LINE)
|
|
|
- gs.Enable(gl.POLYGON_OFFSET_POINT)
|
|
|
+ *s = gs.stats
|
|
|
}
|
|
|
|
|
|
func (gs *GLS) ActiveTexture(texture uint32) {
|
|
|
|
|
|
- gl.ActiveTexture(texture)
|
|
|
- gs.checkError("ActiveTexture")
|
|
|
+ C.glActiveTexture(C.GLenum(texture))
|
|
|
+}
|
|
|
+
|
|
|
+func (gs *GLS) AttachShader(program, shader uint32) {
|
|
|
+
|
|
|
+ C.glAttachShader(C.GLuint(program), C.GLuint(shader))
|
|
|
}
|
|
|
|
|
|
func (gs *GLS) BindBuffer(target int, vbo uint32) {
|
|
|
|
|
|
- gl.BindBuffer(uint32(target), vbo)
|
|
|
- gs.checkError("BindBuffer")
|
|
|
+ C.glBindBuffer(C.GLenum(target), C.GLuint(vbo))
|
|
|
}
|
|
|
|
|
|
func (gs *GLS) BindTexture(target int, tex uint32) {
|
|
|
|
|
|
- gl.BindTexture(uint32(target), tex)
|
|
|
- gs.checkError("BindTexture")
|
|
|
+ C.glBindTexture(C.GLenum(target), C.GLuint(tex))
|
|
|
}
|
|
|
|
|
|
func (gs *GLS) BindVertexArray(vao uint32) {
|
|
|
|
|
|
- gl.BindVertexArray(vao)
|
|
|
- gs.checkError("BindVertexArray")
|
|
|
+ C.glBindVertexArray(C.GLuint(vao))
|
|
|
}
|
|
|
|
|
|
func (gs *GLS) BlendEquation(mode uint32) {
|
|
|
@@ -174,8 +201,7 @@ func (gs *GLS) BlendEquation(mode uint32) {
|
|
|
if gs.blendEquation == mode {
|
|
|
return
|
|
|
}
|
|
|
- gl.BlendEquation(mode)
|
|
|
- gs.checkError("BlendEquation")
|
|
|
+ C.glBlendEquation(C.GLenum(mode))
|
|
|
gs.blendEquation = mode
|
|
|
}
|
|
|
|
|
|
@@ -184,8 +210,7 @@ func (gs *GLS) BlendEquationSeparate(modeRGB uint32, modeAlpha uint32) {
|
|
|
if gs.blendEquationRGB == modeRGB && gs.blendEquationAlpha == modeAlpha {
|
|
|
return
|
|
|
}
|
|
|
- gl.BlendEquationSeparate(uint32(modeRGB), uint32(modeAlpha))
|
|
|
- gs.checkError("BlendEquationSeparate")
|
|
|
+ C.glBlendEquationSeparate(C.GLenum(modeRGB), C.GLenum(modeAlpha))
|
|
|
gs.blendEquationRGB = modeRGB
|
|
|
gs.blendEquationAlpha = modeAlpha
|
|
|
}
|
|
|
@@ -195,8 +220,7 @@ func (gs *GLS) BlendFunc(sfactor, dfactor uint32) {
|
|
|
if gs.blendSrc == sfactor && gs.blendDst == dfactor {
|
|
|
return
|
|
|
}
|
|
|
- gl.BlendFunc(sfactor, dfactor)
|
|
|
- gs.checkError("BlendFunc")
|
|
|
+ C.glBlendFunc(C.GLenum(sfactor), C.GLenum(dfactor))
|
|
|
gs.blendSrc = sfactor
|
|
|
gs.blendDst = dfactor
|
|
|
}
|
|
|
@@ -207,8 +231,7 @@ func (gs *GLS) BlendFuncSeparate(srcRGB uint32, dstRGB uint32, srcAlpha uint32,
|
|
|
gs.blendSrcAlpha == srcAlpha && gs.blendDstAlpha == dstAlpha {
|
|
|
return
|
|
|
}
|
|
|
- gl.BlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha)
|
|
|
- gs.checkError("BlendFuncSeparate")
|
|
|
+ C.glBlendFuncSeparate(C.GLenum(srcRGB), C.GLenum(dstRGB), C.GLenum(srcAlpha), C.GLenum(dstAlpha))
|
|
|
gs.blendSrcRGB = srcRGB
|
|
|
gs.blendDstRGB = dstRGB
|
|
|
gs.blendSrcAlpha = srcAlpha
|
|
|
@@ -217,37 +240,60 @@ func (gs *GLS) BlendFuncSeparate(srcRGB uint32, dstRGB uint32, srcAlpha uint32,
|
|
|
|
|
|
func (gs *GLS) BufferData(target uint32, size int, data interface{}, usage uint32) {
|
|
|
|
|
|
- gl.BufferData(target, size, gl.Ptr(data), usage)
|
|
|
- gs.checkError("BufferData")
|
|
|
+ C.glBufferData(C.GLenum(target), C.GLsizeiptr(size), ptr(data), C.GLenum(usage))
|
|
|
}
|
|
|
|
|
|
func (gs *GLS) ClearColor(r, g, b, a float32) {
|
|
|
|
|
|
- gl.ClearColor(r, g, b, a)
|
|
|
+ C.glClearColor(C.GLfloat(r), C.GLfloat(g), C.GLfloat(b), C.GLfloat(a))
|
|
|
}
|
|
|
|
|
|
-func (gs *GLS) Clear(mask int) {
|
|
|
+func (gs *GLS) Clear(mask uint) {
|
|
|
|
|
|
- gl.Clear(uint32(mask))
|
|
|
+ C.glClear(C.GLbitfield(mask))
|
|
|
+}
|
|
|
+
|
|
|
+func (gs *GLS) CompileShader(shader uint32) {
|
|
|
+
|
|
|
+ C.glCompileShader(C.GLuint(shader))
|
|
|
+}
|
|
|
+
|
|
|
+func (gs *GLS) CreateProgram() uint32 {
|
|
|
+
|
|
|
+ p := C.glCreateProgram()
|
|
|
+ return uint32(p)
|
|
|
+}
|
|
|
+
|
|
|
+func (gs *GLS) CreateShader(stype uint32) uint32 {
|
|
|
+
|
|
|
+ h := C.glCreateShader(C.GLenum(stype))
|
|
|
+ return uint32(h)
|
|
|
}
|
|
|
|
|
|
func (gs *GLS) DeleteBuffers(vbos ...uint32) {
|
|
|
|
|
|
- gl.DeleteBuffers(int32(len(vbos)), &vbos[0])
|
|
|
- gs.checkError("DeleteBuffers")
|
|
|
+ C.glDeleteBuffers(C.GLsizei(len(vbos)), (*C.GLuint)(&vbos[0]))
|
|
|
+}
|
|
|
+
|
|
|
+func (gs *GLS) DeleteShader(shader uint32) {
|
|
|
+
|
|
|
+ C.glDeleteShader(C.GLuint(shader))
|
|
|
+}
|
|
|
+
|
|
|
+func (gs *GLS) DeleteProgram(program uint32) {
|
|
|
+
|
|
|
+ C.glDeleteProgram(C.GLuint(program))
|
|
|
}
|
|
|
|
|
|
func (gs *GLS) DeleteTextures(tex ...uint32) {
|
|
|
|
|
|
- gl.DeleteTextures(int32(len(tex)), &tex[0])
|
|
|
- gs.checkError("DeleteTextures")
|
|
|
- gs.Stats.Textures -= len(tex)
|
|
|
+ C.glDeleteTextures(C.GLsizei(len(tex)), (*C.GLuint)(&tex[0]))
|
|
|
+ gs.stats.Textures -= len(tex)
|
|
|
}
|
|
|
|
|
|
func (gs *GLS) DeleteVertexArrays(vaos ...uint32) {
|
|
|
|
|
|
- gl.DeleteVertexArrays(int32(len(vaos)), &vaos[0])
|
|
|
- gs.checkError("DeleteVertexArrays")
|
|
|
+ C.glDeleteVertexArrays(C.GLsizei(len(vaos)), (*C.GLuint)(&vaos[0]))
|
|
|
}
|
|
|
|
|
|
func (gs *GLS) DepthFunc(mode uint32) {
|
|
|
@@ -255,8 +301,7 @@ func (gs *GLS) DepthFunc(mode uint32) {
|
|
|
if gs.depthFunc == mode {
|
|
|
return
|
|
|
}
|
|
|
- gl.DepthFunc(mode)
|
|
|
- gs.checkError("DepthFunc")
|
|
|
+ C.glDepthFunc(C.GLenum(mode))
|
|
|
gs.depthFunc = mode
|
|
|
}
|
|
|
|
|
|
@@ -268,8 +313,7 @@ func (gs *GLS) DepthMask(flag bool) {
|
|
|
if gs.depthMask == intFalse && !flag {
|
|
|
return
|
|
|
}
|
|
|
- gl.DepthMask(flag)
|
|
|
- gs.checkError("DepthMask")
|
|
|
+ C.glDepthMask(bool2c(flag))
|
|
|
if flag {
|
|
|
gs.depthMask = intTrue
|
|
|
} else {
|
|
|
@@ -279,85 +323,126 @@ func (gs *GLS) DepthMask(flag bool) {
|
|
|
|
|
|
func (gs *GLS) DrawArrays(mode uint32, first int32, count int32) {
|
|
|
|
|
|
- gl.DrawArrays(mode, first, count)
|
|
|
- gs.checkError("DrawArrays")
|
|
|
+ C.glDrawArrays(C.GLenum(mode), C.GLint(first), C.GLsizei(count))
|
|
|
+ gs.stats.Drawcalls++
|
|
|
}
|
|
|
|
|
|
func (gs *GLS) DrawElements(mode uint32, count int32, itype uint32, start uint32) {
|
|
|
|
|
|
- gl.DrawElements(mode, int32(count), itype, gl.PtrOffset(int(start)))
|
|
|
- gs.checkError("DrawElements")
|
|
|
+ C.glDrawElements(C.GLenum(mode), C.GLsizei(count), C.GLenum(itype), unsafe.Pointer(uintptr(start)))
|
|
|
+ gs.stats.Drawcalls++
|
|
|
}
|
|
|
|
|
|
func (gs *GLS) Enable(cap int) {
|
|
|
|
|
|
if gs.capabilities[cap] == capEnabled {
|
|
|
+ gs.stats.Caphits++
|
|
|
return
|
|
|
}
|
|
|
- gl.Enable(uint32(cap))
|
|
|
- gs.checkError("Enable")
|
|
|
+ C.glEnable(C.GLenum(cap))
|
|
|
gs.capabilities[cap] = capEnabled
|
|
|
}
|
|
|
|
|
|
func (gs *GLS) EnableVertexAttribArray(index uint32) {
|
|
|
|
|
|
- gl.EnableVertexAttribArray(index)
|
|
|
- gs.checkError("EnableVertexAttribArray")
|
|
|
+ C.glEnableVertexAttribArray(C.GLuint(index))
|
|
|
}
|
|
|
|
|
|
func (gs *GLS) Disable(cap int) {
|
|
|
|
|
|
if gs.capabilities[cap] == capDisabled {
|
|
|
+ gs.stats.Caphits++
|
|
|
return
|
|
|
}
|
|
|
- gl.Disable(uint32(cap))
|
|
|
- gs.checkError("Disable")
|
|
|
+ C.glDisable(C.GLenum(cap))
|
|
|
gs.capabilities[cap] = capDisabled
|
|
|
}
|
|
|
|
|
|
+func (gs *GLS) CullFace(mode uint32) {
|
|
|
+
|
|
|
+ C.glCullFace(C.GLenum(mode))
|
|
|
+}
|
|
|
+
|
|
|
func (gs *GLS) FrontFace(mode uint32) {
|
|
|
|
|
|
- gl.FrontFace(mode)
|
|
|
- gs.checkError("FrontFace")
|
|
|
+ C.glFrontFace(C.GLenum(mode))
|
|
|
}
|
|
|
|
|
|
func (gs *GLS) GenBuffer() uint32 {
|
|
|
|
|
|
var buf uint32
|
|
|
- gl.GenBuffers(1, &buf)
|
|
|
- gs.checkError("GenBuffers")
|
|
|
- gs.Stats.Vbos++
|
|
|
+ C.glGenBuffers(1, (*C.GLuint)(&buf))
|
|
|
+ gs.stats.Vbos++
|
|
|
return buf
|
|
|
}
|
|
|
|
|
|
func (gs *GLS) GenerateMipmap(target uint32) {
|
|
|
|
|
|
- gl.GenerateMipmap(target)
|
|
|
- gs.checkError("GenerateMipmap")
|
|
|
+ C.glGenerateMipmap(C.GLenum(target))
|
|
|
}
|
|
|
|
|
|
func (gs *GLS) GenTexture() uint32 {
|
|
|
|
|
|
var tex uint32
|
|
|
- gl.GenTextures(1, &tex)
|
|
|
- gs.checkError("GenTextures")
|
|
|
- gs.Stats.Textures++
|
|
|
+ C.glGenTextures(1, (*C.GLuint)(&tex))
|
|
|
+ gs.stats.Textures++
|
|
|
return tex
|
|
|
}
|
|
|
|
|
|
func (gs *GLS) GenVertexArray() uint32 {
|
|
|
|
|
|
var vao uint32
|
|
|
- gl.GenVertexArrays(1, &vao)
|
|
|
- gs.checkError("GenVertexArrays")
|
|
|
- gs.Stats.Vaos++
|
|
|
+ C.glGenVertexArrays(1, (*C.GLuint)(&vao))
|
|
|
+ gs.stats.Vaos++
|
|
|
return vao
|
|
|
}
|
|
|
|
|
|
+func (gs *GLS) GetAttribLocation(program uint32, name string) int32 {
|
|
|
+
|
|
|
+ loc := C.glGetAttribLocation(C.GLuint(program), gs.gobufStr(name))
|
|
|
+ return int32(loc)
|
|
|
+}
|
|
|
+
|
|
|
+func (gs *GLS) GetProgramiv(program, pname uint32, params *int32) {
|
|
|
+
|
|
|
+ C.glGetProgramiv(C.GLuint(program), C.GLenum(pname), (*C.GLint)(params))
|
|
|
+}
|
|
|
+
|
|
|
+// GetProgramInfoLog returns the information log for the specified program object.
|
|
|
+func (gs *GLS) GetProgramInfoLog(program uint32) string {
|
|
|
+
|
|
|
+ var length int32
|
|
|
+ gs.GetProgramiv(program, INFO_LOG_LENGTH, &length)
|
|
|
+ if length == 0 {
|
|
|
+ return ""
|
|
|
+ }
|
|
|
+ C.glGetProgramInfoLog(C.GLuint(program), C.GLsizei(length), nil, gs.gobufSize(uint32(length)))
|
|
|
+ return string(gs.gobuf[:length])
|
|
|
+}
|
|
|
+
|
|
|
+// GetShaderInfoLog returns the information log for the specified shader object.
|
|
|
+func (gs *GLS) GetShaderInfoLog(shader uint32) string {
|
|
|
+
|
|
|
+ var length int32
|
|
|
+ gs.GetShaderiv(shader, INFO_LOG_LENGTH, &length)
|
|
|
+ if length == 0 {
|
|
|
+ return ""
|
|
|
+ }
|
|
|
+ C.glGetShaderInfoLog(C.GLuint(shader), C.GLsizei(length), nil, gs.gobufSize(uint32(length)))
|
|
|
+ return string(gs.gobuf[:length])
|
|
|
+}
|
|
|
+
|
|
|
func (gs *GLS) GetString(name uint32) string {
|
|
|
|
|
|
- cstr := gl.GetString(name)
|
|
|
- return gl.GoStr(cstr)
|
|
|
+ cs := C.glGetString(C.GLenum(name))
|
|
|
+ return C.GoString((*C.char)(unsafe.Pointer(cs)))
|
|
|
+}
|
|
|
+
|
|
|
+// GetUniformLocation returns the location of a uniform variable for the specified program.
|
|
|
+func (gs *GLS) GetUniformLocation(program uint32, name string) int32 {
|
|
|
+
|
|
|
+ loc := C.glGetUniformLocation(C.GLuint(program), gs.gobufStr(name))
|
|
|
+ return int32(loc)
|
|
|
}
|
|
|
|
|
|
func (gs *GLS) GetViewport() (x, y, width, height int32) {
|
|
|
@@ -370,17 +455,21 @@ func (gs *GLS) LineWidth(width float32) {
|
|
|
if gs.lineWidth == width {
|
|
|
return
|
|
|
}
|
|
|
- gl.LineWidth(width)
|
|
|
- gs.checkError("LineWidth")
|
|
|
+ C.glLineWidth(C.GLfloat(width))
|
|
|
gs.lineWidth = width
|
|
|
}
|
|
|
|
|
|
-func (gs *GLS) SetDepthTest(mode bool) {
|
|
|
+func (gs *GLS) LinkProgram(program uint32) {
|
|
|
+
|
|
|
+ C.glLinkProgram(C.GLuint(program))
|
|
|
+}
|
|
|
+
|
|
|
+func (gs *GLS) SetDepthTest(enable bool) {
|
|
|
|
|
|
- if mode {
|
|
|
- gs.Enable(gl.DEPTH_TEST)
|
|
|
+ if enable {
|
|
|
+ gs.Enable(DEPTH_TEST)
|
|
|
} else {
|
|
|
- gs.Disable(gl.DEPTH_TEST)
|
|
|
+ gs.Disable(DEPTH_TEST)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -392,43 +481,53 @@ func (gs *GLS) SetSideView(mode int) {
|
|
|
switch mode {
|
|
|
// Default: show only the front size
|
|
|
case FrontSide:
|
|
|
- gs.Enable(gl.CULL_FACE)
|
|
|
- gl.FrontFace(gl.CCW)
|
|
|
+ gs.Enable(CULL_FACE)
|
|
|
+ C.glFrontFace(CCW)
|
|
|
// Show only the back side
|
|
|
case BackSide:
|
|
|
- gs.Enable(gl.CULL_FACE)
|
|
|
- gl.FrontFace(gl.CW)
|
|
|
+ gs.Enable(CULL_FACE)
|
|
|
+ C.glFrontFace(CW)
|
|
|
// Show both sides
|
|
|
case DoubleSide:
|
|
|
- gs.Disable(gl.CULL_FACE)
|
|
|
+ gs.Disable(CULL_FACE)
|
|
|
default:
|
|
|
panic("SetSideView() invalid mode")
|
|
|
}
|
|
|
gs.sideView = mode
|
|
|
}
|
|
|
|
|
|
-func (gs *GLS) TexImage2D(target uint32, level int32, iformat int32, width int32, height int32, border int32, format uint32, itype uint32, data interface{}) {
|
|
|
+func (gs *GLS) GetShaderiv(shader, pname uint32, params *int32) {
|
|
|
|
|
|
- gl.TexImage2D(uint32(target), int32(level), int32(iformat), int32(width), int32(height), int32(border), uint32(format), uint32(itype), gl.Ptr(data))
|
|
|
- gs.checkError("TexImage2D")
|
|
|
+ C.glGetShaderiv(C.GLuint(shader), C.GLenum(pname), (*C.GLint)(params))
|
|
|
}
|
|
|
|
|
|
-func (gs *GLS) TexStorage2D(target int, levels int, iformat int, width, height int) {
|
|
|
+func (gs *GLS) ShaderSource(shader uint32, src string) {
|
|
|
|
|
|
- gl.TexStorage2D(uint32(target), int32(levels), uint32(iformat), int32(width), int32(height))
|
|
|
- gs.checkError("TexStorage2D")
|
|
|
+ csource := gs.cbufStr(src)
|
|
|
+ C.glShaderSource(C.GLuint(shader), 1, (**C.GLchar)(unsafe.Pointer(&csource)), nil)
|
|
|
+}
|
|
|
+
|
|
|
+func (gs *GLS) TexImage2D(target uint32, level int32, iformat int32, width int32, height int32, border int32, format uint32, itype uint32, data interface{}) {
|
|
|
+
|
|
|
+ C.glTexImage2D(C.GLenum(target),
|
|
|
+ C.GLint(level),
|
|
|
+ C.GLint(iformat),
|
|
|
+ C.GLsizei(width),
|
|
|
+ C.GLsizei(height),
|
|
|
+ C.GLint(border),
|
|
|
+ C.GLenum(format),
|
|
|
+ C.GLenum(itype),
|
|
|
+ ptr(data))
|
|
|
}
|
|
|
|
|
|
func (gs *GLS) TexParameteri(target uint32, pname uint32, param int32) {
|
|
|
|
|
|
- gl.TexParameteri(target, pname, param)
|
|
|
- gs.checkError("TexParameteri")
|
|
|
+ C.glTexParameteri(C.GLenum(target), C.GLenum(pname), C.GLint(param))
|
|
|
}
|
|
|
|
|
|
func (gs *GLS) PolygonMode(face, mode int) {
|
|
|
|
|
|
- gl.PolygonMode(uint32(face), uint32(mode))
|
|
|
- gs.checkError("PolygonMode")
|
|
|
+ C.glPolygonMode(C.GLenum(face), C.GLenum(mode))
|
|
|
}
|
|
|
|
|
|
func (gs *GLS) PolygonOffset(factor float32, units float32) {
|
|
|
@@ -436,52 +535,89 @@ func (gs *GLS) PolygonOffset(factor float32, units float32) {
|
|
|
if gs.polygonOffsetFactor == factor && gs.polygonOffsetUnits == units {
|
|
|
return
|
|
|
}
|
|
|
- gl.PolygonOffset(factor, units)
|
|
|
- gs.checkError("PolygonOffset")
|
|
|
+ C.glPolygonOffset(C.GLfloat(factor), C.GLfloat(units))
|
|
|
gs.polygonOffsetFactor = factor
|
|
|
gs.polygonOffsetUnits = units
|
|
|
}
|
|
|
|
|
|
func (gs *GLS) Uniform1i(location int32, v0 int32) {
|
|
|
|
|
|
- gl.Uniform1i(location, v0)
|
|
|
- gs.checkError("Uniform1i")
|
|
|
+ C.glUniform1i(C.GLint(location), C.GLint(v0))
|
|
|
+ gs.stats.Unisets++
|
|
|
}
|
|
|
|
|
|
func (gs *GLS) Uniform1f(location int32, v0 float32) {
|
|
|
|
|
|
- gl.Uniform1f(location, v0)
|
|
|
- gs.checkError("Uniform1f")
|
|
|
+ C.glUniform1f(C.GLint(location), C.GLfloat(v0))
|
|
|
+ gs.stats.Unisets++
|
|
|
}
|
|
|
|
|
|
func (gs *GLS) Uniform2f(location int32, v0, v1 float32) {
|
|
|
|
|
|
- gl.Uniform2f(location, v0, v1)
|
|
|
- gs.checkError("Uniform2f")
|
|
|
+ C.glUniform2f(C.GLint(location), C.GLfloat(v0), C.GLfloat(v1))
|
|
|
+ gs.stats.Unisets++
|
|
|
}
|
|
|
|
|
|
func (gs *GLS) Uniform3f(location int32, v0, v1, v2 float32) {
|
|
|
|
|
|
- gl.Uniform3f(location, v0, v1, v2)
|
|
|
- gs.checkError("Uniform3f")
|
|
|
+ C.glUniform3f(C.GLint(location), C.GLfloat(v0), C.GLfloat(v1), C.GLfloat(v2))
|
|
|
+ gs.stats.Unisets++
|
|
|
}
|
|
|
|
|
|
func (gs *GLS) Uniform4f(location int32, v0, v1, v2, v3 float32) {
|
|
|
|
|
|
- gl.Uniform4f(location, v0, v1, v2, v3)
|
|
|
- gs.checkError("Uniform4f")
|
|
|
+ C.glUniform4f(C.GLint(location), C.GLfloat(v0), C.GLfloat(v1), C.GLfloat(v2), C.GLfloat(v3))
|
|
|
+ gs.stats.Unisets++
|
|
|
}
|
|
|
|
|
|
-func (gs *GLS) UniformMatrix3fv(location int32, count int32, transpose bool, v []float32) {
|
|
|
+func (gs *GLS) UniformMatrix3fv(location int32, count int32, transpose bool, pm *float32) {
|
|
|
|
|
|
- gl.UniformMatrix3fv(location, count, transpose, &v[0])
|
|
|
- gs.checkError("UniformMatrix3fv")
|
|
|
+ C.glUniformMatrix3fv(C.GLint(location), C.GLsizei(count), bool2c(transpose), (*C.GLfloat)(pm))
|
|
|
+ gs.stats.Unisets++
|
|
|
}
|
|
|
|
|
|
-func (gs *GLS) UniformMatrix4fv(location int32, count int32, transpose bool, v []float32) {
|
|
|
+func (gs *GLS) UniformMatrix4fv(location int32, count int32, transpose bool, pm *float32) {
|
|
|
+
|
|
|
+ C.glUniformMatrix4fv(C.GLint(location), C.GLsizei(count), bool2c(transpose), (*C.GLfloat)(pm))
|
|
|
+ gs.stats.Unisets++
|
|
|
+}
|
|
|
+
|
|
|
+func (gs *GLS) Uniform1fv(location int32, count int32, v []float32) {
|
|
|
+
|
|
|
+ C.glUniform1fv(C.GLint(location), C.GLsizei(count), (*C.GLfloat)(&v[0]))
|
|
|
+ gs.stats.Unisets++
|
|
|
+}
|
|
|
+
|
|
|
+func (gs *GLS) Uniform2fv(location int32, count int32, v []float32) {
|
|
|
+
|
|
|
+ C.glUniform2fv(C.GLint(location), C.GLsizei(count), (*C.GLfloat)(&v[0]))
|
|
|
+ gs.stats.Unisets++
|
|
|
+}
|
|
|
+
|
|
|
+func (gs *GLS) Uniform3fv(location int32, count int32, v []float32) {
|
|
|
+
|
|
|
+ C.glUniform3fv(C.GLint(location), C.GLsizei(count), (*C.GLfloat)(&v[0]))
|
|
|
+ gs.stats.Unisets++
|
|
|
+}
|
|
|
+
|
|
|
+func (gs *GLS) Uniform4fv(location int32, count int32, v []float32) {
|
|
|
+
|
|
|
+ C.glUniform4fv(C.GLint(location), C.GLsizei(count), (*C.GLfloat)(&v[0]))
|
|
|
+ gs.stats.Unisets++
|
|
|
+}
|
|
|
+
|
|
|
+func (gs *GLS) VertexAttribPointer(index uint32, size int32, xtype uint32, normalized bool, stride int32, offset uint32) {
|
|
|
|
|
|
- gl.UniformMatrix4fv(location, count, transpose, &v[0])
|
|
|
- gs.checkError("UniformMatrix4fv")
|
|
|
+ C.glVertexAttribPointer(C.GLuint(index), C.GLint(size), C.GLenum(xtype), bool2c(normalized), C.GLsizei(stride), unsafe.Pointer(uintptr(offset)))
|
|
|
+}
|
|
|
+
|
|
|
+func (gs *GLS) Viewport(x, y, width, height int32) {
|
|
|
+
|
|
|
+ C.glViewport(C.GLint(x), C.GLint(y), C.GLsizei(width), C.GLsizei(height))
|
|
|
+ gs.viewportX = x
|
|
|
+ gs.viewportY = y
|
|
|
+ gs.viewportWidth = width
|
|
|
+ gs.viewportHeight = height
|
|
|
}
|
|
|
|
|
|
// Use set this program as the current program.
|
|
|
@@ -490,8 +626,7 @@ func (gs *GLS) UseProgram(prog *Program) {
|
|
|
if prog.handle == 0 {
|
|
|
panic("Invalid program")
|
|
|
}
|
|
|
- gl.UseProgram(prog.handle)
|
|
|
- gs.checkError("UseProgram")
|
|
|
+ C.glUseProgram(C.GLuint(prog.handle))
|
|
|
gs.Prog = prog
|
|
|
|
|
|
// Inserts program in cache if not already there.
|
|
|
@@ -501,29 +636,93 @@ func (gs *GLS) UseProgram(prog *Program) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-func (gs *GLS) VertexAttribPointer(index uint32, size int32, xtype uint32, normalized bool, stride int32, offset uint32) {
|
|
|
+// Ptr takes a slice or pointer (to a singular scalar value or the first
|
|
|
+// element of an array or slice) and returns its GL-compatible address.
|
|
|
+//
|
|
|
+// For example:
|
|
|
+//
|
|
|
+// var data []uint8
|
|
|
+// ...
|
|
|
+// gl.TexImage2D(gl.TEXTURE_2D, ..., gl.UNSIGNED_BYTE, gl.Ptr(&data[0]))
|
|
|
+func ptr(data interface{}) unsafe.Pointer {
|
|
|
+ if data == nil {
|
|
|
+ return unsafe.Pointer(nil)
|
|
|
+ }
|
|
|
+ var addr unsafe.Pointer
|
|
|
+ v := reflect.ValueOf(data)
|
|
|
+ switch v.Type().Kind() {
|
|
|
+ case reflect.Ptr:
|
|
|
+ e := v.Elem()
|
|
|
+ switch e.Kind() {
|
|
|
+ case
|
|
|
+ reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
|
|
+ reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
|
|
+ reflect.Float32, reflect.Float64:
|
|
|
+ addr = unsafe.Pointer(e.UnsafeAddr())
|
|
|
+ default:
|
|
|
+ panic(fmt.Errorf("unsupported pointer to type %s; must be a slice or pointer to a singular scalar value or the first element of an array or slice", e.Kind()))
|
|
|
+ }
|
|
|
+ case reflect.Uintptr:
|
|
|
+ addr = unsafe.Pointer(v.Pointer())
|
|
|
+ case reflect.Slice:
|
|
|
+ addr = unsafe.Pointer(v.Index(0).UnsafeAddr())
|
|
|
+ default:
|
|
|
+ panic(fmt.Errorf("unsupported type %s; must be a slice or pointer to a singular scalar value or the first element of an array or slice", v.Type()))
|
|
|
+ }
|
|
|
+ return addr
|
|
|
+}
|
|
|
|
|
|
- gl.VertexAttribPointer(index, size, xtype, normalized, stride, gl.PtrOffset(int(offset)))
|
|
|
- gs.checkError("VertexAttribPointer")
|
|
|
+// bool2c convert a Go bool to C.GLboolean
|
|
|
+func bool2c(b bool) C.GLboolean {
|
|
|
+
|
|
|
+ if b {
|
|
|
+ return C.GLboolean(1)
|
|
|
+ }
|
|
|
+ return C.GLboolean(0)
|
|
|
}
|
|
|
|
|
|
-func (gs *GLS) Viewport(x, y, width, height int32) {
|
|
|
+// gobufSize returns a pointer to static buffer with the specified size not including the terminator.
|
|
|
+// If there is available space, there is no memory allocation.
|
|
|
+func (gs *GLS) gobufSize(size uint32) *C.GLchar {
|
|
|
|
|
|
- gl.Viewport(x, y, width, height)
|
|
|
- gs.checkError("Viewport")
|
|
|
- gs.viewportX = x
|
|
|
- gs.viewportY = y
|
|
|
- gs.viewportWidth = width
|
|
|
- gs.viewportHeight = height
|
|
|
+ if size+1 > uint32(len(gs.gobuf)) {
|
|
|
+ gs.gobuf = make([]byte, size+1)
|
|
|
+ }
|
|
|
+ return (*C.GLchar)(unsafe.Pointer(&gs.gobuf[0]))
|
|
|
+}
|
|
|
+
|
|
|
+// gobufStr converts a Go String to a C string by copying it to a static buffer
|
|
|
+// and returning a pointer to the start of the buffer.
|
|
|
+// If there is available space, there is no memory allocation.
|
|
|
+func (gs *GLS) gobufStr(s string) *C.GLchar {
|
|
|
+
|
|
|
+ p := gs.gobufSize(uint32(len(s) + 1))
|
|
|
+ copy(gs.gobuf, s)
|
|
|
+ gs.gobuf[len(s)] = 0
|
|
|
+ return p
|
|
|
}
|
|
|
|
|
|
-// checkError checks the error code of the previously called OpenGL function
|
|
|
-func (gls *GLS) checkError(fname string) {
|
|
|
+// cbufSize returns a pointer to static buffer with C memory
|
|
|
+// If there is available space, there is no memory allocation.
|
|
|
+func (gs *GLS) cbufSize(size uint32) *C.GLchar {
|
|
|
|
|
|
- if gls.checkErrors {
|
|
|
- ecode := gl.GetError()
|
|
|
- if ecode != 0 {
|
|
|
- log.Fatal("Error:%d calling:%s()", ecode, fname)
|
|
|
+ if size > uint32(len(gs.cbuf)) {
|
|
|
+ if len(gs.cbuf) > 0 {
|
|
|
+ C.free(unsafe.Pointer(&gs.cbuf[0]))
|
|
|
}
|
|
|
+ p := C.malloc(C.size_t(size))
|
|
|
+ gs.cbuf = (*[1 << 30]byte)(unsafe.Pointer(p))[:size:size]
|
|
|
}
|
|
|
+ return (*C.GLchar)(unsafe.Pointer(&gs.cbuf[0]))
|
|
|
+}
|
|
|
+
|
|
|
+// cbufStr converts a Go String to a C string by copying it to a single pre-allocated buffer
|
|
|
+// using C memory and returning a pointer to the start of the buffer.
|
|
|
+// If there is available space, there is no memory allocation.
|
|
|
+func (gs *GLS) cbufStr(s string) *C.GLchar {
|
|
|
+
|
|
|
+ p := gs.cbufSize(uint32(len(s) + 1))
|
|
|
+ copy(gs.cbuf, s)
|
|
|
+ gs.cbuf[len(s)] = 0
|
|
|
+ return p
|
|
|
}
|