conversions_notwindows.go (2757B)
1 // SPDX-License-Identifier: MIT 2 3 // +build !windows 4 5 package gl 6 7 import ( 8 "fmt" 9 "reflect" 10 "strings" 11 "unsafe" 12 ) 13 14 // #include <stdlib.h> 15 import "C" 16 17 // Ptr takes a slice or pointer (to a singular scalar value or the first 18 // element of an array or slice) and returns its GL-compatible address. 19 // 20 // For example: 21 // 22 // var data []uint8 23 // ... 24 // gl.TexImage2D(gl.TEXTURE_2D, ..., gl.UNSIGNED_BYTE, gl.Ptr(&data[0])) 25 func Ptr(data interface{}) unsafe.Pointer { 26 if data == nil { 27 return unsafe.Pointer(nil) 28 } 29 var addr unsafe.Pointer 30 switch v := data.(type) { 31 case *uint8: 32 addr = unsafe.Pointer(v) 33 case *uint16: 34 addr = unsafe.Pointer(v) 35 case *float32: 36 addr = unsafe.Pointer(v) 37 case []uint8: 38 addr = unsafe.Pointer(&v[0]) 39 case []uint16: 40 addr = unsafe.Pointer(&v[0]) 41 case []float32: 42 addr = unsafe.Pointer(&v[0]) 43 default: 44 panic(fmt.Errorf("unsupported type %T; must be a slice or pointer to a singular scalar value or the first element of an array or slice", v)) 45 } 46 return addr 47 } 48 49 // Str takes a null-terminated Go string and returns its GL-compatible address. 50 // This function reaches into Go string storage in an unsafe way so the caller 51 // must ensure the string is not garbage collected. 52 func Str(str string) *uint8 { 53 if !strings.HasSuffix(str, "\x00") { 54 panic("str argument missing null terminator: " + str) 55 } 56 header := (*reflect.StringHeader)(unsafe.Pointer(&str)) 57 return (*uint8)(unsafe.Pointer(header.Data)) 58 } 59 60 // GoStr takes a null-terminated string returned by OpenGL and constructs a 61 // corresponding Go string. 62 func GoStr(cstr *uint8) string { 63 return C.GoString((*C.char)(unsafe.Pointer(cstr))) 64 } 65 66 // Strs takes a list of Go strings (with or without null-termination) and 67 // returns their C counterpart. 68 // 69 // The returned free function must be called once you are done using the strings 70 // in order to free the memory. 71 // 72 // If no strings are provided as a parameter this function will panic. 73 func Strs(strs ...string) (cstrs **uint8, free func()) { 74 if len(strs) == 0 { 75 panic("Strs: expected at least 1 string") 76 } 77 78 // Allocate a contiguous array large enough to hold all the strings' contents. 79 n := 0 80 for i := range strs { 81 n += len(strs[i]) 82 } 83 data := C.malloc(C.size_t(n)) 84 85 // Copy all the strings into data. 86 dataSlice := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ 87 Data: uintptr(data), 88 Len: n, 89 Cap: n, 90 })) 91 css := make([]*uint8, len(strs)) // Populated with pointers to each string. 92 offset := 0 93 for i := range strs { 94 copy(dataSlice[offset:offset+len(strs[i])], strs[i][:]) // Copy strs[i] into proper data location. 95 css[i] = (*uint8)(unsafe.Pointer(&dataSlice[offset])) // Set a pointer to it. 96 offset += len(strs[i]) 97 } 98 99 return (**uint8)(&css[0]), func() { C.free(data) } 100 }