Sfoglia il codice sorgente

Merge new opengl binding branch into master

leonsal 8 anni fa
parent
commit
29bd3ffad2
12 ha cambiato i file con 12620 aggiunte e 1888 eliminazioni
  1. 21 0
      gls/build.go
  2. 835 1476
      gls/consts.go
  3. 13 0
      gls/doc.go
  4. 5018 0
      gls/glapi.c
  5. 16 0
      gls/glapi.h
  6. 325 0
      gls/glapi2go/main.go
  7. 355 0
      gls/glapi2go/template.go
  8. 5595 0
      gls/glcorearb.h
  9. 389 190
      gls/gls.go
  10. 12 0
      gls/logger.go
  11. 37 218
      gls/program.go
  12. 4 4
      gls/uniform.go

+ 21 - 0
gls/build.go

@@ -0,0 +1,21 @@
+// 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
+
+// Generation of API files: glapi.c, glapi.h, consts.go
+//go:generate glapi2go -glversion GL_VERSION_3_3 glcorearb.h
+
+// // Platform build flags
+// #cgo freebsd CFLAGS:  -DGL_GLEXT_PROTOTYPES
+// #cgo freebsd LDFLAGS: -ldl
+//
+// #cgo linux   CFLAGS:  -DGL_GLEXT_PROTOTYPES
+// #cgo linux   LDFLAGS: -ldl
+//
+// #cgo windows CFLAGS:  -DGL_GLEXT_PROTOTYPES
+// #cgo windows LDFLAGS: -lopengl32
+//
+// #cgo darwin  CFLAGS:  -DGL_GLEXT_PROTOTYPES
+// #cgo darwin  LDFLAGS: -framework OpenGL
+import "C"

File diff suppressed because it is too large
+ 835 - 1476
gls/consts.go


+ 13 - 0
gls/doc.go

@@ -0,0 +1,13 @@
+// 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 implements a loader of OpenGL functions for the platform
+// and a Go binding for selected OpenGL functions. The binding maintains
+// some cached state to minimize the number of C function calls.
+// The OpenGL function loader is generated by the "glapi2go" tool by
+// parsing the OpenGL "glcorearb.h" header file
+//
+// This package also contains abstractions for some OpenGL object such as Program,
+// Uniform, VBO and others.
+package gls

File diff suppressed because it is too large
+ 5018 - 0
gls/glapi.c


+ 16 - 0
gls/glapi.h

@@ -0,0 +1,16 @@
+
+// This file was generated automatically by "glapi2go" and contains declarations
+// of public functions from "glapli.c".
+
+#ifndef _glapi_h_
+#define _glapi_h_
+
+#include "glcorearb.h"
+
+// Loads the OpenGL function pointers
+int glapiLoad(void);
+
+// Set the internal flag to enable/disable OpenGL error checking
+void glapiCheckError(int check);
+
+#endif

+ 325 - 0
gls/glapi2go/main.go

