123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- // Copyright © 2019 - 2020 Oscar Campos <oscar.campos@thepimpam.com>
- // Copyright © 2017 - William Edwards
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License
- // Package gdnative provides a wrapper around the Godot GDNative API.
- package gdnative
- /*
- #cgo CFLAGS: -I../godot_headers -std=c11
- #cgo linux LDFLAGS: -Wl,-unresolved-symbols=ignore-all
- #cgo darwin LDFLAGS: -Wl,-undefined,dynamic_lookup
- #include <gdnative/gdnative.h>
- #include <gdnative_api_struct.gen.h>
- #include "gdnative.gen.h"
- #include "util.h"
- */
- import "C"
- import (
- "fmt"
- "log"
- "unsafe"
- wchar "github.com/vitaminwater/cgo.wchar"
- )
- // debug determines whether or not we should log messages
- var debug = false
- // EnableDebug will enable logging of GDNative debug messages.
- func EnableDebug() {
- debug = true
- }
- // GDNative is our API main entry point, it is first set here to null.
- // This will be set when 'godot_gdnative_init' is called by Godot when the library is loaded.
- var GDNative = new(gdNative)
- // gdNative is a structure that wraps the GDNativeAPI.
- type gdNative struct {
- api *C.godot_gdnative_core_api_struct
- initialized bool
- }
- // IsInitialized will return true if `godot_gdnative_init` was called by Godot.
- func (g *gdNative) IsInitialized() bool {
- return g.initialized
- }
- // CheckInit will check to see if GDNative has initialized. If it is not, it will
- // throw a panic.
- func (g *gdNative) checkInit() {
- if !g.IsInitialized() {
- panic("GDNative has not initialized! You cannot call this in init()!")
- }
- }
- // godot_gdnative_init is the library entry point. When the library is loaded
- // this method will be called by Godot.
- //export godot_gdnative_init
- func godot_gdnative_init(options *C.godot_gdnative_init_options) {
- // Get the API struct from the init options passed by Godot when this
- // library is loaded. This API struct will have all of the functions
- // to call.
- GDNative.api = (*options).api_struct
- GDNative.initialized = true
- // Configure logging.
- log.SetFlags(log.LstdFlags | log.Lshortfile)
- log.SetOutput(Log)
- if debug {
- log.Println("Initializing gdnative-go library.")
- }
- // Find GDNative extensions that we support.
- for i := 0; i < int(GDNative.api.num_extensions); i++ {
- extension := C.cgo_get_ext(GDNative.api.extensions, C.int(i))
- switch extension._type {
- case C.GDNATIVE_EXT_NATIVESCRIPT:
- if debug {
- log.Println("Found nativescript extension!")
- }
- NativeScript.api = (*C.godot_gdnative_ext_nativescript_api_struct)(unsafe.Pointer(extension))
- }
- }
- }
- /** Library de-initialization **/
- // godot_gdnative_terminate is the library's de-initialization method. When
- // Godot unloads the library, this method will be called.
- //export godot_gdnative_terminate
- func godot_gdnative_terminate(options *C.godot_gdnative_terminate_options) {
- if debug {
- log.Println("De-initializing Go library.")
- }
- GDNative.api = nil
- NativeScript.api = nil
- }
- // NewEmptyVoid returns back a new C empty or void pointer
- func NewEmptyVoid() Pointer {
- var empty C.void
- return Pointer{base: unsafe.Pointer(&empty)}
- }
- // GetSingleton will return an instance of the given singleton.
- func GetSingleton(name String) Object {
- if debug {
- log.Println("Getting singleton:", name)
- }
- GDNative.checkInit()
- // Create a C string from the name argument.
- cName := C.CString(string(name))
- // Call the C method
- obj := C.go_godot_global_get_singleton(GDNative.api, cName)
- return Object{base: (*C.godot_object)(obj)}
- }
- // NewMethodBind will return a method binding using the given class name and method
- // name.
- func NewMethodBind(class, method string) MethodBind {
- if debug {
- log.Println("Creating method bind for:", class+"."+method)
- }
- GDNative.checkInit()
- methodBind := C.go_godot_method_bind_get_method(
- GDNative.api,
- C.CString(class),
- C.CString(method),
- )
- return MethodBind{base: methodBind}
- }
- // MethodBindPtrCall will call the given method on the given Godot Object. Its return
- // value is given as a pointer, which can be used to convert it to a variant.
- func MethodBindPtrCall(methodBind MethodBind, instance Object, args []Pointer, returns Pointer) Pointer {
- GDNative.checkInit()
- if instance.getBase() == nil {
- panic("Godot object pointer was nil when calling MethodBindPtrCall")
- }
- // Build out our C arguments array
- cArgs := C.go_void_build_array(C.int(len(args)))
- for i, arg := range args {
- C.go_void_add_element(cArgs, arg.getBase(), C.int(i))
- }
- if debug {
- // If debug is enabled print all the arguments we are passing
- for i, arg := range args {
- log.Println("arg", i, ": ", arg.getBase())
- }
- log.Println("args: ", cArgs)
- log.Println("returns: ", returns.getBase())
- log.Println("object: ", unsafe.Pointer(instance.getBase()))
- log.Println("methodbind: ", unsafe.Pointer(methodBind.getBase()))
- }
- // Call the C method
- C.go_godot_method_bind_ptrcall(
- GDNative.api,
- methodBind.getBase(),
- unsafe.Pointer(instance.getBase()),
- cArgs,
- returns.getBase(),
- )
- if debug {
- log.Println("Finished calling method.")
- }
- return returns
- }
- // Pointer is a pointer to arbitrary underlying data. This is primarily used
- // in conjunction with MethodBindPtrCall.
- type Pointer struct {
- base unsafe.Pointer
- }
- func (p *Pointer) getBase() unsafe.Pointer {
- return p.base
- }
- // Char is a Godot C char wrapper
- type Char string
- func (c Char) getBase() *C.char {
- // this might lead to memory leaks as this C memory
- // is not gonna be garbage collected by Go runtime
- return C.CString(string(c))
- }
- // Double is a Godot C double wrapper
- type Double float64
- func (d Double) getBase() C.double {
- return C.double(d)
- }
- // NewPointerFromFloat will return an unsafe pointer to the given
- // object. This is primarily used in conjunction with MethodBindPtrCall.
- func NewPointerFromFloat(obj Float) Pointer {
- base := obj.getBase()
- return Pointer{base: unsafe.Pointer(&base)}
- }
- // NewFloatFromPointer will return a Float from the
- // given unsafe pointer. This is primarily used in conjunction with MethodBindPtrCall.
- func NewFloatFromPointer(ptr Pointer) Float {
- base := ptr.getBase()
- return Float(*(*C.float)(base))
- }
- // NewEmptyFloat will return a pointer to an empty
- // initialized Float. This is primarily used in
- // conjunction with MethodBindPtrCall.
- func NewEmptyFloat() Pointer {
- var obj C.float
- return Pointer{base: unsafe.Pointer(&obj)}
- }
- // Float is a Godot C float wrapper
- type Float float64
- func (f Float) getBase() C.float {
- return C.float(f)
- }
- // Int64T is a Godot C int64_t wrapper
- type Int64T int64
- func (i Int64T) getBase() C.int64_t {
- return C.int64_t(i)
- }
- // SignedChar is a Godot C schar wrapper
- type SignedChar int8
- func (s SignedChar) getBase() *C.schar { //nolint:unused
- intVal := int8(s)
- return (*C.schar)(unsafe.Pointer(&intVal))
- }
- // Uint is a Godot C uint wrapper
- type Uint uint
- func (u Uint) getBase() C.uint { //nolint:unused
- return C.uint(u)
- }
- // Uint8T is a Godot C uint8_t wrapper
- type Uint8T uint8
- func (u Uint8T) getBase() C.uint8_t {
- return C.uint8_t(u)
- }
- // Uint32T is a Godot C uint32_t wrapper
- type Uint32T uint32
- func (u Uint32T) getBase() C.uint32_t { //nolint:unused
- return C.uint32_t(u)
- }
- // Uint64T is a Godot C uint64_t wrapper
- type Uint64T uint64
- func (u Uint64T) getBase() C.uint64_t {
- return C.uint64_t(u)
- }
- // newWcharT will convert the given C.wchar_t into a Go string
- func newWcharT(str *C.wchar_t) WcharT {
- goStr, err := wchar.WcharStringPtrToGoString(unsafe.Pointer(str))
- if err != nil {
- log.Println("Error converting wchar_t to Go string:", err)
- }
- return WcharT(goStr)
- }
- // WcharT is a Godot C wchar_t wrapper
- type WcharT string
- func (w WcharT) getBase() *C.wchar_t {
- wcharString, err := wchar.FromGoString(string(w))
- if err != nil {
- log.Println("Error decoding WcharT:", err)
- }
- return (*C.wchar_t)(wcharString.Pointer())
- }
- // AsString converts a WCharT into a string
- func (w WcharT) AsString() String {
- return NewStringWithWideString(string(w))
- }
- // ID will return the Godot object memory address as a string, which can
- // be used in an instance registry for registering classes.
- func (gdt Object) ID() string {
- return fmt.Sprintf("%p", gdt.base)
- }
|