diff --git a/functions.go b/functions.go index 4a1f6e0..85b5839 100644 --- a/functions.go +++ b/functions.go @@ -1,6 +1,9 @@ package main -import "fmt" +import ( + "fmt" + "strings" +) // A Function definition. type Function struct { @@ -10,6 +13,33 @@ type Function struct { Return Type } +// IsImplementedForSyscall reports whether the function is implemented for syscall or not. +func (f Function) IsImplementedForSyscall() bool { + // TODO: Use syscall.Syscall18 when Go 1.12 is the minimum supported version. + if len(f.Parameters) > 15 { + return false + } + return true +} + +// Syscall returns a syscall expression for Windows. +func (f Function) Syscall() string { + var ps []string + for _, p := range f.Parameters { + ps = append(ps, p.Type.ConvertGoToUintptr(p.GoName())) + } + for len(ps) == 0 || len(ps)%3 != 0 { + ps = append(ps, "0") + } + + post := "" + if len(ps) > 3 { + post = fmt.Sprintf("%d", len(ps)) + } + + return fmt.Sprintf("syscall.Syscall%s(gp%s, %d, %s)", post, f.GoName, len(f.Parameters), strings.Join(ps, ", ")) +} + // A Parameter to a Function. type Parameter struct { Name string diff --git a/package.go b/package.go index 1fb0bd1..6dbb410 100644 --- a/package.go +++ b/package.go @@ -69,14 +69,32 @@ func (pkg *Package) GeneratePackage(dir string) error { if err := pkg.generateFile("package", dir); err != nil { return err } + if err := pkg.generateFile("package_notwindows", dir); err != nil { + return err + } + if err := pkg.generateFile("package_windows", dir); err != nil { + return err + } if err := pkg.generateFile("conversions", dir); err != nil { return err } - if err := pkg.generateFile("procaddr", dir); err != nil { + if err := pkg.generateFile("conversions_notwindows", dir); err != nil { + return err + } + if err := pkg.generateFile("conversions_windows", dir); err != nil { + return err + } + if err := pkg.generateFile("procaddr_notwindows", dir); err != nil { + return err + } + if err := pkg.generateFile("procaddr_windows", dir); err != nil { return err } if pkg.HasDebugCallbackFeature() { - if err := pkg.generateFile("debug", dir); err != nil { + if err := pkg.generateFile("debug_notwindows", dir); err != nil { + return err + } + if err := pkg.generateFile("debug_windows", dir); err != nil { return err } } diff --git a/tmpl/conversions.tmpl b/tmpl/conversions.tmpl index ab45cfe..e0b4d11 100644 --- a/tmpl/conversions.tmpl +++ b/tmpl/conversions.tmpl @@ -1,4 +1,5 @@ //glow:keepspace + // Code generated by glow (https://github.com/go-gl/glow). DO NOT EDIT. package {{.Name}} @@ -10,9 +11,6 @@ import ( "unsafe" ) -// #include -import "C" - // 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. // @@ -66,45 +64,3 @@ func Str(str string) *uint8 { header := (*reflect.StringHeader)(unsafe.Pointer(&str)) return (*uint8)(unsafe.Pointer(header.Data)) } - -// GoStr takes a null-terminated string returned by OpenGL and constructs a -// corresponding Go string. -func GoStr(cstr *uint8) string { - return C.GoString((*C.char)(unsafe.Pointer(cstr))) -} - -// Strs takes a list of Go strings (with or without null-termination) and -// returns their C counterpart. -// -// The returned free function must be called once you are done using the strings -// in order to free the memory. -// -// If no strings are provided as a parameter this function will panic. -func Strs(strs ...string) (cstrs **uint8, free func()) { - if len(strs) == 0 { - panic("Strs: expected at least 1 string") - } - - // Allocate a contiguous array large enough to hold all the strings' contents. - n := 0 - for i := range strs { - n += len(strs[i]) - } - data := C.malloc(C.size_t(n)) - - // Copy all the strings into data. - dataSlice := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ - Data: uintptr(data), - Len: n, - Cap: n, - })) - css := make([]*uint8, len(strs)) // Populated with pointers to each string. - offset := 0 - for i := range strs { - copy(dataSlice[offset:offset+len(strs[i])], strs[i][:]) // Copy strs[i] into proper data location. - css[i] = (*uint8)(unsafe.Pointer(&dataSlice[offset])) // Set a pointer to it. - offset += len(strs[i]) - } - - return (**uint8)(&css[0]), func() { C.free(data) } -} diff --git a/tmpl/conversions_notwindows.tmpl b/tmpl/conversions_notwindows.tmpl new file mode 100644 index 0000000..4762ec2 --- /dev/null +++ b/tmpl/conversions_notwindows.tmpl @@ -0,0 +1,56 @@ +//glow:keepspace +// +build !windows + +// Code generated by glow (https://github.com/go-gl/glow). DO NOT EDIT. + +package {{.Name}} + +import ( + "reflect" + "unsafe" +) + +// #include +import "C" + +// GoStr takes a null-terminated string returned by OpenGL and constructs a +// corresponding Go string. +func GoStr(cstr *uint8) string { + return C.GoString((*C.char)(unsafe.Pointer(cstr))) +} + +// Strs takes a list of Go strings (with or without null-termination) and +// returns their C counterpart. +// +// The returned free function must be called once you are done using the strings +// in order to free the memory. +// +// If no strings are provided as a parameter this function will panic. +func Strs(strs ...string) (cstrs **uint8, free func()) { + if len(strs) == 0 { + panic("Strs: expected at least 1 string") + } + + // Allocate a contiguous array large enough to hold all the strings' contents. + n := 0 + for i := range strs { + n += len(strs[i]) + } + data := C.malloc(C.size_t(n)) + + // Copy all the strings into data. + dataSlice := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ + Data: uintptr(data), + Len: n, + Cap: n, + })) + css := make([]*uint8, len(strs)) // Populated with pointers to each string. + offset := 0 + for i := range strs { + copy(dataSlice[offset:offset+len(strs[i])], strs[i][:]) // Copy strs[i] into proper data location. + css[i] = (*uint8)(unsafe.Pointer(&dataSlice[offset])) // Set a pointer to it. + offset += len(strs[i]) + } + + return (**uint8)(&css[0]), func() { C.free(data) } +} diff --git a/tmpl/conversions_windows.tmpl b/tmpl/conversions_windows.tmpl new file mode 100644 index 0000000..d661c8d --- /dev/null +++ b/tmpl/conversions_windows.tmpl @@ -0,0 +1,54 @@ +//glow:keepspace +// +build windows + +// Code generated by glow (https://github.com/go-gl/glow). DO NOT EDIT. + +package {{.Name}} + +import ( + "runtime" + "strings" + "unsafe" +) + +// GoStr takes a null-terminated string returned by OpenGL and constructs a +// corresponding Go string. +func GoStr(cstr *uint8) string { + str := "" + for { + if *cstr == 0 { + break + } + str += string(*cstr) + cstr = (*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(cstr)) + 1)) + } + return str +} + +// Strs takes a list of Go strings (with or without null-termination) and +// returns their C counterpart. +// +// The returned free function must be called once you are done using the strings +// in order to free the memory. +// +// If no strings are provided as a parameter this function will panic. +func Strs(strs ...string) (cstrs **uint8, free func()) { + if len(strs) == 0 { + panic("Strs: expected at least 1 string") + } + + var pinned []string + var ptrs []*uint8 + for _, str := range strs { + if !strings.HasSuffix(str, "\x00") { + str += "\x00" + } + pinned = append(pinned, str) + ptrs = append(ptrs, Str(str)) + } + + return &ptrs[0], func() { + runtime.KeepAlive(pinned) + pinned = nil + } +} diff --git a/tmpl/debug.tmpl b/tmpl/debug_notwindows.tmpl similarity index 97% rename from tmpl/debug.tmpl rename to tmpl/debug_notwindows.tmpl index fcddcb2..df75f14 100644 --- a/tmpl/debug.tmpl +++ b/tmpl/debug_notwindows.tmpl @@ -1,4 +1,6 @@ //glow:keepspace +// +build !windows + // Code generated by glow (https://github.com/go-gl/glow). DO NOT EDIT. package {{.Name}} diff --git a/tmpl/debug_windows.tmpl b/tmpl/debug_windows.tmpl new file mode 100644 index 0000000..8ec4998 --- /dev/null +++ b/tmpl/debug_windows.tmpl @@ -0,0 +1,16 @@ +//glow:keepspace +// Code generated by glow (https://github.com/go-gl/glow). DO NOT EDIT. + +package {{.Name}} +//glow:rmspace + +import "unsafe" + +type DebugProc func( + source uint32, + gltype uint32, + id uint32, + severity uint32, + length int32, + message string, + userParam unsafe.Pointer) diff --git a/tmpl/package.tmpl b/tmpl/package.tmpl index a44f6f6..3968139 100644 --- a/tmpl/package.tmpl +++ b/tmpl/package.tmpl @@ -18,97 +18,12 @@ package {{.Name}} //glow:rmspace -{{define "paramsCDecl"}}{{range $i, $p := .}}{{if ne $i 0}}, {{end}}{{$p.Type.CType}} {{$p.CName}}{{end}}{{end}} -{{define "paramsCCall"}}{{range $i, $p := .}}{{if ne $i 0}}, {{end}}{{if $p.Type.IsDebugProc}}glowCDebugCallback{{else}}{{$p.CName}}{{end}}{{end}}{{end}} - -{{define "paramsGoDecl"}}{{range $i, $p := .}}{{if ne $i 0}}, {{end}}{{$p.GoName}} {{$p.Type.GoType}}{{end}}{{end}} -{{define "paramsGoCall"}}{{range $i, $p := .}}{{if ne $i 0}}, {{end}}{{$p.Type.ConvertGoToC $p.GoName}}{{end}}{{end}} - -// #cgo darwin LDFLAGS: -framework OpenGL -// #cgo windows LDFLAGS: -lopengl32 -// -// #cgo !egl,linux !egl,freebsd pkg-config: gl -// #cgo egl,linux egl,freebsd pkg-config: egl -// -// #if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) -// #ifndef WIN32_LEAN_AND_MEAN -// #define WIN32_LEAN_AND_MEAN 1 -// #endif -// #include -// #endif -// -// #ifndef APIENTRY -// #define APIENTRY -// #endif -// #ifndef APIENTRYP -// #define APIENTRYP APIENTRY * -// #endif -// #ifndef GLAPI -// #define GLAPI extern -// #endif -// -// {{range .Typedefs}} -// {{replace .CTypedef "\n" "\n// " -1}} -// {{end}} -// -// {{if .HasDebugCallbackFeature}} -// extern void glowDebugCallback_{{.UniqueName}}(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam); -// static void APIENTRY glowCDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) { -// glowDebugCallback_{{.UniqueName}}(source, type, id, severity, length, message, userParam); -// } -// {{end}} -// -// {{range .Functions}} -// typedef {{.Return.CType}} (APIENTRYP GP{{toUpper .GoName}})({{template "paramsCDecl" .Parameters}}); -// {{end}} -// -// {{range .Functions}} -// static {{.Return.CType}} glow{{.GoName}}(GP{{toUpper .GoName}} fnptr{{if ge (len .Parameters) 1}}, {{end}}{{template "paramsCDecl" .Parameters}}) { -// {{if not .Return.IsVoid}}return {{end}}(*fnptr)({{template "paramsCCall" .Parameters}}); -// } -// {{end}} -// -import "C" -import ( - {{if .HasRequiredFunctions}} - "errors" - {{end}} - "unsafe" -) - const ( - {{range .Enums}} - {{.GoName}} = {{.Value}} - {{end}} + {{range .Enums}} + {{.GoName}} = {{.Value}} + {{end}} ) -var ( - {{range .Functions}} - gp{{.GoName}} C.GP{{toUpper .GoName}} - {{end}} -) - -// Helper functions -func boolToInt(b bool) int { - if b { return 1 } - return 0 -} - -{{define "bridgeCall"}}C.glow{{.GoName}}(gp{{.GoName}}{{if ge (len .Parameters) 1}}, {{end}}{{template "paramsGoCall" .Parameters}}){{end}} -{{range .Functions}} -{{.Comment}} -func {{.GoName}}({{template "paramsGoDecl" .Parameters}}){{if not .Return.IsVoid}} {{.Return.GoType}}{{end}} { - {{range .Parameters}} - {{if .Type.IsDebugProc}}userDebugCallback = {{.GoName}}{{end}} - {{end}} - {{if .Return.IsVoid}}{{template "bridgeCall" .}} - {{else}} - ret := {{template "bridgeCall" .}} - return {{.Return.ConvertCToGo "ret"}} - {{end}} -} -{{end}} - //glow:keepspace // Init initializes the OpenGL bindings by loading the function pointers (for // each OpenGL function) from the active OpenGL context. @@ -133,18 +48,3 @@ func {{.GoName}}({{template "paramsGoDecl" .Parameters}}){{if not .Return.IsVoid func Init() error { return InitWithProcAddrFunc(getProcAddress) } - -// InitWithProcAddrFunc intializes the package using the specified OpenGL -// function pointer loading function. For more cases Init should be used -// instead. -func InitWithProcAddrFunc(getProcAddr func(name string) unsafe.Pointer) error { - {{range .Functions}} - gp{{.GoName}} = (C.GP{{toUpper .GoName}})(getProcAddr("{{.Name}}")) - {{if .Required}} - if gp{{.GoName}} == nil { - return errors.New("{{.Name}}") - } - {{end}} - {{end}} - return nil -} diff --git a/tmpl/package_notwindows.tmpl b/tmpl/package_notwindows.tmpl new file mode 100644 index 0000000..abee722 --- /dev/null +++ b/tmpl/package_notwindows.tmpl @@ -0,0 +1,100 @@ +//glow:keepspace +// +build !windows + +// Code generated by glow (https://github.com/go-gl/glow). DO NOT EDIT. + +package {{.Name}} +//glow:rmspace + +{{define "paramsCDecl"}}{{range $i, $p := .}}{{if ne $i 0}}, {{end}}{{$p.Type.CType}} {{$p.CName}}{{end}}{{end}} +{{define "paramsCCall"}}{{range $i, $p := .}}{{if ne $i 0}}, {{end}}{{if $p.Type.IsDebugProc}}glowCDebugCallback{{else}}{{$p.CName}}{{end}}{{end}}{{end}} + +{{define "paramsGoDecl"}}{{range $i, $p := .}}{{if ne $i 0}}, {{end}}{{$p.GoName}} {{$p.Type.GoType}}{{end}}{{end}} +{{define "paramsGoCall"}}{{range $i, $p := .}}{{if ne $i 0}}, {{end}}{{$p.Type.ConvertGoToC $p.GoName}}{{end}}{{end}} + +// #cgo darwin LDFLAGS: -framework OpenGL +// +// #cgo !egl,linux !egl,freebsd pkg-config: gl +// #cgo egl,linux egl,freebsd pkg-config: egl +// +// #ifndef APIENTRY +// #define APIENTRY +// #endif +// #ifndef APIENTRYP +// #define APIENTRYP APIENTRY * +// #endif +// #ifndef GLAPI +// #define GLAPI extern +// #endif +// +// {{range .Typedefs}} +// {{replace .CTypedef "\n" "\n// " -1}} +// {{end}} +// +// {{if .HasDebugCallbackFeature}} +// extern void glowDebugCallback_{{.UniqueName}}(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam); +// static void APIENTRY glowCDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) { +// glowDebugCallback_{{.UniqueName}}(source, type, id, severity, length, message, userParam); +// } +// {{end}} +// +// {{range .Functions}} +// typedef {{.Return.CType}} (APIENTRYP GP{{toUpper .GoName}})({{template "paramsCDecl" .Parameters}}); +// {{end}} +// +// {{range .Functions}} +// static {{.Return.CType}} glow{{.GoName}}(GP{{toUpper .GoName}} fnptr{{if ge (len .Parameters) 1}}, {{end}}{{template "paramsCDecl" .Parameters}}) { +// {{if not .Return.IsVoid}}return {{end}}(*fnptr)({{template "paramsCCall" .Parameters}}); +// } +// {{end}} +// +import "C" +import ( + {{if .HasRequiredFunctions}} + "errors" + {{end}} + "unsafe" +) + +var ( + {{range .Functions}} + gp{{.GoName}} C.GP{{toUpper .GoName}} + {{end}} +) + +// Helper functions +func boolToInt(b bool) int { + if b { return 1 } + return 0 +} + +{{define "bridgeCall"}}C.glow{{.GoName}}(gp{{.GoName}}{{if ge (len .Parameters) 1}}, {{end}}{{template "paramsGoCall" .Parameters}}){{end}} +{{range .Functions}} +{{.Comment}} +func {{.GoName}}({{template "paramsGoDecl" .Parameters}}){{if not .Return.IsVoid}} {{.Return.GoType}}{{end}} { + {{range .Parameters}} + {{if .Type.IsDebugProc}}userDebugCallback = {{.GoName}}{{end}} + {{end}} + {{if .Return.IsVoid}}{{template "bridgeCall" .}} + {{else}} + ret := {{template "bridgeCall" .}} + return {{.Return.ConvertCToGo "ret"}} + {{end}} +} +{{end}} + + +// InitWithProcAddrFunc intializes the package using the specified OpenGL +// function pointer loading function. For more cases Init should be used +// instead. +func InitWithProcAddrFunc(getProcAddr func(name string) unsafe.Pointer) error { + {{range .Functions}} + gp{{.GoName}} = (C.GP{{toUpper .GoName}})(getProcAddr("{{.Name}}")) + {{if .Required}} + if gp{{.GoName}} == nil { + return errors.New("{{.Name}}") + } + {{end}} + {{end}} + return nil +} diff --git a/tmpl/package_windows.tmpl b/tmpl/package_windows.tmpl new file mode 100644 index 0000000..363436a --- /dev/null +++ b/tmpl/package_windows.tmpl @@ -0,0 +1,56 @@ +//glow:keepspace +// Code generated by glow (https://github.com/go-gl/glow). DO NOT EDIT. + +package {{.Name}} +//glow:rmspace + +{{define "paramsGoDecl"}}{{range $i, $p := .}}{{if ne $i 0}}, {{end}}{{$p.GoName}} {{$p.Type.GoType}}{{end}}{{end}} + +import ( + {{if .HasRequiredFunctions}} + "errors" + {{end}} + "math" + "syscall" + "unsafe" +) + +var ( + {{range .Functions}} + gp{{.GoName}} uintptr + {{end}} +) + +func boolToUintptr(b bool) uintptr { + if b { + return 1 + } + return 0 +} + +{{range .Functions}} +{{.Comment}} +func {{.GoName}}({{template "paramsGoDecl" .Parameters}}){{if not .Return.IsVoid}} {{.Return.GoType}}{{end}} { + {{if not .IsImplementedForSyscall}}panic("\"{{.GoName}}\" is not implemented") + {{else if .Return.IsVoid}}{{.Syscall}} + {{else}} + ret, _, _ := {{.Syscall}} + return {{.Return.ConvertUintptrToGo "ret"}} + {{end}} +} +{{end}} + +// InitWithProcAddrFunc intializes the package using the specified OpenGL +// function pointer loading function. For more cases Init should be used +// instead. +func InitWithProcAddrFunc(getProcAddr func(name string) unsafe.Pointer) error { + {{range .Functions}} + gp{{.GoName}} = uintptr(getProcAddr("{{.Name}}")) + {{if .Required}} + if gp{{.GoName}} == 0 { + return errors.New("{{.Name}}") + } + {{end}} + {{end}} + return nil +} diff --git a/tmpl/procaddr.tmpl b/tmpl/procaddr_notwindows.tmpl similarity index 77% rename from tmpl/procaddr.tmpl rename to tmpl/procaddr_notwindows.tmpl index d092db8..2d9f700 100644 --- a/tmpl/procaddr.tmpl +++ b/tmpl/procaddr_notwindows.tmpl @@ -1,10 +1,11 @@ //glow:keepspace +// +build !windows + // Code generated by glow (https://github.com/go-gl/glow). DO NOT EDIT. // This file implements GlowGetProcAddress for every supported platform. The // correct version is chosen automatically based on build tags: // -// windows: WGL // darwin: CGL // linux freebsd: GLX // @@ -18,9 +19,6 @@ package {{.Name}} //glow:rmspace /* -#cgo windows CFLAGS: -DTAG_WINDOWS -#cgo windows LDFLAGS: -lopengl32 - #cgo darwin CFLAGS: -DTAG_DARWIN #cgo darwin LDFLAGS: -framework OpenGL @@ -41,23 +39,6 @@ package {{.Name}} return eglGetProcAddress(name); } -#elif defined(TAG_WINDOWS) - - #define WIN32_LEAN_AND_MEAN 1 - #include - #include - static HMODULE ogl32dll = NULL; - void* GlowGetProcAddress_{{.UniqueName}}(const char* name) { - void* pf = wglGetProcAddress((LPCSTR) name); - if (pf) { - return pf; - } - if (ogl32dll == NULL) { - ogl32dll = LoadLibraryA("opengl32.dll"); - } - return GetProcAddress(ogl32dll, (LPCSTR) name); - } - #elif defined(TAG_DARWIN) #include diff --git a/tmpl/procaddr_windows.tmpl b/tmpl/procaddr_windows.tmpl new file mode 100644 index 0000000..2f31628 --- /dev/null +++ b/tmpl/procaddr_windows.tmpl @@ -0,0 +1,33 @@ +//glow:keepspace +// Code generated by glow (https://github.com/go-gl/glow). DO NOT EDIT. + +package {{.Name}} +//glow:rmspace + +import ( + "unsafe" + + "golang.org/x/sys/windows" +) + +var ( + opengl32 = windows.NewLazySystemDLL("opengl32") + wglGetProcAddress = opengl32.NewProc("wglGetProcAddress") +) + +func getProcAddress(namea string) unsafe.Pointer { + cname, err := windows.BytePtrFromString(namea) + if err != nil { + panic(err) + } + if r, _, _ := wglGetProcAddress.Call(uintptr(unsafe.Pointer(cname))); r != 0 { + return unsafe.Pointer(r) + } + + p := opengl32.NewProc(namea) + if err := p.Find(); err != nil { + // The proc is not found. + return nil + } + return unsafe.Pointer(p.Addr()) +} diff --git a/type.go b/type.go index 036f975..ec8fc99 100644 --- a/type.go +++ b/type.go @@ -134,14 +134,60 @@ func (t Type) ConvertGoToC(name string) string { return fmt.Sprintf("(%s)(%s)", t.GoCType(), name) } +// ConvertGoToUintptr returns an expression that converts a variable from the Go type to uintptr type for syscall.Syscall. +func (t Type) ConvertGoToUintptr(name string) string { + switch t.Name { + case "GLboolean": + if t.PointerLevel == 0 { + return fmt.Sprintf("boolToUintptr(%s)", name) + } + case "GLfloat", "GLclampf": + if t.PointerLevel == 0 { + return fmt.Sprintf("uintptr(math.Float32bits(%s))", name) + } + case "GLdouble", "GLclampd": + if t.PointerLevel == 0 { + return fmt.Sprintf("uintptr(math.Float64bits(%s))", name) + } + case "GLDEBUGPROC", "GLDEBUGPROCARB", "GLDEBUGPROCKHR": + return fmt.Sprintf("syscall.NewCallbackCDecl(%s)", name) + } + if t.PointerLevel >= 1 && t.GoType() != "unsafe.Pointer" { + return fmt.Sprintf("uintptr(unsafe.Pointer(%s))", name) + } + return fmt.Sprintf("uintptr(%s)", name) +} + // ConvertCToGo converts from the C type to the Go type. func (t Type) ConvertCToGo(name string) string { - if t.Name == "GLboolean" { + if t.Name == "GLboolean" && t.PointerLevel == 0 { return fmt.Sprintf("%s == TRUE", name) } return fmt.Sprintf("(%s)(%s)", t.GoType(), name) } +// ConvertUintptrToGo converts from the uintptr type to the Go type. +func (t Type) ConvertUintptrToGo(name string) string { + switch t.Name { + case "GLboolean": + if t.PointerLevel == 0 { + return fmt.Sprintf("%s != 0", name) + } + case "GLfloat", "GLclampf": + if t.PointerLevel == 0 { + return fmt.Sprintf("math.Float32frombits(uint32(%s))", name) + } + case "GLdouble", "GLclampd": + if t.PointerLevel == 0 { + return fmt.Sprintf("math.Float64frombits(uint64(%s))", name) + } + } + if t.PointerLevel >= 1 && t.GoType() != "unsafe.Pointer" { + return fmt.Sprintf("(%s)(unsafe.Pointer(%s))", t.GoType(), name) + } + return fmt.Sprintf("(%s)(%s)", t.GoType(), name) +} + func (t Type) pointers() string { return strings.Repeat("*", t.PointerLevel) }