@@ -0,0 +1,325 @@
+package main
+
+import (
+	"bufio"
+	"flag"
+	"fmt"
+	"io"
+	"os"
+	"regexp"
+	"strings"
+)
+
+// Current Version
+const (
+	PROGNAME = "glapi2go"
+	VMAJOR   = 0
+	VMINOR   = 1
+)
+
+// Command line options
+var (
+	oGLVersion = flag.String("glversion", "GL_VERSION_3_3", "OpenGL version to use")
+)
+
+const (
+	fileGLAPIC   = "glapi.c"
+	fileGLAPIH   = "glapi.h"
+	fileGLPARAMH = "glparam.h"
+	fileCONSTS   = "consts.go"
+)
+
+// Maps OpenGL types to Go
+var mapCType2Go = map[string]string{
+	"GLenum":     "uint",
+	"GLfloat":    "float32",
+	"GLchar":     "byte",
+	"GLbyte":     "byte",
+	"GLboolean":  "bool",
+	"GLshort":    "int16",
+	"GLushort":   "uint16",
+	"GLint":      "int",
+	"GLint64":    "int64",
+	"GLsizei":    "int",
+	"GLbitfield": "uint",
+	"GLdouble":   "float64",
+	"GLuint":     "uint",
+	"GLuint64":   "uint64",
+	"GLubyte":    "byte",
+	"GLintptr":   "uintptr",
+	"GLsizeiptr": "uintptr",
+	"GLsync":     "unsafe.Pointer",
+}
+
+func main() {
+
+	// Parse command line parameters
+	flag.Usage = usage
+	flag.Parse()
+
+	// Checks for input header file
+	if len(flag.Args()) == 0 {
+		usage()
+		return
+	}
+	fname := flag.Args()[0]
+
+	// Open input header file
+	fin, err := os.Open(fname)
+	if err != nil {
+		abort(err)
+	}
+
+	// Parses the header and builds GLHeader struct
+	// with all the information necessary to expand all templates.
+	var glh GLHeader
+	err = parser(fin, &glh)
+	if err != nil {
+		abort(err)
+	}
+
+	// Generates glapi.c
+	err = genFile(templGLAPIC, &glh, fileGLAPIC, false)
+	if err != nil {
+		abort(err)
+	}
+
+	// Generates glapi.h
+	err = genFile(templGLAPIH, &glh, fileGLAPIH, false)
+	if err != nil {
+		abort(err)
+	}
+
+	// Generates consts.go
+	err = genFile(templCONSTS, &glh, fileCONSTS, true)
+	if err != nil {
+		abort(err)
+	}
+}
+
+// parser parses the header file and builds the Template structure
+func parser(fheader io.Reader, h *GLHeader) error {
+
+	// Regex to parser #endif line to detect end of definitions for
+	// specific OpenGL version: ex:"#endif /* GL_VERSION_3_3 */"
+	rexEndif := regexp.MustCompile(`#endif\s+/\*\s+(\w+)\s+\*/`)
+
+	// Regex to parse define line, capturing name (1) and value (2)
+	rexDefine := regexp.MustCompile(`#define\s+(\w+)\s+(\w+)`)
+
+	// Regex to parse function definition line,
+	// capturing return value (1), function name (2) and parameters (3)
+	rexApi := regexp.MustCompile(`GLAPI\s+(.*)APIENTRY\s+(\w+)\s+\((.*)\)`)
+
+	h.Defines = make([]GLDefine, 0)
+	h.Funcs = make([]GLFunc, 0)
+	bufin := bufio.NewReader(fheader)
+	maxLength := 0
+	for {
+		// Reads next line and abort on error (not EOF)
+		line, err := bufin.ReadString('\n')
+		if err != nil && err != io.EOF {
+			return err
+		}
+
+		// Checks for "#endif" identifying end of definitions for specified
+		// OpenGL version
+		res := rexEndif.FindStringSubmatch(line)
+		if len(res) > 0 {
+			if res[1] == *oGLVersion {
+				break
+			}
+		}
+
+		// Checks for "#define" of GL constants
+		res = rexDefine.FindStringSubmatch(line)
+		if len(res) >= 3 {
+			dname := res[1]
+			if strings.HasPrefix(dname, "GL_") {
+				h.Defines = append(h.Defines, GLDefine{
+					Name:  gldef2go(res[1]),
+					Value: glval2go(res[2]),
+				})
+			}
+		}
+
+		// Checks for function declaration
+		res = rexApi.FindStringSubmatch(line)
+		if len(res) >= 2 {
+			var f GLFunc
+			f.Rtype = strings.Trim(res[1], " ")
+			f.Ptype = "PFN" + strings.ToUpper(res[2]) + "PROC"
+			f.Fname = res[2]
+			f.FnameGo = glfname2go(res[2])
+			f.Pname = "p" + f.Fname
+			f.CParams = res[3]
+			err := parseParams(res[3], &f)
+			if err != nil {
+				return err
+			}
+			h.Funcs = append(h.Funcs, f)
+			if len(f.Ptype) > maxLength {
+				maxLength = len(f.Ptype)
+			}
+		}
+		// If EOF ends of parsing.
+		if err == io.EOF {
+			break
+		}
+	}
+	// Sets spacer string
+	for i := 0; i < len(h.Funcs); i++ {
+		h.Funcs[i].Spacer = strings.Repeat(" ", maxLength-len(h.Funcs[i].Ptype)+1)
+	}
+
+	return nil
+}
+
+// parseParams receives a string with the declaration of the parameters of a C function
+// and parses it into an array of GLParam types with are then saved in the specified
+// GLfunc object.
+func parseParams(gparams string, f *GLFunc) error {
+
+	params := strings.Split(gparams, ",")
+	res := make([]GLParam, 0)
+	args := make([]string, 0)
+	goParams := make([]string, 0)
+	for _, tn := range params {
+		parts := strings.Split(strings.TrimSpace(tn), " ")
+		var qualif string
+		var name string
+		var ctype string
+		switch len(parts) {
+		case 1:
+			ctype = parts[0]
+			if ctype != "void" {
+				panic("Should be void but is:" + ctype)
+			}
+			continue
+		case 2:
+			ctype = parts[0]
+			name = parts[1]
+		case 3:
+			qualif = parts[0]
+			ctype = parts[1]
+			name = parts[2]
+		default:
+			return fmt.Errorf("Invalid parameter:[%s]", tn)
+		}
+		arg := getArgName(name)
+		args = append(args, arg)
+		res = append(res, GLParam{Qualif: qualif, CType: ctype, Arg: arg, Name: name})
+		// Go parameter
+		goarg, gotype := gltypearg2go(ctype, name)
+		goParams = append(goParams, goarg+" "+gotype)
+	}
+	f.Args = strings.Join(args, ", ")
+	f.Params = res
+	f.GoParams = strings.Join(goParams, ", ")
+	return nil
+}
+
+// getArgName remove qualifiers and array brackets from the argument
+// returning only the argument name. Ex: *const*indices -> indices
+func getArgName(arg string) string {
+
+	if strings.HasPrefix(arg, "*const*") {
+		return strings.TrimPrefix(arg, "*const*")
+	}
+	if strings.HasPrefix(arg, "**") {
+		return strings.TrimPrefix(arg, "**")
+	}
+	if strings.HasPrefix(arg, "*") {
+		return strings.TrimPrefix(arg, "*")
+	}
+	// Checks for array index: [?]
+	aidx := strings.Index(arg, "[")
+	if aidx > 0 {
+		return arg[:aidx]
+	}
+	return arg
+}
+
+// glfname2go converts the name of an OpenGL C function to Go
+func glfname2go(glfname string) string {
+
+	if strings.HasPrefix(glfname, "gl") {
+		return strings.TrimPrefix(glfname, "gl")
+	}
+	return glfname
+}
+
+// gldef2go converts a name such as GL_LINE_LOOP to LINE_LOOP
+func gldef2go(gldef string) string {
+
+	return strings.TrimPrefix(gldef, "GL_")
+}
+
+// glval2go converts a C OpenGL value to a Go value
+func glval2go(glval string) string {
+
+	val := glval
+	if strings.HasSuffix(val, "u") {
+		val = strings.TrimSuffix(val, "u")
+	}
+	if strings.HasSuffix(val, "ull") {
+		val = strings.TrimSuffix(val, "ull")
+	}
+	return val
+}
+
+// gltypearg2go converts a C OpenGL function type/argument to a Go argument/type
+// GLfloat *param -> param *float32
+// GLuint type    -> ptype uint
+// void *pixels   -> pixels unsafe.Pointer
+// void **params  -> params *unsafe.Pointer
+func gltypearg2go(gltype, glarg string) (goarg string, gotype string) {
+
+	// Replace parameter names using Go keywords
+	gokeys := []string{"type", "func"}
+	for _, k := range gokeys {
+		if strings.HasSuffix(glarg, k) {
+			glarg = strings.TrimSuffix(glarg, k) + "p" + k
+			break
+		}
+	}
+
+	if gltype == "void" {
+		gotype = "unsafe.Pointer"
+		if strings.HasPrefix(glarg, "**") {
+			goarg = strings.TrimPrefix(glarg, "**")
+			gotype = "*" + gotype
+			return goarg, gotype
+		}
+		if strings.HasPrefix(glarg, "*") {
+			goarg = strings.TrimPrefix(glarg, "*")
+			return goarg, gotype
+		}
+		return "???", "???"
+	}
+
+	goarg = glarg
+	gotype = mapCType2Go[gltype]
+	if strings.HasPrefix(glarg, "*") {
+		gotype = "*" + gotype
+		goarg = strings.TrimPrefix(goarg, "*")
+	}
+	return goarg, gotype
+}
+
+//
+// Shows application usage
+//
+func usage() {
+
+	fmt.Fprintf(os.Stderr, "%s v%d.%d\n", PROGNAME, VMAJOR, VMINOR)
+	fmt.Fprintf(os.Stderr, "usage:%s [options] <glheader>\n", strings.ToLower(PROGNAME))
+	flag.PrintDefaults()
+	os.Exit(2)
+}
+
+func abort(err error) {
+
+	fmt.Fprintf(os.Stderr, "%s\n", err)
+	os.Exit(1)
+}

