From 04c97656d829530ee302eb9d701c8a149f0366d6 Mon Sep 17 00:00:00 2001 From: Ruslan Mustakov Date: Fri, 28 Jul 2017 23:11:59 +0700 Subject: [PATCH] gdnew via creating NativeScript --- godot/godotinternal.nim | 8 +++--- godot/nim/godotnim.nim | 59 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/godot/godotinternal.nim b/godot/godotinternal.nim index 8b9bb6b..f2652ec 100644 --- a/godot/godotinternal.nim +++ b/godot/godotinternal.nim @@ -34,6 +34,7 @@ type coreApiHash*: uint64 editorApiHash*: uint64 noApiHash*: uint64 + gdNativeLibrary*: ptr GodotObject GodotNativeTerminateOptions* = object inEditor*: bool @@ -234,8 +235,9 @@ proc godotScriptRegisterSignal*(libHandle: pointer; name: cstring; proc getUserdata*(instance: ptr GodotObject): pointer {. importc: "godot_nativescript_get_userdata".} -proc godotNew*(p_classname: cstring): ptr GodotObject {. - importc: "godot_nativescript_new".} +type ClassConstructor = proc (): ptr GodotObject {.noconv.} +proc getClassConstructor*(className: cstring): ClassConstructor {. + importc: "godot_get_class_constructor".} proc godotStackBottom*(): pointer {. importc: "godot_get_stack_bottom".} @@ -256,7 +258,7 @@ proc godotPrintWarning*(description: cstring; function: cstring; proc godotPrint*(message: GodotString) {. importc: "godot_print".} -var getClassMethodBind {.threadvar.}: ptr GodotMethodBind +var getClassMethodBind: ptr GodotMethodBind proc getClassName*(o: ptr GodotObject): string = if getClassMethodBind.isNil: getClassMethodBind = getMethod(cstring"Object", cstring"get_class") diff --git a/godot/nim/godotnim.nim b/godot/nim/godotnim.nim index a850f1e..7c6aa7e 100644 --- a/godot/nim/godotnim.nim +++ b/godot/nim/godotnim.nim @@ -68,6 +68,9 @@ proc print*(message: cstring) {.inline.} = s.deinit() var classRegistry {.threadvar.}: TableRef[cstring, ObjectInfo] +var classRegistryStatic {.compileTime.}: TableRef[cstring, ObjectInfo] +static: + classRegistryStatic = newTable[cstring, ObjectInfo]() static: import sets, strutils @@ -148,12 +151,20 @@ template registerClass*(T: typedesc; godotClassName: cstring, const base = baseNativeType(T) const isRef: bool = isReference(T) - classRegistry[godotClassName] = ObjectInfo( + let objInfo = ObjectInfo( constructor: constructor, baseNativeClass: base, isNative: isNativeParam, isRef: isRef ) + classRegistry[godotClassName] = objInfo + static: + let objInfoStatic = ObjectInfo( + baseNativeClass: base, + isNative: isNativeParam, + isRef: isRef + ) + classRegistryStatic[godotClassName] = objInfoStatic when isRef: static: refClasses.add(T.name) @@ -237,12 +248,48 @@ proc getSingleton*[T: NimGodotObject](): T = else: result = asNimGodotObject[T](singleton) +var gdNativeLibraryObj: ptr GodotObject + +var setClassNameMethod: ptr GodotMethodBind +var setLibraryMethod: ptr GodotMethodBind +var newMethod: ptr GodotMethodBind +type + PtrCallArgType = ptr array[MAX_ARG_COUNT, pointer] +proc newOwnObj[T: NimGodotObject](name: cstring): T = + let newNativeScript = getClassConstructor(cstring"NativeScript")() + if setClassNameMethod.isNil: + setClassNameMethod = + getMethod(cstring"NativeScript", cstring"set_class_name") + if setLibraryMethod.isNil: + setLibraryMethod = + getMethod(cstring"NativeScript", cstring"set_library") + if newMethod.isNil: + newMethod = getMethod(cstring"NativeScript", cstring"new") + var godotStrName = name.toGodotString() + var argPtr: pointer = addr godotStrName + setClassNameMethod.ptrCall( + newNativeScript, cast[PtrCallArgType](addr argPtr), nil) + deinit(godotStrName) + setLibraryMethod.ptrCall( + newNativeScript, cast[PtrCallArgType](addr gdNativeLibraryObj), nil) + + var err: VariantCallError + var ret = newMethod.call(newNativeScript, nil, 0, err) + if err.error != VariantCallErrorType.OK: + printError("Failed to invoke 'new' on NativeScript for " & $name) + elif ret.getType() != VariantType.Object: + printError("Expected that NativeScript::new returns Object, " & + "but it returned: " & $ret.getType()) + else: + result = asNimGodotObject[T](ret.asGodotObject()) + ret.deinit() + proc gdnew*[T: NimGodotObject](): T = const godotName = toGodotName(T) - let obj = godotNew(godotName) - if obj.isNil: - printError("godot_new returned nil for type " & $godotName) - result = asNimGodotObject[T](obj) + const objInfo = classRegistryStatic[godotName] + result = when objInfo.isNative: + asNimGodotObject[T](getClassConstructor(godotName)()) + else: newOwnObj[T](godotName) proc newCallError*(err: VariantCallError): ref CallError = let msg = case err.error: @@ -583,7 +630,7 @@ proc godot_nativescript_init(handle: pointer) {. proc godot_gdnative_init(options: ptr GodotNativeInitOptions) {. cdecl, exportc, dynlib.} = - discard + gdNativeLibraryObj = options.gdNativeLibrary proc godot_gdnative_terminate(options: ptr GodotNativeTerminateOptions) {. cdecl, exportc, dynlib.} =