Documentation & Travis & Refactoring

This commit is contained in:
Ruslan Mustakov 2017-07-31 18:52:07 +07:00
commit 988b9e1f11
27 changed files with 772 additions and 123 deletions

View file

@ -1,3 +0,0 @@
{.warning: "'apigen.apigen' module is deprecated and will be removed in v0.4.0. Use 'godotapigen' instead.".}
include "../godotapigen.nim"

View file

@ -1,7 +1,8 @@
# Copyright 2017 Xored Software, Inc.
import hashes
import internal / [godotstrings, godotdictionaries, godotvariants]
import internal.godotstrings, internal.godotdictionaries,
internal.godotvariants
type
Dictionary* = ref object

1
godot/core/nim.cfg Normal file
View file

@ -0,0 +1 @@
--path:"$projectdir/../"

View file

@ -2,7 +2,7 @@ import internal.godotobjects
type
RID* {.byref.} = object
p: pointer
data: array[sizeof(int), byte]
proc initRID(dest: var RID) {.
importc: "godot_rid_new".}

View file

@ -1,7 +1,7 @@
import tables
import internal / [godotobjects, godotvariants, godotpoolarrays, godotstrings,
godotnodepaths]
import internal.godotobjects, internal.godotvariants, internal.godotpoolarrays,
internal.godotstrings, internal.godotnodepaths
type
Variant* = ref object

View file

@ -1,13 +1,17 @@
# Copyright 2017 Xored Software, Inc.
import core.godotbase, godotinternal
import core / [vector2, rect2, vector3, transform2d, planes, quats]
import core / [rect3, basis, transforms, colors, nodepaths, rids]
import core / [dictionaries, arrays, poolarrays, variants]
import core.vector2, core.rect2, core.vector3, core.transform2d, core.planes,
core.quats
import core.rect3, core.basis, core.transforms, core.colors, core.nodepaths,
core.rids
import core.dictionaries, core.arrays, core.poolarrays, core.variants
import nim / [godotmacros, godotnim]
import nim.godotmacros, nim.godotnim
export godotbase, vector2, rect2, vector3, transform2d, planes, quats,
rect3, basis, transforms, colors, nodepaths, rids, dictionaries, arrays,
poolarrays, variants
export godotmacros, godotnim
export GodotPropertyHint, GodotPropertyUsageFlags

View file

