Skip to content
Find file
Fetching contributors…
Cannot retrieve contributors at this time
528 lines (477 sloc) 15.2 KB
// Copyright 2011 The GoGL Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.mkd file.
package main
import (
"fmt"
"io"
"os"
"path/filepath"
"sort"
"strings"
)
func GeneratePackages(packages Packages, functsInfo *FunctionsInfo, typeMap TypeMap, prefix string) error {
for packageName, pak := range packages {
fmt.Printf("Generating package %s ...\n", packageName)
if err := generatePackage(packageName, pak, functsInfo, typeMap, prefix); err != nil {
return err
}
}
return nil
}
func generatePackage(packageName string, pak *Package, functsInfo *FunctionsInfo, typeMap TypeMap, prefix string) error {
absPath, err := filepath.Abs(packageName)
if err != nil {
return err
}
err = os.MkdirAll(absPath, 0755)
if err != nil {
return err
}
w, err := os.Create(filepath.Join(absPath, fmt.Sprintf("%s.go", packageName)))
if err != nil {
return err
}
defer w.Close()
return writePackage(w, packageName, pak, functsInfo, typeMap, prefix)
}
func writePackage(w io.Writer, packageName string, pak *Package, functsInfo *FunctionsInfo, typeMap TypeMap, prefix string) error {
highestMajorVersion := -1
isGLPackage := false
if strings.HasPrefix(packageName, "gl") && !strings.HasPrefix(packageName, "glx") {
isGLPackage = true
}
fmt.Fprintf(w, "// Automatically generated OpenGL binding.\n// \n")
fmt.Fprintf(w, "// Categories in this package: \n// \n")
sortedFunctionCategories := make([]string, len(pak.Functions))
i := 0
for k, _ := range pak.Functions {
sortedFunctionCategories[i] = k
i++
}
sort.Strings(sortedFunctionCategories)
sortedEnumCategories := make([]string, len(pak.Enums))
i = 0
for k, _ := range pak.Enums {
sortedEnumCategories[i] = k
i++
}
sort.Strings(sortedEnumCategories)
for _, cat := range sortedFunctionCategories {
pc, _ := ParseCategoryString(cat)
switch pc.Type {
case CategoryExtension:
fmt.Fprintf(w, "// %s: %s\n// \n", cat, MakeExtensionSpecDocUrl(pc.Vendor, pc.Name))
case CategoryVersion:
fmt.Fprintf(w, "// %s\n// \n", cat)
if pc.Version.Major > highestMajorVersion {
highestMajorVersion = pc.Version.Major
}
case CategoryDepVersion:
fmt.Fprintf(w, "// %s\n// \n", cat)
}
}
if highestMajorVersion > 0 {
fmt.Fprintf(w, "// %s\n// \n", MakeGLDocUrl(highestMajorVersion))
}
fmt.Fprintf(w, "package %s\n\n", packageName)
fmt.Fprintf(w, "// #cgo darwin LDFLAGS: -framework OpenGL\n")
fmt.Fprintf(w, "// #cgo linux LDFLAGS: -lGL\n")
fmt.Fprintf(w, "// #cgo windows LDFLAGS: -lopengl32\n// \n")
fmt.Fprintf(w, "// #include <stdlib.h>\n")
fmt.Fprintf(w, "// #if defined(__APPLE__)\n")
fmt.Fprintf(w, "// #include <dlfcn.h>\n")
fmt.Fprintf(w, "// #elif defined(_WIN32)\n")
fmt.Fprintf(w, "// #define WIN32_LEAN_AND_MEAN 1\n")
fmt.Fprintf(w, "// #include <windows.h>\n")
fmt.Fprintf(w, "// #else\n")
fmt.Fprintf(w, "// #include <X11/Xlib.h>\n")
fmt.Fprintf(w, "// #include <GL/glx.h>\n")
fmt.Fprintf(w, "// #endif\n// \n")
fmt.Fprintf(w, "// #ifndef APIENTRY\n")
fmt.Fprintf(w, "// #define APIENTRY\n")
fmt.Fprintf(w, "// #endif\n")
fmt.Fprintf(w, "// #ifndef APIENTRYP\n")
fmt.Fprintf(w, "// #define APIENTRYP APIENTRY *\n")
fmt.Fprintf(w, "// #endif\n")
fmt.Fprintf(w, "// #ifndef GLAPI\n")
fmt.Fprintf(w, "// #define GLAPI extern\n")
fmt.Fprintf(w, "// #endif\n// \n")
fmt.Fprintf(w, "// typedef unsigned int GLenum;\n")
fmt.Fprintf(w, "// typedef unsigned char GLboolean;\n")
fmt.Fprintf(w, "// typedef unsigned int GLbitfield;\n")
fmt.Fprintf(w, "// typedef signed char GLbyte;\n")
fmt.Fprintf(w, "// typedef short GLshort;\n")
fmt.Fprintf(w, "// typedef int GLint;\n")
fmt.Fprintf(w, "// typedef int GLsizei;\n")
fmt.Fprintf(w, "// typedef unsigned char GLubyte;\n")
fmt.Fprintf(w, "// typedef unsigned short GLushort;\n")
fmt.Fprintf(w, "// typedef unsigned int GLuint;\n")
fmt.Fprintf(w, "// typedef unsigned short GLhalf;\n")
fmt.Fprintf(w, "// typedef float GLfloat;\n")
fmt.Fprintf(w, "// typedef float GLclampf;\n")
fmt.Fprintf(w, "// typedef double GLdouble;\n")
fmt.Fprintf(w, "// typedef double GLclampd;\n")
fmt.Fprintf(w, "// typedef void GLvoid;\n// \n")
for _, passthrus := range functsInfo.Passthru["global"] {
fmt.Fprintf(w, "// %s\n", passthrus)
}
fmt.Fprintf(w, "// #ifdef _WIN32\n")
fmt.Fprintf(w, "// static HMODULE opengl32 = NULL;\n")
fmt.Fprintf(w, "// #endif\n// \n")
fmt.Fprintf(w, "// static void* go%sGetProcAddress(const char* name) { \n", prefix)
fmt.Fprintf(w, "// #ifdef __APPLE__\n")
fmt.Fprintf(w, "// return dlsym(RTLD_DEFAULT, name);\n")
fmt.Fprintf(w, "// #elif _WIN32\n")
fmt.Fprintf(w, "// void* pf = wglGetProcAddress((LPCSTR)name);\n")
fmt.Fprintf(w, "// if(pf) {\n")
fmt.Fprintf(w, "// return pf;\n")
fmt.Fprintf(w, "// }\n")
fmt.Fprintf(w, "// if(opengl32 == NULL) {\n")
fmt.Fprintf(w, "// opengl32 = LoadLibraryA(\"opengl32.dll\");\n")
fmt.Fprintf(w, "// }\n")
fmt.Fprintf(w, "// return GetProcAddress(opengl32, (LPCSTR)name);\n")
fmt.Fprintf(w, "// #else\n")
fmt.Fprintf(w, "// return glXGetProcAddress((const GLubyte*)name);\n")
fmt.Fprintf(w, "// #endif\n")
fmt.Fprintf(w, "// }\n// \n")
if err := writeCFuncDeclarations(w, sortedFunctionCategories, pak.Functions, typeMap, prefix); err != nil {
return err
}
if err := writeCFuncDefinitions(w, sortedFunctionCategories, pak.Functions, typeMap, prefix); err != nil {
return err
}
if err := writeCFuncGetProcAddrs(w, sortedFunctionCategories, pak.Functions, prefix); err != nil {
return err
}
fmt.Fprintf(w, "import \"C\"\n")
fmt.Fprintf(w, "import \"unsafe\"\n")
fmt.Fprintf(w, "import \"errors\"\n\n")
fmt.Fprintf(w, "type (\n")
fmt.Fprintf(w, " Enum C.GLenum\n")
fmt.Fprintf(w, " Boolean C.GLboolean\n")
fmt.Fprintf(w, " Bitfield C.GLbitfield\n")
fmt.Fprintf(w, " Byte C.GLbyte\n")
fmt.Fprintf(w, " Short C.GLshort\n")
fmt.Fprintf(w, " Int C.GLint\n")
fmt.Fprintf(w, " Sizei C.GLsizei\n")
fmt.Fprintf(w, " Ubyte C.GLubyte\n")
fmt.Fprintf(w, " Ushort C.GLushort\n")
fmt.Fprintf(w, " Uint C.GLuint\n")
fmt.Fprintf(w, " Half C.GLhalf\n")
fmt.Fprintf(w, " Float C.GLfloat\n")
fmt.Fprintf(w, " Clampf C.GLclampf\n")
fmt.Fprintf(w, " Double C.GLdouble\n")
fmt.Fprintf(w, " Clampd C.GLclampd\n")
fmt.Fprintf(w, " Char C.GLchar\n")
fmt.Fprintf(w, " Pointer unsafe.Pointer\n")
fmt.Fprintf(w, " Sync C.GLsync\n")
fmt.Fprintf(w, " Int64 C.GLint64\n")
fmt.Fprintf(w, " Uint64 C.GLuint64\n")
fmt.Fprintf(w, " Intptr C.GLintptr\n")
fmt.Fprintf(w, " Sizeiptr C.GLsizeiptr\n")
fmt.Fprintf(w, ")\n\n")
writeGoEnumDefinitions(w, sortedEnumCategories, pak.Enums)
if err := writeGoFuncDefinitions(w, sortedFunctionCategories, pak.Functions, typeMap, highestMajorVersion, prefix); err != nil {
return err
}
writeGoInitDefinitions(w, sortedFunctionCategories, pak.Functions, isGLPackage)
if isGLPackage {
writeUtilityFunctions(w)
}
fmt.Fprintf(w, "// EOF")
return nil
}
func writeCFuncDeclarations(w io.Writer, sortedFunctionCategories []string, functions FunctionCategories, typeMap TypeMap, prefix string) error {
for _, cat := range sortedFunctionCategories {
fs := functions[cat]
fmt.Fprintf(w, "// // %s\n", cat)
for _, f := range fs {
if err := writeCFuncDeclaration(w, f, typeMap, prefix, false); err != nil {
return err
}
}
}
fmt.Fprintf(w, "// \n")
return nil
}
func writeCFuncDeclaration(w io.Writer, f *Function, typeMap TypeMap, prefix string, prototype bool) error {
rtype, err := typeMap.Resolve(f.Return)
if err != nil {
return err
}
if prototype {
fmt.Fprintf(w, "// GLAPI %s APIENTRY %s%s(", rtype, prefix, f.Name)
} else {
fmt.Fprintf(w, "// %s (APIENTRYP ptr%s%s)(", rtype, prefix, f.Name)
}
for i, _ := range f.Parameters {
p := &f.Parameters[i]
ptype, err := typeMap.Resolve(p.Type)
if err != nil {
return err
}
fmt.Fprintf(w, "%s", ptype)
if p.Out || (p.Modifier == ParamModifierReference || p.Modifier == ParamModifierArray) {
fmt.Fprint(w, "*")
}
fmt.Fprintf(w, " %s", p.Name)
if i < len(f.Parameters)-1 {
fmt.Fprintf(w, ", ")
}
}
fmt.Fprintf(w, ");\n")
return nil
}
func writeCFuncDefinitions(w io.Writer, sortedFunctionCategories []string, functions FunctionCategories, typeMap TypeMap, prefix string) error {
for _, cat := range sortedFunctionCategories {
fs := functions[cat]
fmt.Fprintf(w, "// // %s\n", cat)
for _, f := range fs {
if err := writeCFuncDefinition(w, f, typeMap, prefix, false); err != nil {
return err
}
}
}
fmt.Fprintf(w, "// \n")
return nil
}
func writeCFuncDefinition(w io.Writer, f *Function, typeMap TypeMap, prefix string, prototype bool) error {
rtype, err := typeMap.Resolve(f.Return)
if err != nil {
return err
}
fmt.Fprintf(w, "// %s go%s%s(", rtype, prefix, f.Name)
for i, _ := range f.Parameters {
p := &f.Parameters[i]
ptype, err := typeMap.Resolve(p.Type)
if err != nil {
return err
}
fmt.Fprintf(w, "%s", ptype)
if p.Out || (p.Modifier == ParamModifierReference || p.Modifier == ParamModifierArray) {
fmt.Fprint(w, "*")
}
fmt.Fprintf(w, " %s", RenameIfReservedWord(p.Name))
if i < len(f.Parameters)-1 {
fmt.Fprintf(w, ", ")
}
}
fmt.Fprintf(w, ") {\n")
if rtype == "void" || rtype == "VOID" {
fmt.Fprintf(w, "// ")
} else {
fmt.Fprintf(w, "// return ")
}
if prototype {
fmt.Fprintf(w, "%s%s(", prefix, f.Name)
} else {
fmt.Fprintf(w, "(*ptr%s%s)(", prefix, f.Name)
}
for i, _ := range f.Parameters {
p := &f.Parameters[i]
fmt.Fprintf(w, "%s", RenameIfReservedWord(p.Name))
if i < len(f.Parameters)-1 {
fmt.Fprintf(w, ", ")
}
}
fmt.Fprintf(w, ");\n// }\n")
return nil
}
func writeCFuncGetProcAddrs(w io.Writer, sortedFunctionCategories []string, functions FunctionCategories, prefix string) error {
for _, cat := range sortedFunctionCategories {
fs := functions[cat]
fmt.Fprintf(w, "// int init_%s() {\n", cat)
for _, f := range fs {
fmt.Fprintf(w, "// ptr%s%s = go%sGetProcAddress(\"%s%s\");\n", prefix, f.Name, prefix, prefix, f.Name)
fmt.Fprintf(w, "// if(ptr%s%s == NULL) return 1;\n", prefix, f.Name)
}
fmt.Fprintf(w, "// \treturn 0;\n")
fmt.Fprintf(w, "// }\n")
}
fmt.Fprintf(w, "// \n")
return nil
}
func writeGoEnumDefinitions(w io.Writer, sortedEnumCategories []string, enumCats EnumCategories) {
for _, cat := range sortedEnumCategories {
enums := enumCats[cat]
fmt.Fprintf(w, "// %s\n", cat)
fmt.Fprintf(w, "const (\n")
sortedEnums := make([]string, len(enums))
i := 0
for k, _ := range enums {
sortedEnums[i] = k
i++
}
sort.Strings(sortedEnums)
for _, e := range sortedEnums {
v := enums[e]
if !enumCats.IsAlreadyDefined(e, cat) {
fmt.Fprintf(w, "\t%s = %s\n", CleanEnumName(e), v)
}
}
fmt.Fprintf(w, ")\n")
}
}
func writeGoFuncDefinitions(w io.Writer, sortedFunctionCategories []string, functions FunctionCategories, typeMap TypeMap, majorVersion int, prefix string) error {
for _, cat := range sortedFunctionCategories {
fs := functions[cat]
fmt.Fprintf(w, "// %s\n\n", cat)
for _, f := range fs {
if err := writeGoFuncDefinition(w, f, typeMap, majorVersion, prefix, false); err != nil {
return err
}
}
}
return nil
}
func writeGoFuncDefinition(w io.Writer, f *Function, typeMap TypeMap, majorVersion int, prefix string, prototype bool) error {
if majorVersion > 0 {
fmt.Fprintf(w, "// %s\n", MakeFuncDocUrl(majorVersion, f.Name))
}
fmt.Fprintf(w, "func %s(", f.Name)
for i, _ := range f.Parameters {
p := &f.Parameters[i]
fmt.Fprintf(w, "%s ", RenameIfReservedWord(p.Name))
ptype, err := typeMap.Resolve(p.Type)
if err != nil {
return err
}
goType, _, err := CTypeToGoType(ptype, p.Out, p.Modifier)
if err != nil {
return err
}
fmt.Fprintf(w, "%s", goType)
if i < len(f.Parameters)-1 {
fmt.Fprintf(w, ", ")
}
}
rtype, err := typeMap.Resolve(f.Return)
if err != nil {
return err
}
goType, _, err := CTypeToGoType(rtype, false, ParamModifierValue)
if err != nil {
return err
}
fmt.Fprintf(w, ") %s {\n", goType)
if rtype == "void" || rtype == "VOID" {
if prototype {
fmt.Fprintf(w, " C.%s%s(", prefix, f.Name)
} else {
fmt.Fprintf(w, " C.go%s%s(", prefix, f.Name)
}
} else {
if prototype {
fmt.Fprintf(w, " return (%s)(C.%s%s(", goType, prefix, f.Name)
} else {
fmt.Fprintf(w, " return (%s)(C.go%s%s(", goType, prefix, f.Name)
}
}
for i, _ := range f.Parameters {
p := &f.Parameters[i]
ptype, err := typeMap.Resolve(p.Type)
if err != nil {
return err
}
_, cgoType, err := CTypeToGoType(ptype, p.Out, p.Modifier)
if err != nil {
return err
}
// HACK: handling pointers to pointers is tricky. We use unsafe.Pointer. Any better solution?
if strings.HasPrefix(cgoType, "**") {
fmt.Fprintf(w, "(%s)(unsafe.Pointer(%s))", cgoType, RenameIfReservedWord(p.Name))
} else {
fmt.Fprintf(w, "(%s)(%s)", cgoType, RenameIfReservedWord(p.Name))
}
if i < len(f.Parameters)-1 {
fmt.Fprintf(w, ", ")
}
}
if rtype == "void" || rtype == "VOID" {
fmt.Fprintf(w, ")\n}\n")
} else {
fmt.Fprintf(w, "))\n}\n")
}
return nil
}
func writeGoInitDefinitions(w io.Writer, sortedFunctionCategories []string, functions FunctionCategories, initAll bool) error {
for _, cat := range sortedFunctionCategories {
fmt.Fprintf(w, "func Init%s() error {\n", GoName(cat))
fmt.Fprintf(w, "\tvar ret C.int\n")
fmt.Fprintf(w, "\tif ret = C.init_%s(); ret != 0 {\n", cat)
fmt.Fprintf(w, "\t\treturn errors.New(\"unable to initialize %s\")\n", cat)
fmt.Fprintf(w, "\t}\n")
fmt.Fprintf(w, "\treturn nil\n")
fmt.Fprintf(w, "}\n")
}
if initAll {
fmt.Fprintf(w, "func Init() error {\n")
fmt.Fprintf(w, "\tvar err error\n")
for _, cat := range sortedFunctionCategories {
fmt.Fprintf(w, "\tif err = Init%s(); err != nil {\n", GoName(cat))
fmt.Fprintf(w, "\t\treturn err\n")
fmt.Fprintf(w, "\t}\n")
}
fmt.Fprintf(w, "\treturn nil\n")
fmt.Fprintf(w, "}\n")
}
return nil
}
func writeUtilityFunctions(w io.Writer) {
fmt.Fprintln(w, `//Go bool to GL boolean.
func GLBool(b bool) Boolean {
if b {
return TRUE
}
return FALSE
}
// GL boolean to Go bool.
func GoBool(b Boolean) bool {
return b == TRUE
}
// Go string to GL string.
func GLString(str string) *Char {
return (*Char)(C.CString(str))
}
// Allocates a GL string.
func GLStringAlloc(length Sizei) *Char {
return (*Char)(C.malloc(C.size_t(length)))
}
// Frees GL string.
func GLStringFree(str *Char) {
C.free(unsafe.Pointer(str))
}
// GL string (GLchar*) to Go string.
func GoString(str *Char) string {
return C.GoString((*C.char)(str))
}
// GL string (GLubyte*) to Go string.
func GoStringUb(str *Ubyte) string {
return C.GoString((*C.char)(unsafe.Pointer(str)))
}
// GL string (GLchar*) with length to Go string.
func GoStringN(str *Char, length Sizei) string {
return C.GoStringN((*C.char)(str), C.int(length))
}
// Converts a list of Go strings to a slice of GL strings.
// Usefull for ShaderSource().
func GLStringArray(strs ...string) []*Char {
strSlice := make([]*Char, len(strs))
for i, s := range strs {
strSlice[i] = (*Char)(C.CString(s))
}
return strSlice
}
// Free GL string slice allocated by GLStringArray().
func GLStringArrayFree(strs []*Char) {
for _, s := range strs {
C.free(unsafe.Pointer(s))
}
}
// Add offset to a pointer. Usefull for VertexAttribPointer, TexCoordPointer, NormalPointer, ...
func Offset(p Pointer, o uintptr) Pointer {
return Pointer(uintptr(p) + o)
}
`)
}
Something went wrong with that request. Please try again.