+ 355 - 0
gls/glapi2go/template.go

@@ -0,0 +1,355 @@
+package main
+
+import (
+	"bytes"
+	"go/format"
+	"os"
+	"text/template"
+)
+
+type GLHeader struct {
+	Defines []GLDefine
+	Funcs   []GLFunc
+}
+
+type GLDefine struct {
+	Name  string
+	Value string
+}
+
+type GLFunc struct {
+	Ptype    string    // type of function pointer (ex: PFNCULLFACEPROC)
+	Spacer   string    // spacer string for formatting
+	Pname    string    // pointer name (ex: pglCullFace)
+	Rtype    string    // return type (ex: void)
+	Fname    string    // name of function (ex: glCullFace)
+	FnameGo  string    // name of function without the "gl" prefix
+	CParams  string    // list of comma C parameter types and names ex:"GLenum mode, GLint x"
+	Args     string    // list of comma separated argument names ex:"x, y, z"
+	GoParams string    // list of comma separated Go parameters ex:"x float32, y float32"
+	Params   []GLParam // array of function parameters
+}
+
+type GLParam struct {
+	Qualif string // optional parameter qualifier (ex: const)
+	CType  string // parameter C type
+	Arg    string // parameter name without pointer operator
+	Name   string // parameter name with possible pointer operator
+}
+
+// genFile generates file from the specified template
+func genFile(templText string, td *GLHeader, fout string, gosrc bool) error {
+
+	// Parses the template
+	tmpl := template.New("tmpl")
+	tmpl, err := tmpl.Parse(templText)
+	if err != nil {
+		return err
+	}
+
+	// Expands template to buffer
+	var buf bytes.Buffer
+	err = tmpl.Execute(&buf, &td)
+	if err != nil {
+		return err
+	}
+	text := buf.Bytes()
+
+	// Creates output file
+	f, err := os.Create(fout)
+	if err != nil {
+		return nil
+	}
+
+	// If requested, formats generated text as Go source
+	if gosrc {
+		src, err := format.Source(text)
+		if err != nil {
+			return err
+		}
+		text = src
+	}
+
+	// Writes source to output file
+	_, err = f.Write(text)
+	if err != nil {
+		return err
+	}
+	return f.Close()
+}
+
+//
+// Template for glapi C file
+//
+const templGLAPIC = `
+// This file was generated automatically by "glapi2go" and contains functions to
+// open the platform's OpenGL dll/shared library and to load all OpenGL function
+// pointers for an specified OpenGL version described by the header file "glcorearb.h",
+// from "https://www.khronos.org/registry/OpenGL/api/GL/glcorearb.h".
+//
+// As Go cgo cannot call directly to C pointers it also creates C function wrappers
+// for all loaded OpenGL pointers.
+// The code was heavily based on "https://github.com/skaslev/gl3w"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "glapi.h"
+
+//
+// OpenGL function loader for Windows
+//
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN 1
+#include <windows.h>
+#undef near
+#undef far
+
+static HMODULE libgl;
+
+// open_libgl opens the OpenGL dll for Windows
+static int open_libgl(void) {
+
+	libgl = LoadLibraryA("opengl32.dll");
+	if (libgl == NULL) {
+		return -1;
+	}
+	return 0;
+}
+
+// close_libgl closes the OpenGL dll object for Windows
+static void close_libgl(void) {
+
+	FreeLibrary(libgl);
+}
+
+// get_proc gets the pointer for an OpenGL function for Windows
+static void* get_proc(const char *proc) {
+
+	void* res;
+	res = (void*)wglGetProcAddress(proc);
+	if (!res) {
+		res = (void*)GetProcAddress(libgl, proc);
+	}
+	return res;
+}
+
+//
+// OpenGL function loader for Mac OS
+//
+#elif defined(__APPLE__) || defined(__APPLE_CC__)
+#include <Carbon/Carbon.h>
+
+CFBundleRef bundle;
+CFURLRef bundleURL;
+
+// open_libgl opens the OpenGL shared object for OSX
+static void open_libgl(void) {
+
+	bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
+		CFSTR("/System/Library/Frameworks/OpenGL.framework"),
+		kCFURLPOSIXPathStyle, true);
+
+	bundle = CFBundleCreate(kCFAllocatorDefault, bundleURL);
+	assert(bundle != NULL);
+}
+
+// close_libgl closes the OpenGL shared object object for OSX
+static void close_libgl(void) {
+
+	CFRelease(bundle);
+	CFRelease(bundleURL);
+}
+
+// get_proc gets the pointer for an OpenGL function for OSX
+static void* get_proc(const char *proc) {
+
+	void* res;
+	CFStringRef procname = CFStringCreateWithCString(kCFAllocatorDefault, proc,
+		kCFStringEncodingASCII);
+	*(void **)(&res) = CFBundleGetFunctionPointerForName(bundle, procname);
+	CFRelease(procname);
+	return res;
+}
+
+//
+// OpenGL function loader for Linux, Unix*
+//
+#else
+#include <dlfcn.h>
+#include <GL/glx.h>
+
+static void *libgl;
+static PFNGLXGETPROCADDRESSPROC glx_get_proc_address;
+
+// open_libgl opens the OpenGL shared object for Linux/Freebsd
+static int open_libgl(void) {
+
+	libgl = dlopen("libGL.so.1", RTLD_LAZY | RTLD_GLOBAL);
+	if (libgl == NULL) {
+		return -1;
+	}
+	*(void **)(&glx_get_proc_address) = dlsym(libgl, "glXGetProcAddressARB");
+	if (glx_get_proc_address == NULL) {
+		return -1;
+	}
+	return 0;
+}
+
+// close_libgl closes the OpenGL shared object for Linux/Freebsd
+static void close_libgl(void) {
+
+	dlclose(libgl);
+}
+
+// get_proc gets the pointer for an OpenGL function for Linux/Freebsd
+static void* get_proc(const char *proc) {
+
+	void* res;
+	res = glx_get_proc_address((const GLubyte *)proc);
+	if (!res) {
+		*(void **)(&res) = dlsym(libgl, proc);
+	}
+	return res;
+}
+#endif
+
+// Internal global flag to check error from OpenGL functions
+static int checkError = 1;
+
+// Declaration of internal function for loading OpenGL function pointers
+static void load_procs();
+
+//
+// glapiLoad() tries to load functions addresses from the OpenGL library
+//
+int glapiLoad(void) {
+
+	int res = open_libgl();
+	if (res != 0) {
+		return res;
+	}
+	load_procs();
+	close_libgl();
+	return 0;
+}
+
+//
+// glapiCheckError sets the state of the internal flag which determines
+// if error checking must be done for OpenGL calls
+//
+void glapiCheckError(int check) {
+
+	checkError = check;
+}
+
+// Internal function to abort process when error
+static void panic(GLenum err, const char* fname) {
+
+	printf("\nGLAPI Error: %d calling: %s\n", err, fname);
+	exit(1);
+}
+
+
+//
+// Definitions of function pointers variables
+//
+{{- range .Funcs}}
+static {{.Ptype}} {{.Spacer}} {{.Pname}};
+{{- end}}
+
+//
+// load_procs loads all gl functions addresses into the pointers
+//
+static void load_procs() {
+
+	{{range .Funcs}}
+	{{- .Pname}} = ({{.Ptype}})get_proc("{{.Fname}}"); 
+	{{end}}
+}
+
+//
+// Definitions of C wrapper functions for all OpenGL loaded pointers
+// which call the pointer and optionally cals glGetError() to check
+// for OpenGL errors.
+//
+{{range .Funcs}}
+{{.Rtype}} {{.Fname}} ({{.CParams}}) {
+
+	{{if ne .Rtype "void"}}
+		{{- .Rtype}} res = {{.Pname}}({{.Args}});
+	{{else}}
+		{{- .Pname}}({{.Args}});
+	{{end -}}
+	if (checkError) {
+		GLenum err = pglGetError();
+		if (err != GL_NO_ERROR) {
+			panic(err, "{{.Fname}}");
+		}
+	}
+	{{if ne .Rtype "void" -}}
+		return res;
+	{{- end}}
+}
+{{end}}
+
+`
+
+//
+// Template for glapi.h file
+//
+const templGLAPIH = `
+// This file was generated automatically by "glapi2go" and contains declarations
+// of public functions from "glapli.c".
+
+#ifndef _glapi_h_
+#define _glapi_h_
+
+#include "glcorearb.h"
+
+// Loads the OpenGL function pointers
+int glapiLoad(void);
+
+// Set the internal flag to enable/disable OpenGL error checking
+void glapiCheckError(int check);
+
+#endif
+`
+
+//
+// Template for glparam.h file
+//
+const templGLPARAMH = `
+#ifndef _glparam_h_
+#define _glparam_h_
+
+#include "glcorearb.h"
+
+//
+// Definition of structures for passing parameters to queued OpenGL functions
+//
+{{range .Funcs}}
+typedef struct {
+{{- range .Params}}
+	{{.CType}} {{.Name -}};
+{{- end}}
+} Param{{.Fname}};
+{{end}}
+
+#endif
+`
+
+//
+// Template for consts.go file
+//
+const templCONSTS = `
+// This file was generated automatically by "glapi2go" and contains all
+// OpenGL constants specified by "#define GL_*" directives contained in
+// "glcorearb.h" for an specific OpenGL version converted to Go constants.
+package gls
+
+const (
+	{{range .Defines}}
+	{{.Name}} = {{.Value -}}
+	{{end}}
+)
+`