@ -1,6 +1,6 @@
# Copyright 2017 Xored Software, Inc.
import streams, json, ospaths, strutils, times, sets, tables
import streams, json, os, strutils, times, sets, tables
import sequtils, algorithm
import compiler / [ast, renderer, idents, astalgo]
@ -261,8 +261,8 @@ const standardTypes = toSet(
"PoolByteArray", "PoolIntArray", "PoolRealArray", "PoolStringArray",
"PoolVector2Array", "PoolVector3Array", "PoolColorArray"])
const smallIntTypes = toSet(["uint8", "int8", "uint16", "int16", "uint32", "int32",
"cint", "int", "Error"])
const smallIntTypes = toSet(["uint8", "int8", "uint16", "int16", "uint32",
"int32", "cint", "int", "Error"])
const int64Types = toSet(["uint64", "int64"])
const intTypes = union(smallIntTypes, int64Types)
const float64Types = toSet(["float64", "cdouble"])
@ -339,6 +339,11 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
var body: PNode
if not withImplementation:
body = newNode(nkEmpty)
elif godotMethodName == "_init" and typ.godotName == "Object":
# It's not real (calling it crashes) and will be removed later,
# but we use init() convention in Nim, so it needs to work.
body = newNode(nkStmtList).addChain(
newNode(nkDiscardStmt).addChain(newNode(nkEmpty)))
else:
var methodBindName = toNimStyle(
typ.name & "_" & godotMethodName & "_method_bind")
@ -410,7 +415,7 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
let isStandardType = arg.typ in standardTypes
let isWrappedType = arg.typ in wrapperTypes
let convArg = if not varargsName.isNil:
getInternalPtr(newCall("toGodot", argName), "Variant")
getInternalPtr(newCall("toVariant", argName), "Variant")
elif isWrappedType: getInternalPtr(argName, arg.typ)
elif isStandardType: newCall("unsafeAddr", argName)
elif arg.typ == "string": newCall("unsafeAddr",
@ -440,7 +445,8 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
)
else:
argConversions.add(newNode(nkVarSection).addChain(
newIdentDefs(ident("idx"), newNode(nkEmpty), newIntLit(staticArgsLen))))
newIdentDefs(ident("idx"), newNode(nkEmpty),
newIntLit(staticArgsLen))))
let argLoop = newNode(nkWhileStmt)
argConversions.add(argLoop)
argLoop.add(newInfix(ident("idx"), ident("<"), argLenNode)
@ -544,7 +550,8 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
if isVariantRet:
let convErrDef = newNode(nkLetSection).addChain(
newIdentDefs(ident("convErr"), newNode(nkEmpty),
newCall("fromGodot", ident("result"), newCall("newVariant", retValIdent))))
newCall("fromVariant", ident("result"),
newCall("newVariant", retValIdent))))
let convCheck = newIfStmt(
newInfix(ident("convErr"), ident("!="),
newDotExpr(ident("ConversionResult"), ident("OK"))),
@ -726,7 +733,7 @@ proc shouldExport(typ: GodotType, types: Table[string, GodotType]): bool =
curTyp = types.getOrDefault(curTyp.baseName)
result = curTyp.isNil
proc genTypeFile*(types: var Table[string, GodotType], targetDir: string) =
proc genTypeFile(types: var Table[string, GodotType], targetDir: string) =
for typ in types.values():
types.incDerivedCount(typ.baseName)
@ -755,6 +762,9 @@ proc genTypeFile*(types: var Table[string, GodotType], targetDir: string) =
renderModule(godotApiTypesTree, targetDir / "godottypes.nim")
proc genApi*(targetDir: string, apiJsonFile: string) =
## Generates .nim files in the ``targetDir`` based on the ``apiJsonFile``.
## The JSON file can be generated by executing Godot with
## ``--gdnative-generate-json-api <target_filename>`` parameters.
let apiJson = parseJson(newFileStream(apiJsonFile),
apiJsonFile.extractFilename())
var megaImport = newStringOfCap(64 * 1024)

View file

@ -1,8 +1,8 @@
# Copyright 2017 Xored Software, Inc.
import internal / [
godotobjects, godotarrays, godotnodepaths, godotpoolarrays,
godotstrings, godotvariants, godotdictionaries]
import internal.godotobjects, internal.godotarrays, internal.godotnodepaths,
internal.godotpoolarrays, internal.godotstrings, internal.godotvariants,
internal.godotdictionaries
export godotobjects, godotarrays, godotnodepaths, godotpoolarrays,
godotstrings, godotvariants, godotdictionaries
@ -206,7 +206,7 @@ type
proc godotScriptRegisterProperty*(libHandle: pointer;
name: cstring; path: cstring;
attr: var GodotPropertyAttributes;
attr: ptr GodotPropertyAttributes;
setFunc: GodotPropertySetFunc;
getFunc: GodotPropertyGetFunc) {.
importc: "godot_nativescript_register_property".}
@ -270,6 +270,9 @@ proc getClassName*(o: ptr GodotObject): string =
# There are physics type not known by ClassDB
result = result[0..result.len-3]
proc getGodotSingleton*(name: cstring): ptr GodotObject {.
importc: "godot_global_get_singleton".}
# System Functions
proc godotAlloc*(bytes: cint): pointer {.

View file

@ -2,7 +2,7 @@
type
GodotArray* {.byref.} = object
p: pointer
data: array[sizeof(int), byte]
import hashes
import godotobjects, godotpoolarrays, godotvariants, godotstrings

View file

@ -2,7 +2,7 @@
type
GodotDictionary* {.byref.} = object
p: pointer
data: array[sizeof(int), byte]
import godotarrays, godotvariants, godotstrings

View file

@ -4,7 +4,7 @@ import godotstrings
type
GodotNodePath* {.byref.} = object
p: pointer
data: array[sizeof(int), byte]
proc initGodotNodePath*(dest: var GodotNodePath; s: GodotString) {.
importc: "godot_node_path_new".}

View file

@ -2,22 +2,22 @@
type
GodotPoolByteArray* {.byref.} = object
p: pointer
data: array[sizeof(int), byte]
GodotPoolIntArray* {.byref.} = object
p: pointer
data: array[sizeof(int), byte]
GodotPoolRealArray* {.byref.} = object
p: pointer
data: array[sizeof(int), byte]
GodotPoolStringArray* {.byref.} = object
p: pointer
data: array[sizeof(int), byte]
GodotPoolVector2Array* {.byref.} = object
p: pointer
data: array[sizeof(int), byte]
GodotPoolVector3Array* {.byref.} = object
p: pointer
data: array[sizeof(int), byte]
GodotPoolColorArray* {.byref.} = object
p: pointer
data: array[sizeof(int), byte]
import godotstrings, godotarrays
import core / [godotbase, colors, vector2, vector3]
import core.godotbase, core.colors, core.vector2, core.vector3
# byte

View file

@ -2,7 +2,7 @@
type
GodotString* {.byref.} = object
p: pointer
data: array[sizeof(int), byte]
proc initGodotString(dest: var GodotString) {.
importc: "godot_string_new".}

View file

@ -46,7 +46,7 @@ type
expected*: VariantType
GodotVariant* {.byref.} = object
data: array[16 + sizeof(int), byte]
data: array[4 + sizeof(int) div 4, float32]
import godotobjects, godotarrays, godotpoolarrays,
godotstrings, godotnodepaths, godotdictionaries

1
godot/internal/nim.cfg Normal file
View file

@ -0,0 +1 @@
--path:"$projectdir/../"

View file

@ -32,6 +32,19 @@ type
ParseError = object of Exception
proc godotToNim[T](val: Variant): (T, ConversionResult) =
mixin fromVariant
result[1] = fromVariant(result[0], val)
proc nimToGodot[T](val: T): Variant =
mixin toVariant
when compiles(toVariant(val)):
result = toVariant(val)
else:
printError("Failed to convert Nim value of type " & T.name &
" into Variant")
initNilVariant(result)
template parseError(node: NimNode, msg: string) =
raise newException(ParseError, lineinfo(node) & ": " & msg)
@ -249,7 +262,7 @@ macro invokeVarArgs(procIdent, objIdent;
if hasReturnValue:
let theCall = newNimNode(nnkBracketExpr).add(newNimNode(nnkDotExpr).add(
newCall("toGodot", invocation), ident("godotVariant")))
newCall("toVariant", invocation), ident("godotVariant")))
branchBody.add(getAst(initGodotVariantCall(ident("result"), theCall)))
else:
branchBody.add(invocation)
@ -291,11 +304,18 @@ proc nimDestroyRefFunc(obj: ptr GodotObject, methData: pointer,
# so nothing to do here.
discard
proc refcountIncremented*(obj: NimGodotObject) =
GC_ref(obj)
proc refcountIncremented(obj: ptr GodotObject, methodData: pointer,
userData: pointer, numArgs: cint,
args: var array[MAX_ARG_COUNT, ptr GodotVariant]):
GodotVariant {.noconv.} =
GC_ref(cast[NimGodotObject](userData))
proc refcountDecremented*(obj: NimGodotObject): bool =
GC_unref(obj)
proc refcountDecremented(obj: ptr GodotObject, methodData: pointer,
userData: pointer, numArgs: cint,
args: var array[MAX_ARG_COUNT, ptr GodotVariant]):
GodotVariant {.noconv.} =
GC_unref(cast[NimGodotObject](userData))
initGodotVariant(result, false) # destroy when Nim decides
template registerGodotClass(classNameIdent, classNameLit, isRef,
baseNameLit, createFuncIdent; isTool: bool) =
@ -306,6 +326,8 @@ template registerGodotClass(classNameIdent, classNameLit, isRef,
nimObj.setGodotObject(obj)
GC_ref(nimObj)
result = cast[pointer](nimObj)
when compiles(nimObj.init()):
nimObj.init()
let createFuncObj = GodotInstanceCreateFunc(
createFunc: createFuncIdent
@ -356,19 +378,23 @@ template registerGodotField(classNameLit, classNameIdent, propNameLit,
getFunc: getFuncIdent
)
{.push warning[ProveInit]: off.} # false warning, Nim bug
var attr = GodotPropertyAttributes(
typ: ord(godotVariantType(propTypeIdent)),
hintString: hintTipLit.toGodotString(),
var hintStr = hintTipLit.toGodotString()
let attr = GodotPropertyAttributes(
typ: ord(variantType(propTypeIdent)),
hintString: hintStr,
hint: GodotPropertyHint.hintIdent,
usage: GodotPropertyUsageFlags.usageIdent
)
{.push warning[ProveInit]: on.}
when hasDefaultValue:
attr.defaultValue = (defaultValueNode).toGodot()
attr.defaultValue = (defaultValueNode).toVariant().godotVariant[]
godotScriptRegisterProperty(getNativeLibHandle(), classNameLit, propNameLit,
attr, setFunc, getFunc)
unsafeAddr attr, setFunc, getFunc)
hintStr.deinit()
static:
import strutils, sets
import strutils, sets, sequtils
proc toGodotStyle(s: string): string {.compileTime.} =
result = newStringOfCap(s.len + 10)
for c in s:
@ -469,7 +495,6 @@ proc genType(obj: ObjectDecl): NimNode {.compileTime.} =
GodotVariant {.noconv.} =
let self = cast[classNameIdent](userData)
const isStaticCall = methodNameLit == cstring"_ready" or
methodNameLit == cstring"_init" or
methodNameLit == cstring"_enter_tree" or
methodNameLit == cstring"_exit_tree" or
methodNameLit == cstring"_enter_world" or
@ -520,25 +545,70 @@ proc genType(obj: ObjectDecl): NimNode {.compileTime.} =
if isRef:
# add ref/unref for types inherited from Reference
let noArgs = newSeq[NimNode]()
result.add(getAst(
registerGodotMethod(classNameLit, classNameIdent, ident("refcountIncremented"),
cstring"_refcount_incremented", 0, 0,
noArgs, genSym(nskProc, "refcount_incremented"),
ident("false"))))
result.add(getAst(
registerGodotMethod(classNameLit, classNameIdent, ident("refcountDecremented"),
cstring"_refcount_decremented", 0, 0,
noArgs, genSym(nskProc, "refcount_decremented"),
ident("true"))))
template registerRefIncDec(classNameLit) =
let refInc = GodotInstanceMethod(
meth: refcountIncremented
)
let refDec = GodotInstanceMethod(
meth: refcountDecremented
)
godotScriptRegisterMethod(getNativeLibHandle(), classNameLit,
cstring"_refcount_incremented",
GodotMethodAttributes(), refInc)
godotScriptRegisterMethod(getNativeLibHandle(), classNameLit,
cstring"_refcount_decremented",
GodotMethodAttributes(), refDec)
result.add(getAst(registerRefIncDec(classNameLit)))
{.push warning[Deprecated]: off.}
# immediate macros are deprecated, but `untyped` doesnt make it immediate,
# immediate macros are deprecated, but `untyped` doesn't make it immediate,
# as the warning and the documentation claim.
macro gdobj*(definition: untyped, body: typed): typed {.immediate.} =
## Generates Godot type. Self-documenting example:
##
## .. code-block:: nim
## import godot, node
##
## gdobj MyObj of Node:
## var myField: int
## ## Not exported to Godot (i.e. editor will not see this field).
##
## var myString* {.gdExport, hint: Length, tip: "20".}: string
## ## Exported to Godot as ``my_string``.
## ## Editor will limit this string to length 20.
## ## ``hint` is a value of ``GodotPropertyHint`` enum.
## ## ``tip`` depends on the value of ``hint``, its format is described
## ## in ``GodotPropertyHint`` documentation.
##
## method ready*() =
## ## Exported methods are exported to Godot by default,
## ## and their Godot names are prefixed with ``_``
## ## (in this case ``_ready``)
## print("I am ready! myString is: " & myString)
##
## proc myProc*() {.gdExport.} =
## ## Exported to Godot as ``my_proc``
## print("myProc is called! Incrementing myField.")
## inc myField
##
## If parent type is omitted, the type is inherited from ``Object``.
##
## ``tool`` specifier can be added to mark the type as an
## `editor plugin <https://godot.readthedocs.io/en/stable/development/plugins/making_plugins.html>`_:
##
## .. code-block:: nim
## import godot, editor_plugin
##
## gdobj(MyTool of EditorPlugin, tool):
## method enterTree*() =
## print("MyTool initialized!")
##
## Objects can be instantiated by invoking
## `gdnew <godotnim.html#gdnew>`_ or by using
## `load <godotapi/resource_loader.html#load,string,string,bool>`_ or any other way
## that you can find in `Godot API <index.html#modules-godot-api>`_.
let typeDef = parseType(definition, callsite())
result = genType(typeDef)
{.push warning[Deprecated]: on.}

View file

@ -10,15 +10,28 @@ import core.vector2, core.rect2,
core.arrays, core.poolarrays, core.variants
import godotinternal
## Definition of NimGodotObject and converters for built-in types.
## This module defines ``NimGodotObject`` and ``toVariant``/``fromVariant``
## converters for Nim types. The converters are used by
## `gdobj <godotmacros.html#gdobj.m,untyped,typed>`_ macro to import/export
## values from/to Godot (editor, GDScript).
##
## You can also allow conversion of any custom type ``MyType`` by implementing:
##
## .. code-block:: nim
## proc variantType*(T: typedesc[MyType]): VariantType
## proc toVariant*(self: MyType): Variant
## proc fromVariant*(self: var MyType, val: Variant): ConversionResult
type
NimGodotObject* = ref object of RootObj
## The base type all Godot types inherit from.
## Manages lifecycle of the wrapped GodotObject.
godotObject: ptr GodotObject
isExternalRef: bool
isOwn: bool
ConversionResult* {.pure.} = enum
## Conversion result to return from ``fromVariant`` procedure.
OK,
TypeError,
## Type mismatch
@ -41,7 +54,11 @@ type
SomeGodotOrNum = SomeGodot or SomeSignedInt or SomeUnsignedInt or SomeFloat
CallError* = object of Exception
## Raised by wrappers in case of an incorrect dynamic invocation.
## For example, if incorrect number of arguments were passed or they had
## unexpected types.
err*: VariantCallError
## The error as returned by Godot
ObjectInfo = object
constructor: proc(): NimGodotObject {.gcsafe, nimcall.}
@ -49,20 +66,24 @@ type
isNative: bool
isRef: bool
template printWarning*(warn: typed) =
template printWarning*(warning: typed) =
## Prints ``warning`` to Godot log, adding filename and line information.
let (filename, line) = instantiationInfo()
godotPrintWarning(cstring($warn), nil, cstring(filename), line.cint)
godotPrintWarning(cstring($warning), nil, cstring(filename), line.cint)
template printError*(err: typed) =
template printError*(error: typed) =
## Prints ``error`` to Godot log, adding filename and line information.
let (filename, line) = instantiationInfo()
godotPrintError(cstring($err), nil, cstring(filename), line.cint)
godotPrintError(cstring($error), nil, cstring(filename), line.cint)
proc print*(message: string) {.inline.} =
## Prints ``message`` to Godot log.
var s = message.toGodotString()
godotPrint(s)
s.deinit()
proc print*(message: cstring) {.inline.} =
## Prints ``message`` to Godot log.
var s = message.toGodotString()
godotPrint(s)
s.deinit()
@ -141,7 +162,9 @@ macro isReference(T: typedesc): bool =
else: ident("false")
template registerClass*(T: typedesc; godotClassName: cstring,
isNativeParam: bool) =
native: bool) =
## Registers the specified Godot type.
## Used by ``gdobj`` macro and `godotapigen <godotapigen.html>`_.
if classRegistry.isNil:
classRegistry = newTable[cstring, ObjectInfo]()
let constructor = proc(): NimGodotObject =
@ -154,21 +177,21 @@ template registerClass*(T: typedesc; godotClassName: cstring,
let objInfo = ObjectInfo(
constructor: constructor,
baseNativeClass: base,
isNative: isNativeParam,
isNative: native,
isRef: isRef
)
classRegistry[godotClassName] = objInfo
static:
let objInfoStatic = ObjectInfo(
baseNativeClass: base,
isNative: isNativeParam,
isRef: isRef
isNative: native,
isRef: isRef,
)
classRegistryStatic[godotClassName] = objInfoStatic
when isRef:
static:
refClasses.add(T.name)
when isNativeParam:
when native:
static:
nativeClasses.add(T.name)
@ -187,6 +210,9 @@ proc newNimGodotObject[T: NimGodotObject](
result.godotObject.reference()
proc asNimGodotObject*[T: NimGodotObject](godotObject: ptr GodotObject): T =
## Wraps ``godotObject`` into Nim type ``T``.
## This is used by `godotapigen <godotapigen.html>`_ and should rarely be
## used by anything else.
if godotObject.isNil: return nil
let userDataPtr = godotObject.getUserData()
if not userDataPtr.isNil:
@ -202,15 +228,24 @@ proc newVariant*(obj: NimGodotObject): Variant {.inline.} =
newVariant(obj.godotObject)
proc asObject*[T: NimGodotObject](v: Variant): T {.inline.} =
## Converts ``v`` to object of type ``T``.
## Returns ``nil`` if the conversion cannot be performed
## (``v``'s type is not an Object or it's an object of an incompatible type)
asNimGodotObject[T](v.asGodotObject())
proc asObject*(v: Variant, T: typedesc[NimGodotObject]): T {.inline.} =
## Converts ``v`` to object of type ``T``.
## Returns ``nil`` if the conversion cannot be performed
## (``v``'s type is not an Object or it's an object of an incompatible type)
asNimGodotObject[T](v.asGodotObject())
proc `as`*[T: NimGodotObject](obj: NimGodotObject, t: typedesc[T]): T =
## Converts the ``obj`` into the specified type.
## Returns ``nil`` if the conversion cannot be performed
## (the ``obj`` is not of the type ``T``)
##
## This can be used either in dot notation (``node.as(Button)``) or
## infix notation (``node as Button``).
if obj.isNil or not (obj of T):
when not defined(release):
if not obj.isNil:
@ -220,9 +255,6 @@ proc `as`*[T: NimGodotObject](obj: NimGodotObject, t: typedesc[T]): T =
else:
result = T(obj)
proc getSingletonGodot*(name: cstring): ptr GodotObject {.
importc: "godot_global_get_singleton".}
proc newRStrLit(s: string): NimNode {.compileTime.} =
result = newNimNode(nnkRStrLit)
result.strVal = s
@ -241,8 +273,11 @@ macro toGodotName(T: typedesc): cstring =
ident("cstring"), newRStrLit(godotName))
proc getSingleton*[T: NimGodotObject](): T =
## Returns singleton of type ``T``. Normally, this should not be used,
## because `godotapigen <godotapigen.html>`_ wraps singleton methods so that
## singleton objects don't have to be provided as parameters.
const godotName = toGodotName(T)
let singleton = getSingletonGodot(godotName)
let singleton = getGodotSingleton(godotName)
if singleton.isNil:
printError("Tried to get non-existing singleton of type " & $godotName)
else:
@ -285,6 +320,7 @@ proc newOwnObj[T: NimGodotObject](name: cstring): T =
ret.deinit()
proc gdnew*[T: NimGodotObject](): T =
## Instantiates new object of type ``T``.
const godotName = toGodotName(T)
const objInfo = classRegistryStatic[godotName]
result = when objInfo.isNative:
@ -292,6 +328,7 @@ proc gdnew*[T: NimGodotObject](): T =
else: newOwnObj[T](godotName)
proc newCallError*(err: VariantCallError): ref CallError =
## Instantiates ``CallError`` from Godot ``err``.
let msg = case err.error:
of VariantCallErrorType.OK,
VariantCallErrorType.InvalidMethod,
@ -307,6 +344,8 @@ proc newCallError*(err: VariantCallError): ref CallError =
result.err = err
proc newConversionError*(err: ConversionResult): ref ValueError =
## Instantiates error raised by `godotapigen <godotapigen.html>`_
## generated code in case of a conversion error.
let msg = case err:
of ConversionResult.TypeError:
"Failed to convert the return value into Nim type"
@ -317,28 +356,32 @@ proc newConversionError*(err: ConversionResult): ref ValueError =
result = newException(ValueError, msg)
proc removeGodotObject*(nimObj: NimGodotObject) {.inline.} =
## Used from destructor
nimObj.godotObject = nil
proc setGodotObject*(nimObj: NimGodotObject, obj: ptr GodotObject) {.inline.} =
## Used from Godot constructor. Don't call this.
assert(not obj.isNil)
assert(nimObj.godotObject.isNil) # reassignment is not allowed
nimObj.godotObject = obj
proc setOwn*(nimObj: NimGodotObject) {.inline.} =
## Used from Godot constructor. Don't call this.
nimObj.isOwn = true
proc removeGodotObject*(nimObj: NimGodotObject) {.inline.} =
## Used from Godot destructor. Don't call this.
nimObj.godotObject = nil
proc godotObject*(nimObj: NimGodotObject): ptr GodotObject {.inline.} =
## Returns internal poitner to ``GodotObject``. Use only if you know what
## you are doing.
nimObj.godotObject
proc godotVariantType*(T: typedesc[NimGodotObject]): VariantType {.inline.} =
proc variantType*(T: typedesc[NimGodotObject]): VariantType {.inline.} =
VariantType.Object
proc toGodot*(self: NimGodotObject): Variant {.inline.} =
proc toVariant*(self: NimGodotObject): Variant {.inline.} =
newVariant(self.godotObject)
proc fromGodot*[T: NimGodotObject](self: var T,
proc fromVariant*[T: NimGodotObject](self: var T,
val: Variant): ConversionResult =
if val.getType() == VariantType.Object:
let objPtr = val.asGodotObject()
@ -350,27 +393,27 @@ proc fromGodot*[T: NimGodotObject](self: var T,
else:
result = ConversionResult.TypeError
proc godotVariantType*(T: typedesc[enum]): VariantType {.inline.} =
proc variantType*(T: typedesc[enum]): VariantType {.inline.} =
VariantType.Int
proc toGodot*[T: enum](self: T): Variant {.inline.} =
proc toVariant*[T: enum](self: T): Variant {.inline.} =
newVariant(int64(ord(self)))
proc fromGodot*[T: enum](self: var T,
proc fromVariant*[T: enum](self: var T,
val: Variant): ConversionResult {.inline.} =
if val.getType() == VariantType.Int:
self = T(val.asInt())
else:
result = ConversionResult.TypeError
proc toGodot*(self: Variant): Variant {.inline.} =
proc toVariant*(self: Variant): Variant {.inline.} =
self
proc fromGodot*(self: var Variant,
proc fromVariant*(self: var Variant,
val: Variant): ConversionResult {.inline.} =
self = newVariant(val)
proc godotVariantType*(T: typedesc[SomeGodotOrNum]): VariantType {.inline.} =
proc variantType*(T: typedesc[SomeGodotOrNum]): VariantType {.inline.} =
when T is SomeSignedInt or T is SomeUnsignedInt:
VariantType.Int
elif T is bool:
@ -426,10 +469,10 @@ proc godotVariantType*(T: typedesc[SomeGodotOrNum]): VariantType {.inline.} =
else:
VariantType.Nil
proc toGodot*[T: SomeGodotOrNum](val: T): Variant {.inline.} =
proc toVariant*[T: SomeGodotOrNum](val: T): Variant {.inline.} =
newVariant(val)
proc fromGodot*[T: SomeSignedInt or SomeUnsignedInt](
proc fromVariant*[T: SomeSignedInt or SomeUnsignedInt](
self: var T, val: Variant): ConversionResult =
if val.getType() != VariantType.Int:
result = ConversionResult.TypeError
@ -443,7 +486,7 @@ proc fromGodot*[T: SomeSignedInt or SomeUnsignedInt](
else:
self = T(intVal)
proc fromGodot*[T: SomeFloat](self: var T, val: Variant): ConversionResult =
proc fromVariant*[T: SomeFloat](self: var T, val: Variant): ConversionResult =
if val.getType() == VariantType.Real:
self = T(val.asReal())
elif val.getType() == VariantType.Int:
@ -451,8 +494,8 @@ proc fromGodot*[T: SomeFloat](self: var T, val: Variant): ConversionResult =
else:
result = ConversionResult.TypeError
proc fromGodot*[T: SomeGodot](self: var T, val: Variant): ConversionResult =
if godotVariantType(T) != val.getType():
proc fromVariant*[T: SomeGodot](self: var T, val: Variant): ConversionResult =
if variantType(T) != val.getType():
return ConversionResult.TypeError
when self is bool:
self = val.asBool()
@ -506,13 +549,13 @@ proc fromGodot*[T: SomeGodot](self: var T, val: Variant): ConversionResult =
# mustn't reach this
result = ConversionError.TypeError
proc godotVariantType*(T: typedesc[string]): VariantType {.inline.} =
proc variantType*(T: typedesc[string]): VariantType {.inline.} =
VariantType.String
proc toGodot*(s: string): Variant {.inline.} =
proc toVariant*(s: string): Variant {.inline.} =
newVariant(s)
proc fromGodot*(s: var string, val: Variant): ConversionResult =
proc fromVariant*(s: var string, val: Variant): ConversionResult =
if val.getType() == VariantType.String:
s = val.asString()
elif val.getType() == VariantType.Nil:
@ -520,20 +563,20 @@ proc fromGodot*(s: var string, val: Variant): ConversionResult =
else:
result = ConversionResult.TypeError
proc godotVariantType*(T: typedesc[seq]): VariantType =
proc variantType*(T: typedesc[seq]): VariantType =
VariantType.Array
proc godotVariantType*(T: typedesc[array]): VariantType =
proc variantType*(T: typedesc[array]): VariantType =
VariantType.Array
proc toGodot*[T](s: openarray[T]): Variant =
proc toVariant*[T](s: openarray[T]): Variant =
var arr = newArray()
mixin toGodot
for item in s:
arr.add(toGodot(item))
arr.add(toVariant(item))
result = newVariant(arr)
proc fromGodot*[T](s: var seq[T], val: Variant): ConversionResult =
proc fromVariant*[T](s: var seq[T], val: Variant): ConversionResult =
if val.getType() != VariantType.Array:
result = ConversionResult.TypeError
else:
@ -541,12 +584,12 @@ proc fromGodot*[T](s: var seq[T], val: Variant): ConversionResult =
s = newSeq[T](arr.len)
for idx, item in arr:
mixin fromGodot
let convResult = fromGodot(s[idx], item)
let convResult = fromVariant(s[idx], item)
if convResult != ConversionResult.OK:
s = nil
return convResult
proc fromGodot*[T: array](s: var T, val: Variant): ConversionResult =
proc fromVariant*[T: array](s: var T, val: Variant): ConversionResult =
if val.getType() != VariantType.Array:
result = ConversionResult.TypeError
else:
@ -555,21 +598,21 @@ proc fromGodot*[T: array](s: var T, val: Variant): ConversionResult =
return ConversionResult.TypeError
for idx, item in arr:
mixin fromGodot
let convResult = fromGodot(s[idx], item)
let convResult = fromVariant(s[idx], item)
if convResult != ConversionResult.OK:
return convResult
proc godotVariantType*(T: typedesc[Table|TableRef]): VariantType {.inline.} =
proc variantType*(T: typedesc[Table|TableRef]): VariantType {.inline.} =
VariantType.Dictionary
proc toGodot*[T: Table or TableRef](t: T): Variant =
proc toVariant*[T: Table or TableRef](t: T): Variant =
var dict = newDictionary()
mixin toGodot
for k, v in t.pairs():
dict[toGodot(k)] = toGodot(v)
dict[toVariant(k)] = toVariant(v)
result = newVariant(dict)
proc fromGodot*[T: Table or TableRef](t: var T, val: Variant): ConversionResult =
proc fromVariant*[T: Table or TableRef](t: var T, val: Variant): ConversionResult =
if val.getType() != VariantType.Dictionary:
result = ConversionResult.TypeError
else:
@ -582,31 +625,18 @@ proc fromGodot*[T: Table or TableRef](t: var T, val: Variant): ConversionResult
for k, v in dict:
var nimKey: type(t.keys())
var nimVal: type(t.values())
let keyResult = fromGodot(nimKey, k)
let keyResult = fromVariant(nimKey, k)
if keyResult != ConversionResult.OK:
when t is ref:
t = nil
return keyResult
let valResult = fromGodot(nimVal, v)
let valResult = fromVariant(nimVal, v)
if valResult != ConversionResult.OK:
when t is ref:
t = nil
return valResult
t[nimKey] = nimVal
proc godotToNim*[T](val: Variant): (T, ConversionResult) =
mixin fromGodot
result[1] = fromGodot(result[0], val)
proc nimToGodot*[T](val: T): Variant =
mixin toGodot
when compiles(toGodot(val)):
result = toGodot(val)
else:
printError("Failed to convert Nim value of type " & T.name &
" into Variant")
initNilVariant(result)
{.emit: """/*TYPESECTION*/
void NimMain(void);
N_NOINLINE(void, setStackBottom)(void* thestackbottom);
@ -614,6 +644,8 @@ N_NOINLINE(void, setStackBottom)(void* thestackbottom);
var nativeLibHandle: pointer
proc getNativeLibHandle*(): pointer =
## Returns NativeScript library handle used to register type information
## in Godot. Use only if you know what you are doing.
return nativeLibHandle
proc godot_nativescript_init(handle: pointer) {.

1
godot/nim/nim.cfg Normal file
View file

@ -0,0 +1 @@
--path:"$projectdir/../"

5
godot/nimdoc.cfg Normal file
View file

@ -0,0 +1,5 @@
doc.item.seesrc = """&nbsp;&nbsp;<a
href="${url}/tree/${commit}/${path}#L${line}"
class="link-seesrc" target="_blank">Source</a>
<a href="${url}/edit/master/${path}#L${line}" class="link-seesrc" target="_blank" >Edit</a>
"""