File diff suppressed because it is too large
+ 5595 - 0
gls/glcorearb.h


+ 389 - 190
gls/gls.go

@@ -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
 }

+ 12 - 0
gls/logger.go

@@ -0,0 +1,12 @@
+// 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
+
+import (
+	"github.com/g3n/engine/util/logger"
+)
+
+// Package logger
+var log = logger.New("GLS", logger.Default)

+ 37 - 218
gls/program.go

@@ -9,7 +9,6 @@ import (
 	"errors"
 	"fmt"
 	"github.com/g3n/engine/math32"
-	"github.com/go-gl/gl/v3.3-core/gl"
 	"io"
 	"strconv"
 	"strings"
@@ -35,8 +34,8 @@ type shaderInfo struct {
 
 // Map shader types to names
 var shaderNames = map[uint32]string{
-	gl.VERTEX_SHADER:   "Vertex Shader",
-	gl.FRAGMENT_SHADER: "Fragment Shader",
+	VERTEX_SHADER:   "Vertex Shader",
+	FRAGMENT_SHADER: "Fragment Shader",
 }
 
 // NewProgram creates a new empty shader program object.
@@ -75,7 +74,7 @@ func (prog *Program) Build() error {
 	}
 
 	// Create program
-	prog.handle = gl.CreateProgram()
+	prog.handle = prog.gs.CreateProgram()
 	if prog.handle == 0 {
 		return fmt.Errorf("Error creating program")
 	}
@@ -84,7 +83,7 @@ func (prog *Program) Build() error {
 	defer func() {
 		for _, sinfo := range prog.shaders {
 			if sinfo.handle != 0 {
-				gl.DeleteShader(sinfo.handle)
+				prog.gs.DeleteShader(sinfo.handle)
 				sinfo.handle = 0
 			}
 		}
@@ -112,9 +111,9 @@ func (prog *Program) Build() error {
 		}
 		deftext := strings.Join(deflines, "\n")
 		// Compile shader
-		shader, err := CompileShader(sinfo.stype, sinfo.source+deftext)
+		shader, err := prog.CompileShader(sinfo.stype, sinfo.source+deftext)
 		if err != nil {
-			gl.DeleteProgram(prog.handle)
+			prog.gs.DeleteProgram(prog.handle)
 			prog.handle = 0
 			msg := fmt.Sprintf("Error compiling %s: %s", shaderNames[sinfo.stype], err)
 			if prog.ShowSource {
@@ -124,18 +123,15 @@ func (prog *Program) Build() error {
 			return errors.New(msg)
 		}
 		sinfo.handle = shader
-		gl.AttachShader(prog.handle, shader)
+		prog.gs.AttachShader(prog.handle, shader)
 	}
 
 	// Link program and checks for errors
-	gl.LinkProgram(prog.handle)
+	prog.gs.LinkProgram(prog.handle)
 	var status int32
-	gl.GetProgramiv(prog.handle, gl.LINK_STATUS, &status)
-	if status == gl.FALSE {
-		var logLength int32
-		gl.GetProgramiv(prog.handle, gl.INFO_LOG_LENGTH, &logLength)
-		log := strings.Repeat("\x00", int(logLength+1))
-		gl.GetProgramInfoLog(prog.handle, logLength, nil, gl.Str(log))
+	prog.gs.GetProgramiv(prog.handle, LINK_STATUS, &status)
+	if status == FALSE {
+		log := prog.gs.GetProgramInfoLog(prog.handle)
 		prog.handle = 0
 		return fmt.Errorf("Error linking program: %v", log)
 	}
@@ -149,80 +145,11 @@ func (prog *Program) Handle() uint32 {
 	return prog.handle
 }
 
-// GetActiveUniformBlockSize returns the minimum number of bytes
-// to contain the data for the uniform block specified by its index.
-func (prog *Program) GetActiveUniformBlockSize(ubindex uint32) int32 {
-
-	var uboSize int32
-	gl.GetActiveUniformBlockiv(prog.handle, ubindex, gl.UNIFORM_BLOCK_DATA_SIZE, &uboSize)
-	if prog.gs.CheckErrors() {
-		ecode := gl.GetError()
-		if ecode != 0 {
-			log.Fatal("GetUniformBlockSize(%v) error: %d", ubindex, ecode)
-		}
-	}
-	return uboSize
-}
-
-// GetActiveUniformsiv returns information about the specified uniforms
-// specified by its indices
-func (prog *Program) GetActiveUniformsiv(indices []uint32, pname uint32) []int32 {
-
-	data := make([]int32, len(indices))
-	gl.GetActiveUniformsiv(prog.handle, int32(len(indices)), &indices[0], pname, &data[0])
-	if prog.gs.CheckErrors() {
-		ecode := gl.GetError()
-		if ecode != 0 {
-			log.Fatal("GetActiveUniformsiv() error: %d", ecode)
-		}
-	}
-	return data
-}
-
 // GetAttributeLocation returns the location of the specified attribute
 // in this program. This location is internally cached.
 func (prog *Program) GetAttribLocation(name string) int32 {
 
-	loc := gl.GetAttribLocation(prog.handle, gl.Str(name+"\x00"))
-	prog.gs.checkError("GetAttribLocation")
-	return loc
-}
-
-// GetUniformBlockIndex returns the index of the named uniform block.
-// If the supplied name is not valid, the function returns gl.INVALID_INDEX
-func (prog *Program) GetUniformBlockIndex(name string) uint32 {
-
-	index := gl.GetUniformBlockIndex(prog.handle, gl.Str(name+"\x00"))
-	if prog.gs.CheckErrors() {
-		ecode := gl.GetError()
-		if ecode != 0 {
-			log.Fatal("GetUniformBlockIndex(%s) error", name)
-		}
-	}
-	return index
-}
-
-// GetUniformIndices returns the indices for each specified named
-// uniform. If an specified name is not valid the corresponding
-// index value will be gl.INVALID_INDEX
-func (prog *Program) GetUniformIndices(names []string) []uint32 {
-
-	// Add C terminators to uniform names
-	for _, s := range names {
-		s += "\x00"
-	}
-	unames, freefunc := gl.Strs(names...)
-
-	indices := make([]uint32, len(names))
-	gl.GetUniformIndices(prog.handle, int32(len(names)), unames, &indices[0])
-	if prog.gs.CheckErrors() {
-		ecode := gl.GetError()
-		if ecode != 0 {
-			log.Fatal("GetUniformIndices() error: %d", ecode)
-		}
-	}
-	freefunc()
-	return indices
+	return prog.gs.GetAttribLocation(prog.handle, name)
 }
 
 // GetUniformLocation returns the location of the specified uniform in this program.
@@ -235,13 +162,7 @@ func (prog *Program) GetUniformLocation(name string) int32 {
 		return loc
 	}
 	// Get location from GL
-	loc = gl.GetUniformLocation(prog.handle, gl.Str(name+"\x00"))
-	if prog.gs.CheckErrors() {
-		ecode := gl.GetError()
-		if ecode != 0 {
-			log.Fatal("GetUniformLocation(%s) error: %d", name, ecode)
-		}
-	}
+	loc = prog.gs.GetUniformLocation(prog.handle, name)
 	// Cache result
 	prog.uniforms[name] = loc
 	if loc < 0 {
@@ -254,91 +175,49 @@ func (prog *Program) GetUniformLocation(name string) int32 {
 // its location to the the value of the specified int
 func (prog *Program) SetUniformInt(loc int32, v int) {
 
-	gl.Uniform1i(loc, int32(v))
-	if prog.gs.CheckErrors() {
-		ecode := gl.GetError()
-		if ecode != 0 {
-			log.Fatal("SetUniformInt() error: %d", ecode)
-		}
-	}
+	prog.gs.Uniform1i(loc, int32(v))
 }
 
 // SetUniformFloat sets this program uniform variable specified by
 // its location to the the value of the specified float
 func (prog *Program) SetUniformFloat(loc int32, v float32) {
 
-	gl.Uniform1f(loc, v)
-	if prog.gs.CheckErrors() {
-		ecode := gl.GetError()
-		if ecode != 0 {
-			log.Fatal("SetUniformFloat() error: %d", ecode)
-		}
-	}
+	prog.gs.Uniform1f(loc, v)
 }
 
 // SetUniformVector2 sets this program uniform variable specified by
 // its location to the the value of the specified Vector2
 func (prog *Program) SetUniformVector2(loc int32, v *math32.Vector2) {
 
-	gl.Uniform2f(loc, v.X, v.Y)
-	if prog.gs.CheckErrors() {
-		ecode := gl.GetError()
-		if ecode != 0 {
-			log.Fatal("SetUniformVector2() error: %d", ecode)
-		}
-	}
+	prog.gs.Uniform2f(loc, v.X, v.Y)
 }
 
 // SetUniformVector3 sets this program uniform variable specified by
 // its location to the the value of the specified Vector3
 func (prog *Program) SetUniformVector3(loc int32, v *math32.Vector3) {
 
-	gl.Uniform3f(loc, v.X, v.Y, v.Z)
-	if prog.gs.CheckErrors() {
-		ecode := gl.GetError()
-		if ecode != 0 {
-			log.Fatal("SetUniformVector3() error: %d", ecode)
-		}
-	}
+	prog.gs.Uniform3f(loc, v.X, v.Y, v.Z)
 }
 
 // SetUniformVector4 sets this program uniform variable specified by
 // its location to the the value of the specified Vector4
 func (prog *Program) SetUniformVector4(loc int32, v *math32.Vector4) {
 
-	gl.Uniform4f(loc, v.X, v.Y, v.Z, v.W)
-	if prog.gs.CheckErrors() {
-		ecode := gl.GetError()
-		if ecode != 0 {
-			log.Fatal("SetUniformVector4() error: %d", ecode)
-		}
-	}
+	prog.gs.Uniform4f(loc, v.X, v.Y, v.Z, v.W)
 }
 
 // SetUniformMatrix3 sets this program uniform variable specified by
 // its location with the values from the specified Matrix3.
 func (prog *Program) SetUniformMatrix3(loc int32, m *math32.Matrix3) {
 
-	gl.UniformMatrix3fv(loc, 1, false, &m[0])
-	if prog.gs.CheckErrors() {
-		ecode := gl.GetError()
-		if ecode != 0 {
-			log.Fatal("SetUniformMatrix3() error: %d", ecode)
-		}
-	}
+	prog.gs.UniformMatrix3fv(loc, 1, false, &m[0])
 }
 
 // SetUniformMatrix4 sets this program uniform variable specified by
 // its location with the values from the specified Matrix4.
 func (prog *Program) SetUniformMatrix4(loc int32, m *math32.Matrix4) {
 
-	gl.UniformMatrix4fv(loc, 1, false, &m[0])
-	if prog.gs.CheckErrors() {
-		ecode := gl.GetError()
-		if ecode != 0 {
-			log.Fatal("SetUniformMatrix4() error: %d", ecode)
-		}
-	}
+	prog.gs.UniformMatrix4fv(loc, 1, false, &m[0])
 }
 
 // SetUniformIntByName sets this program uniform variable specified by
@@ -346,13 +225,7 @@ func (prog *Program) SetUniformMatrix4(loc int32, m *math32.Matrix4) {
 // The specified name location is cached internally.
 func (prog *Program) SetUniformIntByName(name string, v int) {
 
-	gl.Uniform1i(prog.GetUniformLocation(name), int32(v))
-	if prog.gs.CheckErrors() {
-		ecode := gl.GetError()
-		if ecode != 0 {
-			log.Fatal("GetUniformIntByName(%s) error: %d", name, ecode)
-		}
-	}
+	prog.gs.Uniform1i(prog.GetUniformLocation(name), int32(v))
 }
 
 // SetUniformFloatByName sets this program uniform variable specified by
@@ -360,13 +233,7 @@ func (prog *Program) SetUniformIntByName(name string, v int) {
 // The specified name location is cached internally.
 func (prog *Program) SetUniformFloatByName(name string, v float32) {
 
-	gl.Uniform1f(prog.GetUniformLocation(name), v)
-	if prog.gs.CheckErrors() {
-		ecode := gl.GetError()
-		if ecode != 0 {
-			log.Fatal("SetUniformFloatByName(%s) error: %d", name, ecode)
-		}
-	}
+	prog.gs.Uniform1f(prog.GetUniformLocation(name), v)
 }
 
 // SetUniformVector2ByName sets this program uniform variable specified by
@@ -374,13 +241,7 @@ func (prog *Program) SetUniformFloatByName(name string, v float32) {
 // The specified name location is cached internally.
 func (prog *Program) SetUniformVector2ByName(name string, v *math32.Vector2) {
 
-	gl.Uniform2f(prog.GetUniformLocation(name), v.X, v.Y)
-	if prog.gs.CheckErrors() {
-		ecode := gl.GetError()
-		if ecode != 0 {
-			log.Fatal("SetUniformVector2ByName(%s) error: %d", name, ecode)
-		}
-	}
+	prog.gs.Uniform2f(prog.GetUniformLocation(name), v.X, v.Y)
 }
 
 // SetUniformVector3ByName sets this program uniform variable specified by
@@ -388,13 +249,7 @@ func (prog *Program) SetUniformVector2ByName(name string, v *math32.Vector2) {
 // The specified name location is cached internally.
 func (prog *Program) SetUniformVector3ByName(name string, v *math32.Vector3) {
 
-	gl.Uniform3f(prog.GetUniformLocation(name), v.X, v.Y, v.Z)
-	if prog.gs.CheckErrors() {
-		ecode := gl.GetError()
-		if ecode != 0 {
-			log.Fatal("SetUniformVector3ByName(%s) error: %d", name, ecode)
-		}
-	}
+	prog.gs.Uniform3f(prog.GetUniformLocation(name), v.X, v.Y, v.Z)
 }
 
 // SetUniformVector4ByName sets this program uniform variable specified by
@@ -402,13 +257,7 @@ func (prog *Program) SetUniformVector3ByName(name string, v *math32.Vector3) {
 // The specified name location is cached internally.
 func (prog *Program) SetUniformVector4ByName(name string, v *math32.Vector4) {
 
-	gl.Uniform4f(prog.GetUniformLocation(name), v.X, v.Y, v.Z, v.W)
-	if prog.gs.CheckErrors() {
-		ecode := gl.GetError()
-		if ecode != 0 {
-			log.Fatal("SetUniformVector4ByName(%s) error: %d", name, ecode)
-		}
-	}
+	prog.gs.Uniform4f(prog.GetUniformLocation(name), v.X, v.Y, v.Z, v.W)
 }
 
 // SetUniformMatrix3ByName sets this program uniform variable specified by
@@ -416,13 +265,7 @@ func (prog *Program) SetUniformVector4ByName(name string, v *math32.Vector4) {
 // The specified name location is cached internally.
 func (prog *Program) SetUniformMatrix3ByName(name string, m *math32.Matrix3) {
 
-	gl.UniformMatrix3fv(prog.GetUniformLocation(name), 1, false, &m[0])
-	if prog.gs.CheckErrors() {
-		ecode := gl.GetError()
-		if ecode != 0 {
-			log.Fatal("SetUniformMatrix3ByName(%s) error: %d", name, ecode)
-		}
-	}
+	prog.gs.UniformMatrix3fv(prog.GetUniformLocation(name), 1, false, &m[0])
 }
 
 // SetUniformMatrix4ByName sets this program uniform variable specified by
@@ -430,13 +273,7 @@ func (prog *Program) SetUniformMatrix3ByName(name string, m *math32.Matrix3) {
 // The location of the name is cached internally.
 func (prog *Program) SetUniformMatrix4ByName(name string, m *math32.Matrix4) {
 
-	gl.UniformMatrix4fv(prog.GetUniformLocation(name), 1, false, &m[0])
-	if prog.gs.CheckErrors() {
-		ecode := gl.GetError()
-		if ecode != 0 {
-			log.Fatal("SetUniformMatrix4ByName(%s) error: %d", name, ecode)
-		}
-	}
+	prog.gs.UniformMatrix4fv(prog.GetUniformLocation(name), 1, false, &m[0])
 }
 
 // SetUniformColorByName set this program uniform variable specified by
@@ -444,13 +281,7 @@ func (prog *Program) SetUniformMatrix4ByName(name string, m *math32.Matrix4) {
 // The specified name location is cached internally.
 func (prog *Program) SetUniformColorByName(name string, c *math32.Color) {
 
-	gl.Uniform3f(prog.GetUniformLocation(name), c.R, c.G, c.B)
-	if prog.gs.CheckErrors() {
-		ecode := gl.GetError()
-		if ecode != 0 {
-			log.Fatal("SetUniformColorByName(%s) error: %d", name, ecode)
-		}
-	}
+	prog.gs.Uniform3f(prog.GetUniformLocation(name), c.R, c.G, c.B)
 }
 
 // SetUniformColor4ByName set this program uniform variable specified by
@@ -458,43 +289,31 @@ func (prog *Program) SetUniformColorByName(name string, c *math32.Color) {
 // The specified name location is cached internally.
 func (prog *Program) SetUniformColor4ByName(name string, c *math32.Color4) {
 
-	gl.Uniform4f(prog.GetUniformLocation(name), c.R, c.G, c.B, c.A)
-	if prog.gs.CheckErrors() {
-		ecode := gl.GetError()
-		if ecode != 0 {
-			log.Fatal("SetUniformColor4ByName(%s) error: %d", name, ecode)
-		}
-	}
+	prog.gs.Uniform4f(prog.GetUniformLocation(name), c.R, c.G, c.B, c.A)
 }
 
 // CompileShader creates and compiles a shader of the specified type and with
 // the specified source code and returns a non-zero value by which
 // it can be referenced.
-func CompileShader(stype uint32, source string) (uint32, error) {
+func (prog *Program) CompileShader(stype uint32, source string) (uint32, error) {
 
-	shader := gl.CreateShader(stype)
+	// Creates shader object
+	shader := prog.gs.CreateShader(stype)
 	if shader == 0 {
 		return 0, fmt.Errorf("Error creating shader")
 	}
 
-	// Allocates C string to store the source
-	csource, freeSource := gl.Strs(source + "\x00")
-	defer freeSource()
-
 	// Set shader source and compile it
-	gl.ShaderSource(shader, 1, csource, nil)
-	gl.CompileShader(shader)
+	prog.gs.ShaderSource(shader, source)
+	prog.gs.CompileShader(shader)
 
 	// Get the shader compiler log
-	var logLength int32
-	gl.GetShaderiv(shader, gl.INFO_LOG_LENGTH, &logLength)
-	slog := strings.Repeat("\x00", int(logLength+1))
-	gl.GetShaderInfoLog(shader, logLength, nil, gl.Str(slog))
+	slog := prog.gs.GetShaderInfoLog(shader)
 
 	// Get the shader compile status
 	var status int32
-	gl.GetShaderiv(shader, gl.COMPILE_STATUS, &status)
-	if status == gl.FALSE {
+	prog.gs.GetShaderiv(shader, COMPILE_STATUS, &status)
+	if status == FALSE {
 		return shader, fmt.Errorf("%s", slog)
 	}
 

+ 4 - 4
gls/uniform.go

@@ -351,12 +351,12 @@ func (uni *UniformMatrix3f) GetMatrix3() math32.Matrix3 {
 
 func (uni *UniformMatrix3f) Transfer(gl *GLS) {
 
-	gl.UniformMatrix3fv(uni.Location(gl), 1, false, uni.v[0:9])
+	gl.UniformMatrix3fv(uni.Location(gl), 1, false, &uni.v[0])
 }
 
 func (uni *UniformMatrix3f) TransferIdx(gl *GLS, idx int) {
 
-	gl.UniformMatrix3fv(uni.LocationIdx(gl, idx), 1, false, uni.v[0:9])
+	gl.UniformMatrix3fv(uni.LocationIdx(gl, idx), 1, false, &uni.v[0])
 }
 
 //
@@ -392,10 +392,10 @@ func (uni *UniformMatrix4f) GetMatrix4() math32.Matrix4 {
 
 func (uni *UniformMatrix4f) Transfer(gl *GLS) {
 
-	gl.UniformMatrix4fv(uni.Location(gl), 1, false, uni.v[0:16])
+	gl.UniformMatrix4fv(uni.Location(gl), 1, false, &uni.v[0])
 }
 
 func (uni *UniformMatrix4f) TransferIdx(gl *GLS, idx int) {
 
-	gl.UniformMatrix4fv(uni.LocationIdx(gl, idx), 1, false, uni.v[0:16])
+	gl.UniformMatrix4fv(uni.LocationIdx(gl, idx), 1, false, &uni.v[0])
 }