Compare commits

...

25 commits

Author SHA1 Message Date
Ruslan Mustakov
4175dbb3e5 Bump version to 0.8.2 2021-05-03 23:18:50 +07:00
7eadb07820 Move template below arrays import
Fixes #81 

Alternate workaround for https://github.com/nim-lang/Nim/issues/16462 without changing VariantType.
2021-05-03 23:17:18 +07:00
Jason
00d8ac2691 Support nim case insensitivy in pragmas 2021-03-12 11:09:55 +07:00
Arun Dilipan
388bea9205 Added moveToward for vectors. 2020-12-13 12:13:41 +07:00
ShalokShalom
f25c3c7a5d Clarify version compability
One guy in the chat just asked me, if this binding is for 3.0 only, or also for 3.2.3
2020-10-17 13:22:31 +07:00
Ruslan Mustakov
d3e5f91b40 Fix wrapping methods with Array return types 2020-08-14 01:44:48 +07:00
Ruslan Mustakov
3f46e3c648 Break reference cycle in NimGodotObject 2020-06-05 16:53:34 +07:00
Ruslan Mustakov
87707a86b4 Remove Travis badge from README
Need to fix the CI script.
2020-06-03 18:06:18 +07:00
Ruslan Mustakov
031774f54f More efficient and GC-safe conversions in API generator 2020-06-03 17:58:47 +07:00
Ruslan Mustakov
ed9ede5cb3 Up version to 0.7.27 2020-02-05 12:34:44 +07:00
Konstantin Zaitsev
a49fcbdac7 Fix variant size for 32bit platform with memory alignment 2020-02-05 11:36:42 +07:00
zetashift
157a90e4a0
add gensym in hygienic template fix thanks to demotohiro (#55)
Add gensym in hygienic template fix thanks to demotohiro
2020-02-05 11:35:50 +07:00
Ruslan Mustakov
d1b82d351c Fix unsigned int conversion to/from Variant 2019-12-23 20:53:13 +07:00
Ruslan Mustakov
78d3626fa3 Do not log error when casting fails
This allows not to perform unnecessary 'of' check before
casting, if cast failure is expected.
2019-12-04 23:58:13 +07:00
Ruslan Mustakov
1b8e7ccd98 Add variant conversion for Option[T] 2019-10-02 15:26:41 +07:00
Ruslan Mustakov
c2db807da4 Up version to 0.7.23 2019-09-20 09:20:50 +07:00
Dwana Games
7dd1b1ed5f Add self to field initialization 2019-09-20 09:20:27 +07:00
Ruslan Mustakov
2f3f4034cf Fix newVariant for nil strings and older Nim 2019-09-18 13:27:31 +07:00
Ruslan Mustakov
19b0c23d62 Finalize support for Nim 0.20
Closes #32, closes #41.
2019-09-15 20:11:15 +07:00
Dwana Games
0fecfdb3b8 Updated to work with nim 0.20
- Attempt to fix deprecated this:self pragma by injecting self to methods and properties (needs more testing)
- Changed import headers to use / (slash) instead of . (period)
- Fixed object branch in godotapigen.nim
- Fixed deprecated nimNode.ident with nimNode.strVal

Fix toGodotName function

Consider procCall calls as special cases, otherwise it gives problems in _init function

Fix infinite recursive call in Godot 3.2
2019-09-15 15:34:09 +07:00
zetashift
34fda99def Small changes to add 0.18.0 compatibility
Change toGodotName back to macro because that got fixed in devel

change isSome to isNone in godotapigen
2019-09-15 15:33:59 +07:00
Fabian Keller
3a935b9308 attempt to make 0.19 compatible
workaround for nim/macro/typedesc issue

work-around for nim-lang/Nim#7375

fixed more isNil usages

fixed new name of setStackBottom
2019-09-15 15:33:44 +07:00
Konstantin Zaitsev
f45281f5a0 Fix possible double free memory on exit 2019-09-12 18:59:11 +07:00
Ruslan Mustakov
db4bb91765 Fix editor crash in multithreaded mode 2019-07-09 13:48:54 +07:00
Ruslan Mustakov
e9d73d8ec4 Fix GDNative API procedure declarations
Earlier signature mismatch caused problems on macOS with Godot 3.1.
2018-10-11 19:06:05 +07:00
32 changed files with 880 additions and 645 deletions

View file

@ -1,6 +1,6 @@
# Nim bindings for Godot Engine [![Build Status](https://travis-ci.org/pragmagic/godot-nim.svg?branch=master)](https://travis-ci.org/pragmagic/godot-nim) # Nim bindings for Godot Engine
Nim bindings for Godot 3.0 based on [GDNative](https://godotengine.org/article/dlscript-here). Nim bindings for Godot 3 based on [GDNative](https://godotengine.org/article/dlscript-here).
Documentation: https://pragmagic.github.io/godot-nim/ Documentation: https://pragmagic.github.io/godot-nim/

View file

@ -71,7 +71,7 @@ proc fixupHrefs(file: string) =
proc getGitHash(): string = proc getGitHash(): string =
result = execProcess("git rev-parse HEAD") result = execProcess("git rev-parse HEAD")
if not result.isNil and result.len > 0: if result.len > 0:
result = result.replace("\L", "").replace("\r", "") result = result.replace("\L", "").replace("\r", "")
proc buildDocs*(outDir, godotNimDir, godotBin: string) = proc buildDocs*(outDir, godotNimDir, godotBin: string) =
@ -112,7 +112,7 @@ proc buildDocs*(outDir, godotNimDir, godotBin: string) =
var gitHash: string var gitHash: string
withDir(godotBinAbs.parentDir()): withDir(godotBinAbs.parentDir()):
gitHash = getGitHash() gitHash = getGitHash()
if gitHash.isNil or gitHash.len == 0: if gitHash.len == 0:
raise newException(Exception, raise newException(Exception,
"Godot executable is not under Git repository") "Godot executable is not under Git repository")

View file

@ -1,4 +1,4 @@
version = "0.7.17" version = "0.8.2"
author = "Xored Software, Inc." author = "Xored Software, Inc."
description = "Godot Engine bindings" description = "Godot Engine bindings"
license = "MIT" license = "MIT"

View file

@ -3,7 +3,7 @@
import hashes import hashes
import vector3 import vector3
import internal.godotinternaltypes, internal.godotstrings import internal/godotinternaltypes, internal/godotstrings
import godotcoretypes, gdnativeapi import godotcoretypes, gdnativeapi
proc initAABB*(pos, size: Vector3): AABB {.inline.} = proc initAABB*(pos, size: Vector3): AABB {.inline.} =
@ -31,10 +31,10 @@ proc encloses*(self, other: AABB): bool {.inline.} =
getGDNativeAPI().aabbEncloses(self, other) getGDNativeAPI().aabbEncloses(self, other)
proc merge*(self, other: AABB): AABB {.inline.} = proc merge*(self, other: AABB): AABB {.inline.} =
getGDNativeAPI().aabbMerge(self, other) getGDNativeAPI().aabbMerge(self, other).toAABB()
proc intersection*(self, other: AABB): AABB {.inline.} = proc intersection*(self, other: AABB): AABB {.inline.} =
getGDNativeAPI().aabbIntersection(self, other) getGDNativeAPI().aabbIntersection(self, other).toAABB()
proc intersectsPlane*(self: AABB; plane: Plane): bool {.inline.} = proc intersectsPlane*(self: AABB; plane: Plane): bool {.inline.} =
getGDNativeAPI().aabbIntersectsPlane(self, plane) getGDNativeAPI().aabbIntersectsPlane(self, plane)
@ -46,10 +46,10 @@ proc contains*(self: AABB; point: Vector3): bool {.inline.} =
getGDNativeAPI().aabbHasPoint(self, point) getGDNativeAPI().aabbHasPoint(self, point)
proc getSupport*(self: AABB; dir: Vector3): Vector3 {.inline.} = proc getSupport*(self: AABB; dir: Vector3): Vector3 {.inline.} =
getGDNativeAPI().aabbGetSupport(self, dir) getGDNativeAPI().aabbGetSupport(self, dir).toVector3()
proc getLongestAxis*(self: AABB): Vector3 {.inline.} = proc getLongestAxis*(self: AABB): Vector3 {.inline.} =
getGDNativeAPI().aabbGetLongestAxis(self) getGDNativeAPI().aabbGetLongestAxis(self).toVector3()
proc getLongestAxisIndex*(self: AABB): cint {.inline.} = proc getLongestAxisIndex*(self: AABB): cint {.inline.} =
getGDNativeAPI().aabbGetLongestAxisIndex(self) getGDNativeAPI().aabbGetLongestAxisIndex(self)
@ -58,7 +58,7 @@ proc getLongestAxisSize*(self: AABB): float32 {.inline.} =
getGDNativeAPI().aabbGetLongestAxisSize(self) getGDNativeAPI().aabbGetLongestAxisSize(self)
proc getShortestAxis*(self: AABB): Vector3 {.inline.} = proc getShortestAxis*(self: AABB): Vector3 {.inline.} =
getGDNativeAPI().aabbGetShortestAxis(self) getGDNativeAPI().aabbGetShortestAxis(self).toVector3()
proc getShortestAxisIndex*(self: AABB): cint {.inline.} = proc getShortestAxisIndex*(self: AABB): cint {.inline.} =
getGDNativeAPI().aabbGetShortestAxisIndex(self) getGDNativeAPI().aabbGetShortestAxisIndex(self)
@ -67,13 +67,13 @@ proc getShortestAxisSize*(self: AABB): float32 {.inline.} =
getGDNativeAPI().aabbGetShortestAxisSize(self) getGDNativeAPI().aabbGetShortestAxisSize(self)
proc expand*(self: AABB; toPoint: Vector3): AABB {.inline.} = proc expand*(self: AABB; toPoint: Vector3): AABB {.inline.} =
getGDNativeAPI().aabbExpand(self, toPoint) getGDNativeAPI().aabbExpand(self, toPoint).toAABB()
proc grow*(self: AABB; by: float32): AABB {.inline.} = proc grow*(self: AABB; by: float32): AABB {.inline.} =
getGDNativeAPI().aabbGrow(self, by) getGDNativeAPI().aabbGrow(self, by).toAABB()
proc getEndpoint*(self: AABB; idx: cint): Vector3 {.inline.} = proc getEndpoint*(self: AABB; idx: cint): Vector3 {.inline.} =
getGDNativeAPI().aabbGetEndpoint(self, idx) getGDNativeAPI().aabbGetEndpoint(self, idx).toVector3()
proc `==`*(a, b: AABB): bool {.inline.} = proc `==`*(a, b: AABB): bool {.inline.} =
getGDNativeAPI().aabbOperatorEqual(a, b) getGDNativeAPI().aabbOperatorEqual(a, b)

View file

@ -1,7 +1,7 @@
# Copyright 2018 Xored Software, Inc. # Copyright 2018 Xored Software, Inc.
import hashes import hashes
import internal.godotinternaltypes, internal.godotarrays import internal/godotinternaltypes, internal/godotarrays
type type
Array* = ref object Array* = ref object

View file

@ -64,16 +64,16 @@ proc gray*(self: Color): float32 {.inline.} =
getGDNativeAPI().colorGray(self) getGDNativeAPI().colorGray(self)
proc inverted*(self: Color): Color {.inline.} = proc inverted*(self: Color): Color {.inline.} =
getGDNativeAPI().colorInverted(self) getGDNativeAPI().colorInverted(self).toColor()
proc contrasted*(self: Color): Color {.inline.} = proc contrasted*(self: Color): Color {.inline.} =
getGDNativeAPI().colorContrasted(self) getGDNativeAPI().colorContrasted(self).toColor()
proc lerp*(self: Color; b: Color; t: float32): Color {.inline.} = proc lerp*(self: Color; b: Color; t: float32): Color {.inline.} =
getGDNativeAPI().colorLinearInterpolate(self, b, t) getGDNativeAPI().colorLinearInterpolate(self, b, t).toColor()
proc blend*(self: Color; over: Color): Color {.inline.} = proc blend*(self: Color; over: Color): Color {.inline.} =
getGDNativeAPI().colorBlend(self, over) getGDNativeAPI().colorBlend(self, over).toColor()
proc `==`*(a, b: Color): bool {.inline.} = proc `==`*(a, b: Color): bool {.inline.} =
a.r == b.r and a.g == b.g and a.b == b.b and a.a == b.a a.r == b.r and a.g == b.g and a.b == b.b and a.a == b.a

View file

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

View file

@ -30,6 +30,9 @@ proc stepify*(value, step: float32): float32 {.inline, noinit.} =
else: else:
value value
when (NimMajor, NimMinor, NimPatch) < (0, 20, 4):
# Newer Nim has these procs in system module
proc min*(x, y: float32): float32 {.inline, noinit.} = proc min*(x, y: float32): float32 {.inline, noinit.} =
if x <= y: x else: y if x <= y: x else: y

View file

@ -2,8 +2,8 @@
import hashes import hashes
import internal.godotinternaltypes, internal.godotnodepaths, import internal/godotinternaltypes, internal/godotnodepaths,
internal.godotstrings internal/godotstrings
type type
NodePath* = ref object NodePath* = ref object

View file

@ -4,7 +4,7 @@ import hashes
import vector3 import vector3
import internal.godotinternaltypes, internal.godotstrings import internal/godotinternaltypes, internal/godotstrings
import godotcoretypes, gdnativeapi import godotcoretypes, gdnativeapi
proc initPlane*(a, b, c, d: float32): Plane {.inline.} = proc initPlane*(a, b, c, d: float32): Plane {.inline.} =
@ -26,13 +26,13 @@ proc hash*(self: Plane): Hash {.inline, noinit.} =
!$(self.normal.hash() !& self.d.hash()) !$(self.normal.hash() !& self.d.hash())
proc normalized*(self: Plane): Plane {.inline.} = proc normalized*(self: Plane): Plane {.inline.} =
getGDNativeAPI().planeNormalized(self) getGDNativeAPI().planeNormalized(self).toPlane()
proc center*(self: Plane): Vector3 {.inline.} = proc center*(self: Plane): Vector3 {.inline.} =
getGDNativeAPI().planeCenter(self) getGDNativeAPI().planeCenter(self).toVector3()
proc getAnyPoint*(self: Plane): Vector3 {.inline.} = proc getAnyPoint*(self: Plane): Vector3 {.inline.} =
getGDNativeAPI().planeGetAnyPoint(self) getGDNativeAPI().planeGetAnyPoint(self).toVector3()
proc isPointOver*(self: Plane; point: Vector3): bool {.inline.} = proc isPointOver*(self: Plane; point: Vector3): bool {.inline.} =
getGDNativeAPI().planeIsPointOver(self, point) getGDNativeAPI().planeIsPointOver(self, point)
@ -45,7 +45,7 @@ proc contains*(self: Plane; point: Vector3;
getGDNativeAPI().planeHasPoint(self, point, epsilon) getGDNativeAPI().planeHasPoint(self, point, epsilon)
proc project*(self: Plane; point: Vector3): Vector3 {.inline.} = proc project*(self: Plane; point: Vector3): Vector3 {.inline.} =
getGDNativeAPI().planeProject(self, point) getGDNativeAPI().planeProject(self, point).toVector3()
proc intersect3*(self: Plane; dest: var Vector3; proc intersect3*(self: Plane; dest: var Vector3;
b, c: Plane): bool {.inline.} = b, c: Plane): bool {.inline.} =
@ -60,7 +60,7 @@ proc intersectsSegment*(self: Plane; dest: var Vector3;
getGDNativeAPI().planeIntersectsSegment(self, dest, segmentBegin, segmentEnd) getGDNativeAPI().planeIntersectsSegment(self, dest, segmentBegin, segmentEnd)
proc `-`*(self: Plane): Plane {.inline.} = proc `-`*(self: Plane): Plane {.inline.} =
getGDNativeAPI().planeOperatorNeg(self) getGDNativeAPI().planeOperatorNeg(self).toPlane()
proc `==`*(a, b: Plane): bool {.inline.} = proc `==`*(a, b: Plane): bool {.inline.} =
getGDNativeAPI().planeOperatorEqual(a, b) getGDNativeAPI().planeOperatorEqual(a, b)

View file

@ -3,8 +3,8 @@
import hashes import hashes
import godotcoretypes import godotcoretypes
import internal.godotinternaltypes, internal.godotpoolarrays, import internal/godotinternaltypes, internal/godotpoolarrays,
internal.godotstrings internal/godotstrings
import vector2, vector3, colors import vector2, vector3, colors
template definePoolArrayBase(T, GodotT, DataT, fieldName, newProcName, template definePoolArrayBase(T, GodotT, DataT, fieldName, newProcName,
@ -35,6 +35,30 @@ template definePoolArrayBase(T, GodotT, DataT, fieldName, newProcName,
(when type(item) is GodotString: ($item).hash() else: item.hash()) (when type(item) is GodotString: ($item).hash() else: item.hash())
result = !$result result = !$result
definePoolArrayBase(PoolByteArray, GodotPoolByteArray, uint8,
godotPoolByteArray, newPoolByteArray,
initGodotPoolByteArray)
definePoolArrayBase(PoolIntArray, GodotPoolIntArray, cint,
godotPoolIntArray, newPoolIntArray,
initGodotPoolIntArray)
definePoolArrayBase(PoolRealArray, GodotPoolRealArray, float32,
godotPoolRealArray, newPoolRealArray,
initGodotPoolRealArray)
definePoolArrayBase(PoolVector2Array, GodotPoolVector2Array, Vector2,
godotPoolVector2Array, newPoolVector2Array,
initGodotPoolVector2Array)
definePoolArrayBase(PoolVector3Array, GodotPoolVector3Array, Vector3,
godotPoolVector3Array, newPoolVector3Array,
initGodotPoolVector3Array)
definePoolArrayBase(PoolColorArray, GodotPoolColorArray, Color,
godotPoolColorArray, newPoolColorArray,
initGodotPoolColorArray)
definePoolArrayBase(PoolStringArray, GodotPoolStringArray, string,
godotPoolStringArray, newPoolStringArray,
initGodotPoolStringArray)
import arrays
template definePoolArray(T, GodotT, DataT, fieldName, newProcName, initProcName; template definePoolArray(T, GodotT, DataT, fieldName, newProcName, initProcName;
noData = false) = noData = false) =
@ -92,30 +116,6 @@ template definePoolArray(T, GodotT, DataT, fieldName, newProcName, initProcName;
for pair in arr.fieldName.mpairs: for pair in arr.fieldName.mpairs:
yield (pair[0].int, pair[1]) yield (pair[0].int, pair[1])
definePoolArrayBase(PoolByteArray, GodotPoolByteArray, uint8,
godotPoolByteArray, newPoolByteArray,
initGodotPoolByteArray)
definePoolArrayBase(PoolIntArray, GodotPoolIntArray, cint,
godotPoolIntArray, newPoolIntArray,
initGodotPoolIntArray)
definePoolArrayBase(PoolRealArray, GodotPoolRealArray, float32,
godotPoolRealArray, newPoolRealArray,
initGodotPoolRealArray)
definePoolArrayBase(PoolVector2Array, GodotPoolVector2Array, Vector2,
godotPoolVector2Array, newPoolVector2Array,
initGodotPoolVector2Array)
definePoolArrayBase(PoolVector3Array, GodotPoolVector3Array, Vector3,
godotPoolVector3Array, newPoolVector3Array,
initGodotPoolVector3Array)
definePoolArrayBase(PoolColorArray, GodotPoolColorArray, Color,
godotPoolColorArray, newPoolColorArray,
initGodotPoolColorArray)
definePoolArrayBase(PoolStringArray, GodotPoolStringArray, string,
godotPoolStringArray, newPoolStringArray,
initGodotPoolStringArray)
import arrays
definePoolArray(PoolByteArray, GodotPoolByteArray, uint8, definePoolArray(PoolByteArray, GodotPoolByteArray, uint8,
godotPoolByteArray, newPoolByteArray, godotPoolByteArray, newPoolByteArray,
initGodotPoolByteArray) initGodotPoolByteArray)

View file

@ -2,7 +2,7 @@
import hashes import hashes
import internal.godotinternaltypes, internal.godotstrings import internal/godotinternaltypes, internal/godotstrings
import godotcoretypes, gdnativeapi import godotcoretypes, gdnativeapi
proc initQuat*(x, y, z, w: float32): Quat {.inline.} = proc initQuat*(x, y, z, w: float32): Quat {.inline.} =
@ -29,50 +29,50 @@ proc lengthSquared*(self: Quat): float32 {.inline.} =
getGDNativeAPI().quatLengthSquared(self) getGDNativeAPI().quatLengthSquared(self)
proc normalized*(self: Quat): Quat {.inline.} = proc normalized*(self: Quat): Quat {.inline.} =
getGDNativeAPI().quatNormalized(self) getGDNativeAPI().quatNormalized(self).toQuat()
proc isNormalized*(self: Quat): bool {.inline.} = proc isNormalized*(self: Quat): bool {.inline.} =
getGDNativeAPI().quatIsNormalized(self) getGDNativeAPI().quatIsNormalized(self)
proc inverse*(self: Quat): Quat {.inline.} = proc inverse*(self: Quat): Quat {.inline.} =
getGDNativeAPI().quatInverse(self) getGDNativeAPI().quatInverse(self).toQuat()
proc dot*(a, b: Quat): float32 {.inline.} = proc dot*(a, b: Quat): float32 {.inline.} =
getGDNativeAPI().quatDot(a, b) getGDNativeAPI().quatDot(a, b)
proc xform*(self: Quat; v: Vector3): Vector3 {.inline.} = proc xform*(self: Quat; v: Vector3): Vector3 {.inline.} =
getGDNativeAPI().quatXform(self, v) getGDNativeAPI().quatXform(self, v).toVector3()
proc slerp*(self: Quat; b: Quat; t: float32): Quat {.inline.} = proc slerp*(self: Quat; b: Quat; t: float32): Quat {.inline.} =
getGDNativeAPI().quatSlerp(self, b, t) getGDNativeAPI().quatSlerp(self, b, t).toQuat()
proc slerpni*(self: Quat; b: Quat; t: float32): Quat {.inline.} = proc slerpni*(self: Quat; b: Quat; t: float32): Quat {.inline.} =
getGDNativeAPI().quatSlerpni(self, b, t) getGDNativeAPI().quatSlerpni(self, b, t).toQuat()
proc cubicSlerp*(self, b, preA, postB: Quat; proc cubicSlerp*(self, b, preA, postB: Quat;
t: float32): Quat {.inline.} = t: float32): Quat {.inline.} =
getGDNativeAPI().quatCubicSlerp(self, b, preA, postB, t) getGDNativeAPI().quatCubicSlerp(self, b, preA, postB, t).toQuat()
proc `*`*(a: Quat, b: float32): Quat {.inline.} = proc `*`*(a: Quat, b: float32): Quat {.inline.} =
getGDNativeAPI().quatOperatorMultiply(a, b) getGDNativeAPI().quatOperatorMultiply(a, b).toQuat()
proc `*=`*(a: var Quat, b: float32) {.inline.} = proc `*=`*(a: var Quat, b: float32) {.inline.} =
a = a * b a = a * b
proc `+`*(a, b: Quat): Quat {.inline.} = proc `+`*(a, b: Quat): Quat {.inline.} =
getGDNativeAPI().quatOperatorAdd(a, b) getGDNativeAPI().quatOperatorAdd(a, b).toQuat()
proc `+=`*(a: var Quat, b: Quat) {.inline.} = proc `+=`*(a: var Quat, b: Quat) {.inline.} =
a = a + b a = a + b
proc `-`*(a, b: Quat): Quat {.inline.} = proc `-`*(a, b: Quat): Quat {.inline.} =
getGDNativeAPI().quatOperatorSubtract(a, b) getGDNativeAPI().quatOperatorSubtract(a, b).toQuat()
proc `-=`* (a: var Quat, b: Quat) {.inline.} = proc `-=`* (a: var Quat, b: Quat) {.inline.} =
a = a - b a = a - b
proc `/`*(self: Quat; b: float32): Quat {.inline.} = proc `/`*(self: Quat; b: float32): Quat {.inline.} =
getGDNativeAPI().quatOperatorDivide(self, b) getGDNativeAPI().quatOperatorDivide(self, b).toQuat()
proc `/=`*(self: var Quat, b: float32) {.inline.} = proc `/=`*(self: var Quat, b: float32) {.inline.} =
self = self / b self = self / b
@ -81,4 +81,4 @@ proc `==`*(a, b: Quat): bool {.inline.} =
getGDNativeAPI().quatOperatorEqual(a, b) getGDNativeAPI().quatOperatorEqual(a, b)
proc `-`*(self: Quat): Quat {.inline.} = proc `-`*(self: Quat): Quat {.inline.} =
getGDNativeAPI().quatOperatorNeg(self) getGDNativeAPI().quatOperatorNeg(self).toQuat()

View file

@ -3,7 +3,7 @@
import hashes import hashes
import vector2 import vector2
import internal.godotinternaltypes, internal.godotstrings import internal/godotinternaltypes, internal/godotstrings
import godotcoretypes, gdnativeapi import godotcoretypes, gdnativeapi
{.push stackTrace: off.} {.push stackTrace: off.}

View file

@ -2,7 +2,7 @@
import hashes import hashes
import godotcoretypes, internal.godotinternaltypes, gdnativeapi import godotcoretypes, internal/godotinternaltypes, gdnativeapi
proc initRID*(): RID {.inline.} = proc initRID*(): RID {.inline.} =
getGDNativeAPI().ridNew(result) getGDNativeAPI().ridNew(result)

View file

@ -2,7 +2,7 @@
import hashes, vector2 import hashes, vector2
import internal.godotinternaltypes, internal.godotstrings import internal/godotinternaltypes, internal/godotstrings
import godotcoretypes, gdnativeapi import godotcoretypes, gdnativeapi
proc initTransform2D*(): Transform2D {.inline.} = proc initTransform2D*(): Transform2D {.inline.} =
@ -21,59 +21,59 @@ proc hash*(self: Transform2D): Hash {.inline, noinit.} =
!$(self.elements[0].hash() !& self.elements[1].hash() !& self.elements[2].hash()) !$(self.elements[0].hash() !& self.elements[1].hash() !& self.elements[2].hash())
proc inverse*(self: Transform2D): Transform2D {.inline.} = proc inverse*(self: Transform2D): Transform2D {.inline.} =
getGDNativeAPI().transform2DInverse(self) getGDNativeAPI().transform2DInverse(self).toTransform2D()
proc affineInverse*(self: Transform2D): Transform2D {.inline.} = proc affineInverse*(self: Transform2D): Transform2D {.inline.} =
getGDNativeAPI().transform2DAffineInverse(self) getGDNativeAPI().transform2DAffineInverse(self).toTransform2D()
proc rotation*(self: Transform2D): float32 {.inline.} = proc rotation*(self: Transform2D): float32 {.inline.} =
getGDNativeAPI().transform2DGetRotation(self) getGDNativeAPI().transform2DGetRotation(self)
proc origin*(self: Transform2D): Vector2 {.inline.} = proc origin*(self: Transform2D): Vector2 {.inline.} =
getGDNativeAPI().transform2DGetOrigin(self) getGDNativeAPI().transform2DGetOrigin(self).toVector2()
proc scale*(self: Transform2D): Vector2 {.inline.} = proc scale*(self: Transform2D): Vector2 {.inline.} =
getGDNativeAPI().transform2DGetScale(self) getGDNativeAPI().transform2DGetScale(self).toVector2()
proc orthonormalized*(self: Transform2D): Transform2D {.inline.} = proc orthonormalized*(self: Transform2D): Transform2D {.inline.} =
getGDNativeAPI().transform2DOrthonormalized(self) getGDNativeAPI().transform2DOrthonormalized(self).toTransform2D()
proc rotated*(self: Transform2D; phi: float32): Transform2D {.inline.} = proc rotated*(self: Transform2D; phi: float32): Transform2D {.inline.} =
getGDNativeAPI().transform2DRotated(self, phi) getGDNativeAPI().transform2DRotated(self, phi).toTransform2D()
proc scaled*(self: Transform2D; scale: Vector2): Transform2D {.inline.} = proc scaled*(self: Transform2D; scale: Vector2): Transform2D {.inline.} =
getGDNativeAPI().transform2DScaled(self, scale) getGDNativeAPI().transform2DScaled(self, scale).toTransform2D()
proc translated*(self: Transform2D; offset: Vector2): Transform2D {.inline.} = proc translated*(self: Transform2D; offset: Vector2): Transform2D {.inline.} =
getGDNativeAPI().transform2DTranslated(self, offset) getGDNativeAPI().transform2DTranslated(self, offset).toTransform2D()
proc xformVector2*(self: Transform2D; v: Vector2): Vector2 {.inline.} = proc xformVector2*(self: Transform2D; v: Vector2): Vector2 {.inline.} =
getGDNativeAPI().transform2DXformVector2(self, v) getGDNativeAPI().transform2DXformVector2(self, v).toVector2()
proc xformInvVector2*(self: Transform2D; v: Vector2): Vector2 {.inline.} = proc xformInvVector2*(self: Transform2D; v: Vector2): Vector2 {.inline.} =
getGDNativeAPI().transform2DXformInvVector2(self, v) getGDNativeAPI().transform2DXformInvVector2(self, v).toVector2()
proc basisXformVector2*(self: Transform2D; v: Vector2): Vector2 {.inline.} = proc basisXformVector2*(self: Transform2D; v: Vector2): Vector2 {.inline.} =
getGDNativeAPI().transform2DBasisXformVector2(self, v) getGDNativeAPI().transform2DBasisXformVector2(self, v).toVector2()
proc basisXformInvVector2*(self: Transform2D; v: Vector2): Vector2 {.inline.} = proc basisXformInvVector2*(self: Transform2D; v: Vector2): Vector2 {.inline.} =
getGDNativeAPI().transform2DBasisXformInvVector2(self, v) getGDNativeAPI().transform2DBasisXformInvVector2(self, v).toVector2()
proc xformRect2*(self: Transform2D; rect: Rect2): Rect2 {.inline.} = proc xformRect2*(self: Transform2D; rect: Rect2): Rect2 {.inline.} =
getGDNativeAPI().transform2DXformRect2(self, rect) getGDNativeAPI().transform2DXformRect2(self, rect).toRect2()
proc xformInvRect2*(self: Transform2D; rect: Rect2): Rect2 {.inline.} = proc xformInvRect2*(self: Transform2D; rect: Rect2): Rect2 {.inline.} =
getGDNativeAPI().transform2DXformInvRect2(self, rect) getGDNativeAPI().transform2DXformInvRect2(self, rect).toRect2()
proc interpolateWith*(self, m: Transform2D; proc interpolateWith*(self, m: Transform2D;
c: float32): Transform2D {.inline.} = c: float32): Transform2D {.inline.} =
getGDNativeAPI().transform2DInterpolateWith(self, m, c) getGDNativeAPI().transform2DInterpolateWith(self, m, c).toTransform2D()
proc `==`*(a, b: Transform2D): bool {.inline.} = proc `==`*(a, b: Transform2D): bool {.inline.} =
getGDNativeAPI().transform2DOperatorEqual(a, b) getGDNativeAPI().transform2DOperatorEqual(a, b)
proc `*`*(a, b: Transform2D): Transform2D {.inline.} = proc `*`*(a, b: Transform2D): Transform2D {.inline.} =
getGDNativeAPI().transform2DOperatorMultiply(a, b) getGDNativeAPI().transform2DOperatorMultiply(a, b).toTransform2D()
proc `*=`*(a: var Transform2D, b: Transform2D) {.inline.} = proc `*=`*(a: var Transform2D, b: Transform2D) {.inline.} =
a = a * b a = a * b

View file

@ -2,7 +2,7 @@
import hashes import hashes
import internal.godotinternaltypes, internal.godotstrings import internal/godotinternaltypes, internal/godotstrings
import godotcoretypes, gdnativeapi import godotcoretypes, gdnativeapi
import basis, vector3 import basis, vector3
@ -27,50 +27,50 @@ proc hash*(self: Transform): Hash {.inline.} =
!$(self.basis.hash() !& self.origin.hash()) !$(self.basis.hash() !& self.origin.hash())
proc inverse*(self: Transform): Transform {.inline.} = proc inverse*(self: Transform): Transform {.inline.} =
getGDNativeAPI().transformInverse(self) getGDNativeAPI().transformInverse(self).toTransform()
proc affineInverse*(self: Transform): Transform {.inline.} = proc affineInverse*(self: Transform): Transform {.inline.} =
getGDNativeAPI().transformAffineInverse(self) getGDNativeAPI().transformAffineInverse(self).toTransform()
proc orthonormalized*(self: Transform): Transform {.inline.} = proc orthonormalized*(self: Transform): Transform {.inline.} =
getGDNativeAPI().transformOrthonormalized(self) getGDNativeAPI().transformOrthonormalized(self).toTransform()
proc rotated*(self: Transform; axis: Vector3; proc rotated*(self: Transform; axis: Vector3;
phi: float32): Transform {.inline.} = phi: float32): Transform {.inline.} =
getGDNativeAPI().transformRotated(self, axis, phi) getGDNativeAPI().transformRotated(self, axis, phi).toTransform()
proc scaled*(self: Transform; scale: Vector3): Transform {.inline.} = proc scaled*(self: Transform; scale: Vector3): Transform {.inline.} =
getGDNativeAPI().transformScaled(self, scale) getGDNativeAPI().transformScaled(self, scale).toTransform()
proc translated*(self: Transform; offset: Vector3): Transform {.inline.} = proc translated*(self: Transform; offset: Vector3): Transform {.inline.} =
getGDNativeAPI().transformTranslated(self, offset) getGDNativeAPI().transformTranslated(self, offset).toTransform()
proc lookingAt*(self: Transform; target, up: Vector3): Transform {.inline.} = proc lookingAt*(self: Transform; target, up: Vector3): Transform {.inline.} =
getGDNativeAPI().transformLookingAt(self, target, up) getGDNativeAPI().transformLookingAt(self, target, up).toTransform()
proc xformPlane*(self: Transform; plane: Plane): Plane {.inline.} = proc xformPlane*(self: Transform; plane: Plane): Plane {.inline.} =
getGDNativeAPI().transformXformPlane(self, plane) getGDNativeAPI().transformXformPlane(self, plane).toPlane()
proc xformInvPlane*(self: Transform; plane: Plane): Plane {.inline.} = proc xformInvPlane*(self: Transform; plane: Plane): Plane {.inline.} =
getGDNativeAPI().transformXformInvPlane(self, plane) getGDNativeAPI().transformXformInvPlane(self, plane).toPlane()
proc xformVector3*(self: Transform; v: Vector3): Vector3 {.inline.} = proc xformVector3*(self: Transform; v: Vector3): Vector3 {.inline.} =
getGDNativeAPI().transformXformVector3(self, v) getGDNativeAPI().transformXformVector3(self, v).toVector3()
proc xformInvVector3*(self: Transform; v: Vector3): Vector3 {.inline.} = proc xformInvVector3*(self: Transform; v: Vector3): Vector3 {.inline.} =
getGDNativeAPI().transformXformInvVector3(self, v) getGDNativeAPI().transformXformInvVector3(self, v).toVector3()
proc xformAABB*(self: Transform; rect: AABB): AABB {.inline.} = proc xformAABB*(self: Transform; rect: AABB): AABB {.inline.} =
getGDNativeAPI().transformXformAABB(self, rect) getGDNativeAPI().transformXformAABB(self, rect).toAABB()
proc xformInvAABB*(self: Transform; rect: AABB): AABB {.inline.} = proc xformInvAABB*(self: Transform; rect: AABB): AABB {.inline.} =
getGDNativeAPI().transformXformInvAABB(self, rect) getGDNativeAPI().transformXformInvAABB(self, rect).toAABB()
proc `==`*(self: Transform; b: Transform): bool {.inline.} = proc `==`*(self: Transform; b: Transform): bool {.inline.} =
getGDNativeAPI().transformOperatorEqual(self, b) getGDNativeAPI().transformOperatorEqual(self, b)
proc `*`*(self, other: Transform): Transform {.inline.} = proc `*`*(self, other: Transform): Transform {.inline.} =
getGDNativeAPI().transformOperatorMultiply(self, other) getGDNativeAPI().transformOperatorMultiply(self, other).toTransform()
proc `*=`*(self: var Transform, other: Transform) {.inline.} = proc `*=`*(self: var Transform, other: Transform) {.inline.} =
self = self * other self = self * other

View file

@ -1,9 +1,9 @@
import tables, hashes import tables, hashes
import godotcoretypes import godotcoretypes
import internal.godotinternaltypes, internal.godotvariants, import internal/godotinternaltypes, internal/godotvariants,
internal.godotstrings, internal.godotdictionaries, internal/godotstrings, internal/godotdictionaries,
internal.godotarrays internal/godotarrays
type type
Variant* = ref object Variant* = ref object
@ -73,9 +73,10 @@ proc newVariant*(r: cdouble): Variant {.inline.} =
proc newVariant*(s: string): Variant {.inline.} = proc newVariant*(s: string): Variant {.inline.} =
new(result, variantFinalizer) new(result, variantFinalizer)
when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
if s.isNil: if s.isNil:
initGodotVariant(result.godotVariant) initGodotVariant(result.godotVariant)
else: return
var godotStr = s.toGodotString() var godotStr = s.toGodotString()
initGodotVariant(result.godotVariant, godotStr) initGodotVariant(result.godotVariant, godotStr)
godotStr.deinit() godotStr.deinit()

View file

@ -2,9 +2,11 @@
import math, godotbase, hashes import math, godotbase, hashes
import internal.godotinternaltypes, internal.godotstrings import internal/godotinternaltypes, internal/godotstrings
import godotcoretypes, gdnativeapi import godotcoretypes, gdnativeapi
const EPSILON = 0.00001'f32
{.push stackTrace: off.} {.push stackTrace: off.}
proc vec2*(): Vector2 {.inline, noinit.} = proc vec2*(): Vector2 {.inline, noinit.} =
@ -199,4 +201,14 @@ proc clamped*(self: Vector2; length: float32): Vector2 {.noinit.} =
result /= len result /= len
result *= length result *= length
proc moveToward*(vFrom, to: Vector2, delta: float32): Vector2 =
let
vd = to - vFrom
vLen = vd.length
if vLen <= delta or vLen < EPSILON:
result = to
else:
result = vFrom + (vd / vLen) * delta
{.pop.} # stackTrace: off {.pop.} # stackTrace: off

View file

@ -3,6 +3,8 @@
import math, hashes import math, hashes
import godotbase, godotcoretypes import godotbase, godotcoretypes
const EPSILON = 0.00001'f32
{.push stackTrace: off.} {.push stackTrace: off.}
proc vec3*(): Vector3 {.inline.} = proc vec3*(): Vector3 {.inline.} =
@ -239,4 +241,14 @@ proc cubicInterpolate*(self, b, preA, postB: Vector3;
(2.0 * p0 - 5.0 * p1 + 4 * p2 - p3) * t2 + (2.0 * p0 - 5.0 * p1 + 4 * p2 - p3) * t2 +
(-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3) (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3)
proc moveToward*(vFrom, to: Vector3, delta: float32): Vector3 =
let
vd = to - vFrom
vLen = vd.length
if vLen <= delta or vLen < EPSILON:
result = to
else:
result = vFrom + (vd / vLen) * delta
{.pop.} # stackTrace: off {.pop.} # stackTrace: off

File diff suppressed because it is too large Load diff

View file

@ -1,14 +1,14 @@
# Copyright 2018 Xored Software, Inc. # Copyright 2018 Xored Software, Inc.
import core.godotbase, godotinternal import core/godotbase, godotinternal
import core.godotcoretypes import core/godotcoretypes
import core.vector2, core.rect2, core.vector3, core.transform2d, core.planes, import core/vector2, core/rect2, core/vector3, core/transform2d, core/planes,
core.quats core/quats
import core.aabb, core.basis, core.transforms, core.colors, core.nodepaths, import core/aabb, core/basis, core/transforms, core/colors, core/nodepaths,
core.rids core/rids
import core.dictionaries, core.arrays, core.poolarrays, core.variants import core/dictionaries, core/arrays, core/poolarrays, core/variants
import nim.godotmacros, nim.godotnim import nim/godotmacros, nim/godotnim
export godotbase, godotcoretypes, vector2, rect2, vector3, transform2d, planes, export godotbase, godotcoretypes, vector2, rect2, vector3, transform2d, planes,
quats, aabb, basis, transforms, colors, nodepaths, rids, dictionaries, quats, aabb, basis, transforms, colors, nodepaths, rids, dictionaries,

View file

@ -1,12 +1,31 @@
# Copyright 2018 Xored Software, Inc. # Copyright 2018 Xored Software, Inc.
import streams, json, os, strutils, times, sets, tables import streams, json, os, strutils, times, sets, tables, options
import sequtils, algorithm import sequtils, algorithm
import compiler.ast, compiler.renderer, compiler.idents, compiler.astalgo import compiler/ast, compiler/renderer, compiler/idents, compiler/astalgo
include "internal/backwardcompat.inc.nim"
when (NimMajor, NimMinor, NimPatch) >= (0, 19, 0):
import compiler/lineinfos
when (NimMajor, NimMinor, NimPatch) >= (0, 19, 0):
var gic = newIdentCache()
proc getIdent(ident: string): PIdent =
getIdent(gic, ident)
proc ident(ident: string): PNode = proc ident(ident: string): PNode =
result = newNode(nkIdent) result = PNode(kind: nkIdent, ident: getIdent(ident))
result.ident = getIdent(ident)
proc newPNode(kind: TNodeKind): PNode =
when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
result = newNode(kind)
else:
result = PNode(kind: kind)
result.info.fileIndex = InvalidFileIdx
result.info.col = int16(-1)
result.info.line = uint16(0)
proc addChain(node: PNode, others: varargs[PNode]): PNode {.discardable.} = proc addChain(node: PNode, others: varargs[PNode]): PNode {.discardable.} =
for other in others: for other in others:
@ -15,37 +34,37 @@ proc addChain(node: PNode, others: varargs[PNode]): PNode {.discardable.} =
proc newIdentDefs(name, typ: PNode, proc newIdentDefs(name, typ: PNode,
defaultVal: PNode = nil): PNode = defaultVal: PNode = nil): PNode =
result = newNode(nkIdentDefs) result = newPNode(nkIdentDefs)
result.add(name) result.add(name)
result.add(typ) result.add(typ)
if defaultVal.isNil: if defaultVal.isNil:
result.add(newNode(nkEmpty)) result.add(newPNode(nkEmpty))
else: else:
result.add(defaultVal) result.add(defaultVal)
proc newProc(name: PNode, params: openArray[PNode], body = newNode(nkEmpty), proc newProc(name: PNode, params: openArray[PNode], body = newPNode(nkEmpty),
procType = nkProcDef): PNode = procType = nkProcDef): PNode =
result = newNode(procType) result = newPNode(procType)
result.add(name) result.add(name)
result.add(newNode(nkEmpty)) result.add(newPNode(nkEmpty))
result.add(newNode(nkEmpty)) result.add(newPNode(nkEmpty))
let formalParams = newNode(nkFormalParams) let formalParams = newPNode(nkFormalParams)
for param in params: for param in params:
formalParams.add(param) formalParams.add(param)
result.add(formalParams) result.add(formalParams)
result.add(newNode(nkEmpty)) result.add(newPNode(nkEmpty))
result.add(newNode(nkEmpty)) result.add(newPNode(nkEmpty))
result.add(body) result.add(body)
proc newIfStmt(condition, body: PNode): PNode = proc newIfStmt(condition, body: PNode): PNode =
result = newNode(nkIfStmt) result = newPNode(nkIfStmt)
let branch = newNode(nkElifBranch) let branch = newPNode(nkElifBranch)
result.add(branch) result.add(branch)
branch.add(condition) branch.add(condition)
branch.add(body) branch.add(body)
proc newCall(theProc: PNode, args: varargs[PNode]): PNode = proc newCall(theProc: PNode, args: varargs[PNode]): PNode =
result = newNode(nkCall) result = newPNode(nkCall)
result.add(theProc) result.add(theProc)
for arg in args: for arg in args:
result.add(arg) result.add(arg)
@ -54,66 +73,66 @@ proc newCall(theProc: string, args: varargs[PNode]): PNode =
newCall(ident(theProc), args) newCall(ident(theProc), args)
proc newStrLit(s: string): PNode = proc newStrLit(s: string): PNode =
result = newNode(nkStrLit) result = newPNode(nkStrLit)
result.strVal = s result.strVal = s
proc newRStrLit(s: string): PNode = proc newRStrLit(s: string): PNode =
result = newNode(nkRStrLit) result = newPNode(nkRStrLit)
result.strVal = s result.strVal = s
proc newCStringLit(s: string): PNode = proc newCStringLit(s: string): PNode =
newNode(nkCallStrLit).addChain(ident("cstring"), newRStrLit(s)) newPNode(nkCallStrLit).addChain(ident("cstring"), newRStrLit(s))
proc newIntLit(val: BiggestInt): PNode = proc newIntLit(val: BiggestInt): PNode =
result = newNode(nkIntLit) result = newPNode(nkIntLit)
result.intVal = val result.intVal = val
proc newInt64Lit(val: BiggestInt): PNode = proc newInt64Lit(val: BiggestInt): PNode =
result = newNode(nkInt64Lit) result = newPNode(nkInt64Lit)
result.intVal = val result.intVal = val
proc newFloatLit(val: BiggestFloat): PNode = proc newFloatLit(val: BiggestFloat): PNode =
result = newNode(nkFloatLit) result = newPNode(nkFloatLit)
result.floatVal = val result.floatVal = val
proc newFloat64Lit(val: BiggestFloat): PNode = proc newFloat64Lit(val: BiggestFloat): PNode =
result = newNode(nkFloat64Lit) result = newPNode(nkFloat64Lit)
result.floatVal = val result.floatVal = val
proc newNilLit(): PNode = proc newNilLit(): PNode =
result = newNode(nkNilLit) result = newPNode(nkNilLit)
proc newDotExpr(left, right: PNode): PNode = proc newDotExpr(left, right: PNode): PNode =
result = newNode(nkDotExpr) result = newPNode(nkDotExpr)
result.add(left) result.add(left)
result.add(right) result.add(right)
proc newCommand(left, right: PNode): PNode = proc newCommand(left, right: PNode): PNode =
result = newNode(nkCommand) result = newPNode(nkCommand)
result.add(left) result.add(left)
result.add(right) result.add(right)
proc infix(left, op, right: PNode): PNode = proc infix(left, op, right: PNode): PNode =
result = newNode(nkInfix) result = newPNode(nkInfix)
result.add(op) result.add(op)
result.add(left) result.add(left)
result.add(right) result.add(right)
proc postfix(left: PNode, op: string): PNode = proc postfix(left: PNode, op: string): PNode =
result = newNode(nkPostfix) result = newPNode(nkPostfix)
result.add(ident(op)) result.add(ident(op))
result.add(left) result.add(left)
proc prefix(op: string, right: PNode): PNode = proc prefix(op: string, right: PNode): PNode =
result = newNode(nkPrefix) result = newPNode(nkPrefix)
result.add(ident(op)) result.add(ident(op))
result.add(right) result.add(right)
proc newBracketExpr(first, bracket: PNode): PNode = proc newBracketExpr(first, bracket: PNode): PNode =
newNode(nkBracketExpr).addChain(first, bracket) newPNode(nkBracketExpr).addChain(first, bracket)
proc newEmptyNode(): PNode = proc newEmptyNode(): PNode =
newNode(nkEmpty) newPNode(nkEmpty)
type GodotType = ref object type GodotType = ref object
name: string name: string
@ -139,19 +158,19 @@ proc findCommonRoot(typeRegistry: Table[string, GodotType],
var idx = 0 var idx = 0
while true: while true:
var curType: string var curType = none(string)
var allEqual = true var allEqual = true
for chain in chains: for chain in chains:
if idx >= chain.len: if idx >= chain.len:
allEqual = false allEqual = false
break break
if curType.isNil: if curType.isNone:
curType = chain[idx] curType = some(chain[idx])
elif curType != chain[idx]: elif curType.get != chain[idx]:
allEqual = false allEqual = false
break break
if allEqual: if allEqual:
result = curType result = curType.get
else: else:
break break
inc idx inc idx
@ -206,42 +225,42 @@ proc toNimStyle(name: string): string =
proc newRefTypeNode(typeSection: PNode, typ, base, doc: string, proc newRefTypeNode(typeSection: PNode, typ, base, doc: string,
isExported = true) = isExported = true) =
let typeDef = newNode(nkTypeDef) let typeDef = newPNode(nkTypeDef)
typeSection.add(typeDef) typeSection.add(typeDef)
if isExported: if isExported:
typeDef.add(postfix(ident(typ), "*")) typeDef.add(postfix(ident(typ), "*"))
else: else:
typeDef.add(ident(typ)) typeDef.add(ident(typ))
typeDef.add(newNode(nkEmpty)) # generic typeDef.add(newPNode(nkEmpty)) # generic
let objTy = newNode(nkObjectTy) let objTy = newPNode(nkObjectTy)
let refTy = newNode(nkRefTy) let refTy = newPNode(nkRefTy)
refTy.add(objTy) refTy.add(objTy)
typeDef.add(refTy) typeDef.add(refTy)
objTy.add(newNode(nkEmpty)) objTy.add(newPNode(nkEmpty))
let inherit = newNode(nkOfInherit) let inherit = newPNode(nkOfInherit)
inherit.add(ident(base)) inherit.add(ident(base))
objTy.add(inherit) objTy.add(inherit)
if not doc.isNil: if doc.len > 0:
let recList = newNode(nkRecList) let recList = newPNode(nkRecList)
let docNode = newNode(nkCommentStmt) let docNode = newPNode(nkCommentStmt)
docNode.comment = doc docNode.comment = doc
recList.add(docNode) recList.add(docNode)
objTy.add(recList) objTy.add(recList)
else: else:
objTy.add(newNode(nkEmpty)) objTy.add(newPNode(nkEmpty))
proc makeConstSection(constObj: JsonNode): PNode = proc makeConstSection(constObj: JsonNode): PNode =
if constObj.len == 0: if constObj.len == 0:
return newNode(nkEmpty) return newPNode(nkEmpty)
result = newNode(nkConstSection) result = newPNode(nkConstSection)
for field, val in constObj: for field, val in constObj:
let def = newNode(nkConstDef) let def = newPNode(nkConstDef)
def.add(postfix(ident(field), "*")) def.add(postfix(ident(field), "*"))
def.add(newNode(nkEmpty)) # infer type def.add(newPNode(nkEmpty)) # infer type
var valNode: PNode var valNode: PNode
if val.kind == JInt: if val.kind == JInt:
valNode = newInt64Lit(val.num) valNode = newInt64Lit(val.num)
@ -251,7 +270,7 @@ proc makeConstSection(constObj: JsonNode): PNode =
elif val.kind == JBool: elif val.kind == JBool:
valNode = ident($val.bval) valNode = ident($val.bval)
elif val.kind == JString: elif val.kind == JString:
valNode = newNode(nkStrLit) valNode = newPNode(nkStrLit)
valNode.strVal = val.str valNode.strVal = val.str
else: else:
raise newException(ValueError, "Unexpected constant kind: " & $val.kind) raise newException(ValueError, "Unexpected constant kind: " & $val.kind)
@ -275,12 +294,12 @@ type
godotName: string godotName: string
typ: GodotType typ: GodotType
args: seq[MethodArg] args: seq[MethodArg]
returnType: string returnType: Option[string]
isVirtual: bool isVirtual: bool
isBase: bool isBase: bool
isDiscardable: bool isDiscardable: bool
const standardTypes = toSet( const standardTypes = toHashSet(
["bool", "cint", "int", "uint8", "int8", "uint16", "int16", "uint32", "int32", ["bool", "cint", "int", "uint8", "int8", "uint16", "int16", "uint32", "int32",
"uint64", "Error", "uint64", "Error",
"int64", "float32", "cfloat", "float64", "GodotString", "Vector2", "Rect2", "int64", "float32", "cfloat", "float64", "GodotString", "Vector2", "Rect2",
@ -289,26 +308,33 @@ const standardTypes = toSet(
"PoolByteArray", "PoolIntArray", "PoolRealArray", "PoolStringArray", "PoolByteArray", "PoolIntArray", "PoolRealArray", "PoolStringArray",
"PoolVector2Array", "PoolVector3Array", "PoolColorArray"]) "PoolVector2Array", "PoolVector3Array", "PoolColorArray"])
const smallIntTypes = toSet(["uint8", "int8", "uint16", "int16", "uint32", const variantPrimitives = [
"bool", "cint", "int", "uint8", "int8", "uint16", "int16", "uint32", "int32",
"uint64", "Error",
"int64", "float32", "cfloat", "float64", "GodotString", "Vector2", "Rect2",
"Vector3", "Transform2D", "Plane", "Quat", "AABB", "Basis", "Transform",
"Color", "RID"]
const smallIntTypes = toHashSet(["uint8", "int8", "uint16", "int16", "uint32",
"int32", "cint", "int", "Error"]) "int32", "cint", "int", "Error"])
const int64Types = toSet(["uint64", "int64"]) const int64Types = toHashSet(["uint64", "int64"])
const intTypes = union(smallIntTypes, int64Types) const intTypes = union(smallIntTypes, int64Types)
const float64Types = toSet(["float64", "cdouble"]) const float64Types = toHashSet(["float64", "cdouble"])
const float32Types = toSet(["float32", "cfloat"]) const float32Types = toHashSet(["float32", "cfloat"])
const floatTypes = union(float64Types, float32Types) const floatTypes = union(float64Types, float32Types)
const arrayTypes = toSet(["Array", "PoolByteArray", const arrayTypes = toHashSet(["Array", "PoolByteArray",
"PoolIntArray", "PoolRealArray", "PoolStringArray", "PoolVector2Array", "PoolIntArray", "PoolRealArray", "PoolStringArray", "PoolVector2Array",
"PoolVector3Array", "PoolColorArray"]) "PoolVector3Array", "PoolColorArray"])
const wrapperTypes = union(arrayTypes, const wrapperTypes = union(arrayTypes,
toSet(["NodePath", "Dictionary", "Variant"])) toHashSet(["NodePath", "Dictionary", "Variant"]))
proc getInternalPtr(varName: PNode, typ: string): PNode = proc getInternalPtr(varName: PNode, typ: string): PNode =
assert(typ in wrapperTypes) assert(typ in wrapperTypes or typ == "Object")
result = newDotExpr(varName, ident("godot" & typ)) result = newDotExpr(varName, ident("godot" & typ))
proc newNilCheck(ident, toAssign: PNode): PNode = proc newNilCheck(ident, toAssign: PNode): PNode =
newIfStmt(newCall("isNil", ident), newIfStmt(newCall("isNil", ident),
newNode(nkAsgn).addChain(ident).addChain( newPNode(nkAsgn).addChain(ident).addChain(
toAssign toAssign
) )
) )
@ -381,6 +407,8 @@ proc makeDefaultValue(arg: MethodArg): PNode =
result = newCall("newVariant") result = newCall("newVariant")
else: else:
failed = true failed = true
elif arg.typ == "Dictionary":
result = newCall("newDictionary")
else: else:
failed = true failed = true
@ -397,12 +425,12 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
meth: MethodInfo, withImplementation: bool) = meth: MethodInfo, withImplementation: bool) =
var body: PNode var body: PNode
if not withImplementation: if not withImplementation:
body = newNode(nkEmpty) body = newPNode(nkEmpty)
elif meth.godotName == "_init" and meth.typ.godotName == "Object": elif meth.godotName == "_init" and meth.typ.godotName == "Object":
# It's not real (calling it crashes) and will be removed later, # It's not real (calling it crashes) and will be removed later,
# but we use init() convention in Nim, so it needs to work. # but we use init() convention in Nim, so it needs to work.
body = newNode(nkStmtList).addChain( body = newPNode(nkStmtList).addChain(
newNode(nkDiscardStmt).addChain(newNode(nkEmpty))) newPNode(nkDiscardStmt).addChain(newPNode(nkEmpty)))
else: else:
let methGodotName = if meth.godotName.startsWith('_'): let methGodotName = if meth.godotName.startsWith('_'):
"underscore" & meth.godotName[1..^1] "underscore" & meth.godotName[1..^1]
@ -413,12 +441,12 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
if methodBindName[0].isUpperAscii(): if methodBindName[0].isUpperAscii():
methodBindName[0] = methodBindName[0].toLowerAscii() methodBindName[0] = methodBindName[0].toLowerAscii()
if methodBindName notin methodBindRegistry: if methodBindName notin methodBindRegistry:
let methodBindDecl = newNode(nkVarSection).addChain( let methodBindDecl = newPNode(nkVarSection).addChain(
newIdentDefs( newIdentDefs(
newNode(nkPragmaExpr).addChain( newPNode(nkPragmaExpr).addChain(
ident(methodBindName)).addChain( ident(methodBindName)).addChain(
newNode(nkPragma).addChain(ident("threadvar"))), newPNode(nkPragma).addChain(ident("threadvar"))),
newNode(nkPtrTy).addChain(ident("GodotMethodBind")) newPNode(nkPtrTy).addChain(ident("GodotMethodBind"))
)) ))
tree.add(methodBindDecl) tree.add(methodBindDecl)
methodBindRegistry.incl(methodBindName) methodBindRegistry.incl(methodBindName)
@ -427,8 +455,8 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
newCall("getMethod", newCStringLit(meth.typ.godotName), newCall("getMethod", newCStringLit(meth.typ.godotName),
newCStringLit(meth.godotName)) newCStringLit(meth.godotName))
) )
let vars = newNode(nkVarSection) let vars = newPNode(nkVarSection)
var varargsName: string var varargsName = none(string)
var isVarargs: bool var isVarargs: bool
var staticArgsLen: int var staticArgsLen: int
var argLenNode = newIntLit(0) var argLenNode = newIntLit(0)
@ -436,54 +464,90 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
if meth.args.len > 0: if meth.args.len > 0:
for idx, arg in meth.args: for idx, arg in meth.args:
if arg.kind == ArgKind.VarArgs: if arg.kind == ArgKind.VarArgs:
varargsName = arg.name varargsName = some(arg.name)
isVarargs = true isVarargs = true
vars.add(newIdentDefs(ident("callError"), ident("VariantCallError"))) vars.add(newIdentDefs(ident("callError"), ident("VariantCallError")))
elif arg.kind == ArgKind.Bound: elif arg.kind == ArgKind.Bound:
let argName = boundArgName(idx) let argName = boundArgName(idx)
vars.add(newIdentDefs( vars.add(newIdentDefs(
ident(argName), newNode(nkEmpty), arg.makeDefaultValue())) ident(argName), newPNode(nkEmpty), arg.makeDefaultValue()))
let argsAlloc = newNode(nkCast).addChain( let argsAlloc = newPNode(nkCast).addChain(
newNode(nkPtrTy).addChain( newPNode(nkPtrTy).addChain(
newNode(nkBracketExpr).addChain( newPNode(nkBracketExpr).addChain(
ident("array"), ident("MAX_ARG_COUNT"), ident("array"), ident("MAX_ARG_COUNT"),
if isVarargs: newNode(nkPtrTy).addChain(ident("GodotVariant")) if isVarargs: newPNode(nkPtrTy).addChain(ident("GodotVariant"))
else: ident("pointer")))) else: ident("pointer"))))
staticArgsLen = if varargsName.isNil: meth.args.len staticArgsLen = if varargsName.isNone: meth.args.len
else: meth.args.len - 1 else: meth.args.len - 1
if not varargsName.isNil: if varargsName.isSome:
argLenNode = newCall("cint", argLenNode = newCall("cint",
infix(newIntLit(staticArgsLen), infix(newIntLit(staticArgsLen),
ident("+"), ident("+"),
newDotExpr(ident(varargsName), ident("len")))) newDotExpr(ident(varargsName.get), ident("len"))))
argsAlloc.add(newCall("godotAlloc", newCall("cint", infix( argsAlloc.add(newCall("godotAlloc", newCall("cint", infix(
newCall("sizeof", ident("Variant")), ident("*"), newCall("sizeof", newPNode(nkPtrTy).addChain(ident("GodotVariant"))), ident("*"),
newNode(nkPar).addChain(argLenNode)))) newPNode(nkPar).addChain(argLenNode))))
) )
else: else:
argLenNode = newCall("cint", newIntLit(staticArgsLen)) argLenNode = newCall("cint", newIntLit(staticArgsLen))
vars.add(newIdentDefs( vars.add(newIdentDefs(
ident("argsStatic"), ident("argsStatic"),
newNode(nkBracketExpr).addChain( newPNode(nkBracketExpr).addChain(
ident("array"), newIntLit(staticArgsLen), ident("pointer")), ident("array"), newIntLit(staticArgsLen), ident("pointer")),
newNode(nkEmpty))) newPNode(nkEmpty)))
argsAlloc.add(newCommand(ident("addr"), ident("argsStatic"))) argsAlloc.add(newCommand(ident("addr"), ident("argsStatic")))
vars.add(newIdentDefs(argsName, newNode(nkEmpty), argsAlloc)) vars.add(newIdentDefs(argsName, newPNode(nkEmpty), argsAlloc))
let argConversions = newNode(nkStmtList) let argConversions = newPNode(nkStmtList)
let destructors = newPNode(nkStmtList)
for idx, arg in meth.args: for idx, arg in meth.args:
var argName = if arg.kind == ArgKind.Bound: ident(boundArgName(idx)) var argName = if arg.kind == ArgKind.Bound: ident(boundArgName(idx))
else: ident(arg.name) else: ident(arg.name)
if arg.kind == ArgKind.VarArgs: if arg.kind == ArgKind.VarArgs:
argName = newNode(nkBracketExpr).addChain( argName = newPNode(nkBracketExpr).addChain(
ident(varargsName), ident(varargsName.get),
infix(ident("idx"), ident("-"), newIntLit(staticArgsLen))) infix(ident("idx"), ident("-"), newIntLit(staticArgsLen)))
let argIdx = if arg.kind == ArgKind.VarArgs: ident("idx") else: newIntLit(idx) let argIdx = if arg.kind == ArgKind.VarArgs: ident("idx") else: newIntLit(idx)
let isStandardType = arg.typ in standardTypes let isStandardType = arg.typ in standardTypes
let isWrappedType = arg.typ in wrapperTypes let isWrappedType = arg.typ in wrapperTypes
let convArg = if not varargsName.isNil: let convArg =
getInternalPtr(newCall("toVariant", argName), "Variant") if varargsName.isSome:
let isAlreadyVariant = arg.typ == "Variant"
let variantIdent = if isAlreadyVariant: getInternalPtr(argName, "Variant")
else: ident("variant" & $idx)
if not isAlreadyVariant:
argConversions.add(newPNode(nkVarSection).addChain(
newIdentDefs(variantIdent, ident("GodotVariant"), newEmptyNode())
))
destructors.add(
newCall("deinit", variantIdent)
)
if arg.typ in variantPrimitives:
argConversions.add(
newCall("initGodotVariant", variantIdent, argName)
)
elif arg.typ in wrapperTypes or arg.typ == "Object":
argConversions.add(
newCall("initGodotVariant", variantIdent, getInternalPtr(argName, arg.typ))
)
elif arg.typ == "string":
let stringIdent = ident("variantString" & $idx)
argConversions.addChain(
newPNode(nkVarSection).addChain(
newIdentDefs(stringIdent, ident("GodotString"), newCall("toGodotString", argName))
)
).addChain(
newCall("initGodotVariant", variantIdent, stringIdent)
)
destructors.add(newCall("deinit", stringIdent))
else:
raise newException(ValueError,
"Non-standard type $# for varargs params of method $# of type $#" %
[arg.typ, meth.godotName, meth.typ.godotName])
if isAlreadyVariant: variantIdent
else: newCall("addr", variantIdent)
elif isWrappedType: getInternalPtr(argName, arg.typ) elif isWrappedType: getInternalPtr(argName, arg.typ)
elif isStandardType: newCall("unsafeAddr", argName) elif isStandardType: newCall("unsafeAddr", argName)
elif arg.typ == "string": newCall("unsafeAddr", elif arg.typ == "string": newCall("unsafeAddr",
@ -493,21 +557,21 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
raise newException(ValueError, raise newException(ValueError,
"Non-standard type $# for varargs params of method $# of type $#" % "Non-standard type $# for varargs params of method $# of type $#" %
[arg.typ, meth.godotName, meth.typ.godotName]) [arg.typ, meth.godotName, meth.typ.godotName])
if not isStandardType and varargsName.isNil: if not isStandardType and varargsName.isNone:
if arg.typ == "string": if arg.typ == "string":
argConversions.add(newNode(nkVarSection).addChain( argConversions.add(newPNode(nkVarSection).addChain(
newIdentDefs(ident("argToPassToGodot" & $idx), newEmptyNode(), newIdentDefs(ident("argToPassToGodot" & $idx), newEmptyNode(),
newCall("toGodotString", argName)))) newCall("toGodotString", argName))))
else: else:
let objVal = newIfStmt( let objVal = newIfStmt(
prefix("not", newDotExpr(argName, ident"isNil")), prefix("not", newDotExpr(argName, ident"isNil")),
newDotExpr(argName, ident("godotObject")) newDotExpr(argName, ident("godotObject"))
).addChain(newNode(nkElse).addChain(newNilLit())) ).addChain(newPNode(nkElse).addChain(newNilLit()))
argConversions.add(newNode(nkLetSection).addChain( argConversions.add(newPNode(nkLetSection).addChain(
newIdentDefs(ident("argToPassToGodot" & $idx), newEmptyNode(), objVal))) newIdentDefs(ident("argToPassToGodot" & $idx), newEmptyNode(), objVal)))
let argAsgn = newNode(nkAsgn).addChain( let argAsgn = newPNode(nkAsgn).addChain(
newNode(nkBracketExpr).addChain( newPNode(nkBracketExpr).addChain(
newNode(nkBracketExpr).addChain(argsName), argIdx), newPNode(nkBracketExpr).addChain(argsName), argIdx),
convArg convArg
) )
if arg.kind != ArgKind.VarArgs: if arg.kind != ArgKind.VarArgs:
@ -515,14 +579,14 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
argAsgn argAsgn
) )
else: else:
argConversions.add(newNode(nkVarSection).addChain( argConversions.add(newPNode(nkVarSection).addChain(
newIdentDefs(ident("idx"), newNode(nkEmpty), newIdentDefs(ident("idx"), newPNode(nkEmpty),
newIntLit(staticArgsLen)))) newIntLit(staticArgsLen))))
let argLoop = newNode(nkWhileStmt) let argLoop = newPNode(nkWhileStmt)
argConversions.add(argLoop) argConversions.add(argLoop)
argLoop.add(infix(ident("idx"), ident("<"), argLenNode) argLoop.add(infix(ident("idx"), ident("<"), argLenNode)
) )
argLoop.add(newNode(nkStmtList).addChain( argLoop.add(newPNode(nkStmtList).addChain(
argAsgn, argAsgn,
newCommand(ident("inc"), ident("idx")))) newCommand(ident("inc"), ident("idx"))))
@ -531,26 +595,26 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
newDotExpr(ident(methodBindName), newDotExpr(ident(methodBindName),
ident(if isVarargs: "call" else: "ptrCall")), ident(if isVarargs: "call" else: "ptrCall")),
newDotExpr(ident("self"), ident("godotObject")), newDotExpr(ident("self"), ident("godotObject")),
if meth.args.len > 0: argsName else: newNode(nkNilLit), if meth.args.len > 0: argsName else: newPNode(nkNilLit),
argLenNode, argLenNode,
if not isVarargs: ident(retName) else: ident("callError") if not isVarargs: ident(retName) else: ident("callError")
) )
if not isVarargs: if not isVarargs:
theCall.sons.delete(3) theCall.sons.delete(3)
let freeCall = newCall("godotFree", argsName) let freeCall = newCall("godotFree", argsName)
body = newNode(nkStmtList) body = newPNode(nkStmtList)
if meth.typ.isSingleton: if meth.typ.isSingleton:
let varName = singletonName(meth.typ.name) let varName = singletonName(meth.typ.name)
body.add(newNilCheck(varName, newCall( body.add(newNilCheck(varName, newCall(
newBracketExpr(ident("getSingleton"), ident(meth.typ.name))))) newBracketExpr(ident("getSingleton"), ident(meth.typ.name)))))
body.add(newNode(nkLetSection).addChain(newIdentDefs( body.add(newPNode(nkLetSection).addChain(newIdentDefs(
ident("self"), newNode(nkEmpty), varName ident("self"), newPNode(nkEmpty), varName
))) )))
body.add(nilCheck) body.add(nilCheck)
body.add(vars) body.add(vars)
body.add(argConversions) body.add(argConversions)
if not isVarargs: if not isVarargs:
let retPtrDecl = newNode(nkVarSection).addChain( let retPtrDecl = newPNode(nkVarSection).addChain(
newIdentDefs(ident(retName), ident("pointer"), newEmptyNode()) newIdentDefs(ident(retName), ident("pointer"), newEmptyNode())
) )
body.add(retPtrDecl) body.add(retPtrDecl)
@ -560,105 +624,109 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
var isStringRet: bool var isStringRet: bool
var isWrapperRet: bool var isWrapperRet: bool
let retValIdent = if not isVarargs: ident("ptrCallVal") else: ident(retName) let retValIdent = if not isVarargs: ident("ptrCallVal") else: ident(retName)
if not meth.returnType.isNil and not isVarargs: if meth.returnType.isSome and not isVarargs:
let returnType = meth.returnType.get
var addrToAssign = newCall("addr", retValIdent) var addrToAssign = newCall("addr", retValIdent)
if meth.returnType in smallIntTypes: if returnType in smallIntTypes:
isConversionRet = true isConversionRet = true
body.add(newNode(nkVarSection).addChain(newIdentDefs( body.add(newPNode(nkVarSection).addChain(newIdentDefs(
retValIdent, ident("int64"), retValIdent, ident("int64"),
))) )))
elif meth.returnType in float32Types: elif returnType in float32Types:
isConversionRet = true isConversionRet = true
body.add(newNode(nkVarSection).addChain(newIdentDefs( body.add(newPNode(nkVarSection).addChain(newIdentDefs(
retValIdent, ident("float64"), retValIdent, ident("float64"),
))) )))
elif meth.returnType in wrapperTypes: elif returnType in wrapperTypes:
isWrapperRet = true isWrapperRet = true
body.add(newNode(nkVarSection).addChain(newIdentDefs( body.add(newPNode(nkVarSection).addChain(newIdentDefs(
retValIdent, ident("Godot" & meth.returnType), retValIdent, ident("Godot" & returnType),
))) )))
elif meth.returnType in standardTypes: if returnType != "NodePath":
body.add(newCall("initGodot" & returnType, retValIdent))
elif returnType in standardTypes:
addrToAssign = newCall("addr", ident("result")) addrToAssign = newCall("addr", ident("result"))
elif meth.returnType == "string": elif returnType == "string":
isStringRet = true isStringRet = true
body.add(newNode(nkVarSection).addChain(newIdentDefs( body.add(newPNode(nkVarSection).addChain(newIdentDefs(
retValIdent, ident("GodotString"), retValIdent, ident("GodotString"),
))) )))
elif meth.returnType != "void": elif returnType != "void":
isObjRet = true isObjRet = true
body.add(newNode(nkVarSection).addChain(newIdentDefs( body.add(newPNode(nkVarSection).addChain(newIdentDefs(
retValIdent, newNode(nkPtrTy).addChain(ident("GodotObject")), retValIdent, newPNode(nkPtrTy).addChain(ident("GodotObject")),
))) )))
body.add(newNode(nkAsgn).addChain(ident(retName), addrToAssign)) body.add(newPNode(nkAsgn).addChain(ident(retName), addrToAssign))
if not isVarargs: if not isVarargs:
body.add(theCall) body.add(theCall)
else: else:
if not meth.returnType.isNil: if meth.returnType.isSome:
isVariantRet = true isVariantRet = true
let callStmt = newNode(nkLetSection).addChain( let callStmt = newPNode(nkLetSection).addChain(
newIdentDefs( newIdentDefs(
newNode(nkPragmaExpr).addChain( newPNode(nkPragmaExpr).addChain(
ident(retName), newNode(nkPragma).addChain(ident("used"))), ident(retName), newPNode(nkPragma).addChain(ident("used"))),
newNode(nkEmpty), theCall)) newPNode(nkEmpty), theCall))
body.add(callStmt) body.add(callStmt)
if varargsName.isNil: if varargsName.isNone:
for idx, arg in meth.args: for idx, arg in meth.args:
if arg.typ == "string": if arg.typ == "string":
body.add(newCall("deinit", ident("argToPassToGodot" & $idx))) body.add(newCall("deinit", ident("argToPassToGodot" & $idx)))
if meth.args.len > 0 and not varargsName.isNil: if varargsName.isSome:
if meth.args.len > 0:
body.add(freeCall) body.add(freeCall)
if not varargsName.isNil: body.add(destructors)
let errCheck = newIfStmt( let errCheck = newIfStmt(
infix(newDotExpr(ident("callError"), ident("error")), ident("!="), infix(newDotExpr(ident("callError"), ident("error")), ident("!="),
newDotExpr(ident("VariantCallErrorType"), ident("OK"))), newDotExpr(ident("VariantCallErrorType"), ident("OK"))),
newNode(nkRaiseStmt).addChain( newPNode(nkRaiseStmt).addChain(
newCall("newCallError", ident("callError"))) newCall("newCallError", ident("callError")))
) )
body.add(errCheck) body.add(errCheck)
if isVariantRet: if isVariantRet:
let convErrDef = newNode(nkLetSection).addChain( let convErrDef = newPNode(nkLetSection).addChain(
newIdentDefs(ident("convErr"), newNode(nkEmpty), newIdentDefs(ident("convErr"), newPNode(nkEmpty),
newCall("fromVariant", ident("result"), newCall("fromVariant", ident("result"),
newCall("newVariant", retValIdent)))) newCall("newVariant", retValIdent))))
let convCheck = newIfStmt( let convCheck = newIfStmt(
infix(ident("convErr"), ident("!="), infix(ident("convErr"), ident("!="),
newDotExpr(ident("ConversionResult"), ident("OK"))), newDotExpr(ident("ConversionResult"), ident("OK"))),
newNode(nkRaiseStmt).addChain( newPNode(nkRaiseStmt).addChain(
newCall("newConversionError", ident("convErr"))) newCall("newConversionError", ident("convErr")))
) )
body.add(convErrDef) body.add(convErrDef)
body.add(convCheck) body.add(convCheck)
if isStringRet: if isStringRet:
body.add(newNode(nkAsgn).addChain( body.add(newPNode(nkAsgn).addChain(
ident("result"), prefix("$", retValIdent))) ident("result"), prefix("$", retValIdent)))
body.add(newCall("deinit", retValIdent)) body.add(newCall("deinit", retValIdent))
elif isConversionRet: elif isConversionRet:
body.add(newNode(nkAsgn).addChain( body.add(newPNode(nkAsgn).addChain(
ident("result"), ident("result"),
newCall(meth.returnType, retValIdent))) newCall(meth.returnType.get, retValIdent)))
elif isWrapperRet: elif isWrapperRet:
body.add(newNode(nkAsgn).addChain( body.add(newPNode(nkAsgn).addChain(
ident("result"), ident("result"),
newCall("new" & meth.returnType, retValIdent))) newCall("new" & meth.returnType.get, retValIdent)))
elif isObjRet: elif isObjRet:
body.add(newNode(nkAsgn).addChain(ident("result"), body.add(newPNode(nkAsgn).addChain(ident("result"),
newCall(newBracketExpr(ident("asNimGodotObject"), newCall(newBracketExpr(ident("asNimGodotObject"),
newCall("type", ident("result"))), newCall("type", ident("result"))),
retValIdent, ident("false"), ident("true")))) retValIdent, ident("false"), ident("true"))))
elif isStringRet: elif isStringRet:
body.add(newNode(nkAsgn).addChain(ident("result"), body.add(newPNode(nkAsgn).addChain(ident("result"),
newCall("$", retValIdent))) newCall("$", retValIdent)))
let procType = if meth.isVirtual: nkMethodDef let procType = if meth.isVirtual: nkMethodDef
else: nkProcDef else: nkProcDef
var params = newSeqOfCap[PNode](meth.args.len + 2) var params = newSeqOfCap[PNode](meth.args.len + 2)
if not meth.returnType.isNil: if meth.returnType.isSome:
params.add(ident(meth.returnType)) params.add(ident(meth.returnType.get))
else: else:
params.add(newNode(nkEmpty)) params.add(newPNode(nkEmpty))
if not meth.typ.isSingleton: if not meth.typ.isSingleton:
params.add(newIdentDefs(ident("self"), ident(toNimType(meth.typ.name)))) params.add(newIdentDefs(ident("self"), ident(toNimType(meth.typ.name))))
@ -669,7 +737,7 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
params.add(newIdentDefs(ident(arg.name), ident(arg.typ), defaultValue)) params.add(newIdentDefs(ident(arg.name), ident(arg.typ), defaultValue))
of ArgKind.VarArgs: of ArgKind.VarArgs:
params.add(newIdentDefs(ident(arg.name), params.add(newIdentDefs(ident(arg.name),
newNode(nkBracketExpr).addChain(ident("varargs"), ident(arg.typ)))) newPNode(nkBracketExpr).addChain(ident("varargs"), ident(arg.typ))))
of ArgKind.Bound: of ArgKind.Bound:
discard discard
@ -677,14 +745,14 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
else: meth.name, else: meth.name,
params, body, procType) params, body, procType)
if not withImplementation: if not withImplementation:
let pragma = newNode(nkPragma) let pragma = newPNode(nkPragma)
pragma.add(ident("gcsafe")) pragma.add(ident("gcsafe"))
pragma.add(newNode(nkExprColonExpr).addChain(ident("locks"), pragma.add(newPNode(nkExprColonExpr).addChain(ident("locks"),
newIntLit(0))) newIntLit(0)))
if meth.isVirtual and meth.isBase and meth.typ.name != "PhysicsBody": if meth.isVirtual and meth.isBase and meth.typ.name != "PhysicsBody":
# Nim doesn't like `base` on PhysicsBody methods - wtf # Nim doesn't like `base` on PhysicsBody methods - wtf
pragma.add(ident("base")) pragma.add(ident("base"))
if meth.isDiscardable and not meth.returnType.isNil: if meth.isDiscardable and meth.returnType.isSome:
pragma.add(ident("discardable")) pragma.add(ident("discardable"))
procDecl.sons[4] = pragma procDecl.sons[4] = pragma
tree.add(procDecl) tree.add(procDecl)
@ -729,9 +797,9 @@ proc getMethodInfo(methodObj: JsonNode, types: Table[string, GodotType],
nimName = nimName & "Impl" nimName = nimName & "Impl"
let returnType = if methodObj["return_type"].str != "void": let returnType = if methodObj["return_type"].str != "void":
toNimType(types, methodObj["return_type"].str) some(toNimType(types, methodObj["return_type"].str))
else: nil else: none(string)
const discardableMethods = toSet(["emit_signal"]) const discardableMethods = toHashSet(["emit_signal"])
result = MethodInfo( result = MethodInfo(
name: ident(nimName), name: ident(nimName),
typ: typ, typ: typ,
@ -760,17 +828,17 @@ proc makeProperty(types: Table[string, GodotType], tree: PNode,
return return
let getterNameStr = toNimStyle(propertyObj["name"].str) let getterNameStr = toNimStyle(propertyObj["name"].str)
let getterName = ident(getterNameStr) let getterName = ident(getterNameStr)
let setterName = newNode(nkAccQuoted).addChain(ident(getterNameStr & "=")) let setterName = newPNode(nkAccQuoted).addChain(ident(getterNameStr & "="))
let getter = findMethod(obj, propertyObj["getter"].str) let getter = findMethod(obj, propertyObj["getter"].str)
let nimType = if getter.isNil: toNimType(types, propertyObj["type"].str) let nimType = if getter.isNil: toNimType(types, propertyObj["type"].str)
else: getMethodInfo(getter, types, typ).returnType else: getMethodInfo(getter, types, typ).returnType.get("void")
let getterInfo = MethodInfo( let getterInfo = MethodInfo(
name: getterName, name: getterName,
typ: typ, typ: typ,
godotName: propertyObj["getter"].str, godotName: propertyObj["getter"].str,
args: @[], args: newSeq[MethodArg](),
returnType: nimType returnType: some(nimType)
) )
let setterInfo = MethodInfo( let setterInfo = MethodInfo(
name: setterName, name: setterName,
@ -779,9 +847,11 @@ proc makeProperty(types: Table[string, GodotType], tree: PNode,
args: @[MethodArg(name: "val", typ: nimType)] args: @[MethodArg(name: "val", typ: nimType)]
) )
if "index" in propertyObj and propertyObj["index"] != newJInt(-1): if "index" in propertyObj and propertyObj["index"] != newJInt(-1):
getterInfo.args = @[MethodArg(defaultVal: newJString($propertyObj["index"]), getterInfo.args =
@[MethodArg(defaultVal: newJString($propertyObj["index"]),
typ: "int", kind: ArgKind.Bound)] & getterInfo.args typ: "int", kind: ArgKind.Bound)] & getterInfo.args
setterInfo.args = @[MethodArg(defaultVal: newJString($propertyObj["index"]), setterInfo.args =
@[MethodArg(defaultVal: newJString($propertyObj["index"]),
typ: "int", kind: ArgKind.Bound)] & setterInfo.args typ: "int", kind: ArgKind.Bound)] & setterInfo.args
generateMethod(tree, methodBindRegistry, getterInfo, withImplementation) generateMethod(tree, methodBindRegistry, getterInfo, withImplementation)
generateMethod(tree, methodBindRegistry, setterInfo, withImplementation) generateMethod(tree, methodBindRegistry, setterInfo, withImplementation)
@ -844,10 +914,10 @@ proc newRegisterClassNode(typ: GodotType): PNode =
) )
proc genSingletonDecl(typ: string): PNode = proc genSingletonDecl(typ: string): PNode =
result = newNode(nkVarSection) result = newPNode(nkVarSection)
let name = singletonName(typ) let name = singletonName(typ)
let threadvar = newNode(nkPragma).addChain(ident("threadvar")) let threadvar = newPNode(nkPragma).addChain(ident("threadvar"))
result.add(newIdentDefs(newNode(nkPragmaExpr).addChain(name, threadvar), result.add(newIdentDefs(newPNode(nkPragmaExpr).addChain(name, threadvar),
ident(typ))) ident(typ)))
proc shouldExport(typ: GodotType, types: Table[string, GodotType]): bool = proc shouldExport(typ: GodotType, types: Table[string, GodotType]): bool =
@ -864,9 +934,9 @@ proc sortByDerivedCount(types: Table[string, GodotType]): seq[GodotType] =
proc genTypeFile(types: Table[string, GodotType], targetDir: string) = proc genTypeFile(types: Table[string, GodotType], targetDir: string) =
let sortedTypes = sortByDerivedCount(types) let sortedTypes = sortByDerivedCount(types)
let godotApiTypesTree = newNode(nkStmtList) let godotApiTypesTree = newPNode(nkStmtList)
godotApiTypesTree.add(newNode(nkImportStmt).addChain(ident("godot"))) godotApiTypesTree.add(newPNode(nkImportStmt).addChain(ident("godot")))
let typeSection = newNode(nkTypeSection) let typeSection = newPNode(nkTypeSection)
godotApiTypesTree.add(typeSection) godotApiTypesTree.add(typeSection)
for typ in sortedTypes: for typ in sortedTypes:
@ -888,10 +958,10 @@ proc genSingletonWithDerived(tree: PNode, typ: GodotType,
types: Table[string, GodotType]) = types: Table[string, GodotType]) =
let sortedTypes = sortByDerivedCount(types) let sortedTypes = sortByDerivedCount(types)
var parents = initSet[string]() var parents = initHashSet[string]()
parents.incl(typ.name) parents.incl(typ.name)
let typeDecl = newNode(nkTypeSection) let typeDecl = newPNode(nkTypeSection)
tree.add(typeDecl) tree.add(typeDecl)
proc genDecl(typ: GodotType) = proc genDecl(typ: GodotType) =
newRefTypeNode(typeDecl, typ.name, typ.baseName, typ.doc, newRefTypeNode(typeDecl, typ.name, typ.baseName, typ.doc,
@ -920,7 +990,7 @@ proc genApi*(targetDir: string, apiJsonFile: string) =
let className = godotClassName.replace("_", "") let className = godotClassName.replace("_", "")
var baseClassName = obj["base_class"].str var baseClassName = obj["base_class"].str
baseClassName = toNimType(baseClassName.replace("_", "")) baseClassName = toNimType(baseClassName.replace("_", ""))
if baseClassName.isNil or baseClassName.len == 0: if baseClassName.len == 0:
baseClassName = "NimGodotObject" baseClassName = "NimGodotObject"
var doc = "" var doc = ""
for attr in classAttributes: for attr in classAttributes:
@ -941,17 +1011,17 @@ proc genApi*(targetDir: string, apiJsonFile: string) =
for typ in types.values(): for typ in types.values():
let moduleName = typeNameToModuleName(typ.name) let moduleName = typeNameToModuleName(typ.name)
echo "Generating ", moduleName, ".nim..." echo "Generating ", moduleName, ".nim..."
let tree = newNode(nkStmtList) let tree = newPNode(nkStmtList)
let importStmt = newNode(nkImportStmt) let importStmt = newPNode(nkImportStmt)
importStmt.add(ident("godot")) importStmt.add(ident("godot"))
importStmt.add(ident("godottypes")) importStmt.add(ident("godottypes"))
importStmt.add(ident("godotinternal")) importStmt.add(ident("godotinternal"))
tree.add(importStmt) tree.add(importStmt)
let exportStmt = newNode(nkExportStmt) let exportStmt = newPNode(nkExportStmt)
exportStmt.add(ident("godottypes")) exportStmt.add(ident("godottypes"))
tree.add(exportStmt) tree.add(exportStmt)
var methodBindRegsitry = initSet[string]() var methodBindRegsitry = initHashSet[string]()
let obj = typ.jsonNode let obj = typ.jsonNode
if typ.baseName != "NimGodotObject": if typ.baseName != "NimGodotObject":
let baseModule = typeNameToModuleName(typ.baseName) let baseModule = typeNameToModuleName(typ.baseName)
@ -1012,7 +1082,6 @@ when isMainModule:
import os import os
const usage = """Tool for wrapping Godot API into Nim const usage = """Tool for wrapping Godot API into Nim
godotapigen [godot binary path] [target directory]""" godotapigen [godot binary path] [target directory]"""
proc main() = proc main() =

View file

@ -1,8 +1,8 @@
# Copyright 2018 Xored Software, Inc. # Copyright 2018 Xored Software, Inc.
import internal.godotinternaltypes, internal.godotarrays, import internal/godotinternaltypes, internal/godotarrays,
internal.godotnodepaths, internal.godotpoolarrays, internal.godotstrings, internal/godotnodepaths, internal/godotpoolarrays, internal/godotstrings,
internal.godotvariants, internal.godotdictionaries internal/godotvariants, internal/godotdictionaries
import gdnativeapi import gdnativeapi
export godotinternaltypes, godotarrays, godotnodepaths, godotpoolarrays, export godotinternaltypes, godotarrays, godotnodepaths, godotpoolarrays,

View file

@ -0,0 +1,19 @@
# Copyright 2019 Xored Software, Inc.
when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
import macros, sets
proc strVal(n: NimNode): string {.used.} =
case n.kind
of nnkIdent:
$n.ident
of nnkSym:
$n.symbol
else:
macros.strVal(n)
proc toHashSet[A](keys: openArray[A]): HashSet[A] {.inline, used.} =
toSet(keys)
proc initHashSet[A](): HashSet[A] {.inline, used.} =
initSet[A]()

View file

@ -1,6 +1,6 @@
# Copyright (c) 2018 Xored Software, Inc. # Copyright (c) 2018 Xored Software, Inc.
import godotinternaltypes, gdnativeapi, core.godotcoretypes import godotinternaltypes, gdnativeapi, core/godotcoretypes
proc len*(self: GodotArray): cint {.inline.} = proc len*(self: GodotArray): cint {.inline.} =
getGDNativeAPI().arraySize(self) getGDNativeAPI().arraySize(self)

View file

@ -116,7 +116,8 @@ type
expected*: VariantType expected*: VariantType
GodotVariant* {.byref.} = object GodotVariant* {.byref.} = object
data: array[4 + sizeof(int) div 4, float32] data: array[2, int64]
data2: int
type GodotMethodBind* = object type GodotMethodBind* = object

View file

@ -1,7 +1,7 @@
# Copyright (c) 2018 Xored Software, Inc. # Copyright (c) 2018 Xored Software, Inc.
import godotinternaltypes, gdnativeapi import godotinternaltypes, gdnativeapi
import core.godotcoretypes import core/godotcoretypes
template genPoolArrayAPI(ArrayT, initIdent, DataT, template genPoolArrayAPI(ArrayT, initIdent, DataT,
newProc, newCopyProc, newWithArrayProc, appendProc, newProc, newCopyProc, newWithArrayProc, appendProc,
@ -45,7 +45,15 @@ template genPoolArrayAPI(ArrayT, initIdent, DataT,
getGDNativeAPI().setProc(self, idx, data) getGDNativeAPI().setProc(self, idx, data)
proc `[]`*(self: ArrayT; idx: cint): DataT {.inline.} = proc `[]`*(self: ArrayT; idx: cint): DataT {.inline.} =
getGDNativeAPI().getProc(self, idx) let data = getGDNativeAPI().getProc(self, idx)
when DataT is Color:
data.toColor()
elif DataT is Vector2:
data.toVector2()
elif DataT is Vector3:
data.toVector3()
else:
data
proc len*(self: ArrayT): cint {.inline.} = proc len*(self: ArrayT): cint {.inline.} =
getGDNativeAPI().sizeProc(self) getGDNativeAPI().sizeProc(self)

View file

@ -38,10 +38,13 @@ proc `$`*(self: GodotString): string =
proc toGodotString*(s: string): GodotString {.inline.} = proc toGodotString*(s: string): GodotString {.inline.} =
## Converts the Nim string into ``GodotString`` ## Converts the Nim string into ``GodotString``
when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
if s.isNil: if s.isNil:
initGodotString(result) initGodotString(result)
else: else:
initGodotString(result, cstring(s), cint(s.len + 1)) initGodotString(result, cstring(s), cint(s.len + 1))
else:
initGodotString(result, cstring(s), cint(s.len + 1))
proc toGodotString*(s: cstring): GodotString {.inline.} = proc toGodotString*(s: cstring): GodotString {.inline.} =
## Converts the cstring into ``GodotString`` ## Converts the cstring into ``GodotString``

View file

@ -1,6 +1,6 @@
# Copyright 2018 Xored Software, Inc. # Copyright 2018 Xored Software, Inc.
import core.godotcoretypes, godotinternaltypes, gdnativeapi import core/godotcoretypes, godotinternaltypes, gdnativeapi
proc getType*(p: GodotVariant): VariantType {.inline.} = proc getType*(p: GodotVariant): VariantType {.inline.} =
getGDNativeAPI().variantGetType(p) getGDNativeAPI().variantGetType(p)
@ -121,34 +121,34 @@ proc asGodotString*(self: GodotVariant): GodotString {.inline.} =
getGDNativeAPI().variantAsString(self) getGDNativeAPI().variantAsString(self)
proc asVector2*(self: GodotVariant): Vector2 {.inline.} = proc asVector2*(self: GodotVariant): Vector2 {.inline.} =
getGDNativeAPI().variantAsVector2(self) getGDNativeAPI().variantAsVector2(self).toVector2()
proc asRect2*(self: GodotVariant): Rect2 {.inline.} = proc asRect2*(self: GodotVariant): Rect2 {.inline.} =
getGDNativeAPI().variantAsRect2(self) getGDNativeAPI().variantAsRect2(self).toRect2()
proc asVector3*(self: GodotVariant): Vector3 {.inline.} = proc asVector3*(self: GodotVariant): Vector3 {.inline.} =
getGDNativeAPI().variantAsVector3(self) getGDNativeAPI().variantAsVector3(self).toVector3()
proc asTransform2D*(self: GodotVariant): Transform2D {.inline.} = proc asTransform2D*(self: GodotVariant): Transform2D {.inline.} =
getGDNativeAPI().variantAsTransform2D(self) getGDNativeAPI().variantAsTransform2D(self).toTransform2D()
proc asPlane*(self: GodotVariant): Plane {.inline.} = proc asPlane*(self: GodotVariant): Plane {.inline.} =
getGDNativeAPI().variantAsPlane(self) getGDNativeAPI().variantAsPlane(self).toPlane()
proc asQuat*(self: GodotVariant): Quat {.inline.} = proc asQuat*(self: GodotVariant): Quat {.inline.} =
getGDNativeAPI().variantAsQuat(self) getGDNativeAPI().variantAsQuat(self).toQuat()
proc asAABB*(self: GodotVariant): AABB {.inline.} = proc asAABB*(self: GodotVariant): AABB {.inline.} =
getGDNativeAPI().variantAsAABB(self) getGDNativeAPI().variantAsAABB(self).toAABB()
proc asBasis*(self: GodotVariant): Basis {.inline.} = proc asBasis*(self: GodotVariant): Basis {.inline.} =
getGDNativeAPI().variantAsBasis(self) getGDNativeAPI().variantAsBasis(self).toBasis()
proc asTransform*(self: GodotVariant): Transform {.inline.} = proc asTransform*(self: GodotVariant): Transform {.inline.} =
getGDNativeAPI().variantAsTransform(self) getGDNativeAPI().variantAsTransform(self).toTransform()
proc asColor*(self: GodotVariant): Color {.inline.} = proc asColor*(self: GodotVariant): Color {.inline.} =
getGDNativeAPI().variantAsColor(self) getGDNativeAPI().variantAsColor(self).toColor()
proc asNodePath*(self: GodotVariant): GodotNodePath {.inline.} = proc asNodePath*(self: GodotVariant): GodotNodePath {.inline.} =
getGDNativeAPI().variantAsNodePath(self) getGDNativeAPI().variantAsNodePath(self)

View file

@ -1,8 +1,8 @@
# Copyright 2018 Xored Software, Inc. # Copyright 2018 Xored Software, Inc.
import macros, tables, typetraits import macros, tables, typetraits, strutils, sets, sequtils, options, algorithm
import godotinternal, internal.godotvariants import godotinternal, internal/godotvariants
import godotnim, core.variants import godotnim, core/variants
type type
VarDecl = ref object VarDecl = ref object
@ -10,8 +10,8 @@ type
typ: NimNode typ: NimNode
defaultValue: NimNode defaultValue: NimNode
isNoGodot: bool isNoGodot: bool
hint: string hint: Option[string]
hintStr: string hintStr: Option[string]
usage: NimNode usage: NimNode
isExported: bool isExported: bool
@ -32,6 +32,8 @@ type
ParseError = object of Exception ParseError = object of Exception
include "internal/backwardcompat.inc.nim"
proc godotToNim[T](val: Variant): (T, ConversionResult) = proc godotToNim[T](val: Variant): (T, ConversionResult) =
mixin fromVariant mixin fromVariant
result[1] = fromVariant(result[0], val) result[1] = fromVariant(result[0], val)
@ -51,15 +53,15 @@ template parseError(node: NimNode, msg: string) =
proc extractNames(definition: NimNode): proc extractNames(definition: NimNode):
tuple[name, parentName: string] = tuple[name, parentName: string] =
if definition.kind == nnkIdent: if definition.kind == nnkIdent:
result.name = $(definition.ident) result.name = definition.strVal
else: else:
if not (definition.kind == nnkInfix and if not (definition.kind == nnkInfix and
definition[0].ident == toNimIdent("of")): definition[0].strVal == "of"):
parseError(definition, "invalid type definition") parseError(definition, "invalid type definition")
result.name = $(definition[1].ident) result.name = definition[1].strVal
case definition[2].kind: case definition[2].kind:
of nnkIdent: of nnkIdent:
result.parentName = $definition[2].ident result.parentName = definition[2].strVal
else: else:
parseError(definition[2], "parent type expected") parseError(definition[2], "parent type expected")
@ -72,13 +74,13 @@ proc newCStringLit(s: string): NimNode {.compileTime.} =
newNimNode(nnkCallStrLit).add(ident("cstring"), newRStrLit(s)) newNimNode(nnkCallStrLit).add(ident("cstring"), newRStrLit(s))
iterator pragmas(node: NimNode): iterator pragmas(node: NimNode):
tuple[key: NimIdent, value: NimNode, index: int] = tuple[key: string, value: NimNode, index: int] =
assert node.kind in {nnkPragma, nnkEmpty} assert node.kind in {nnkPragma, nnkEmpty}
for index in countdown(node.len - 1, 0): for index in countdown(node.len - 1, 0):
if node[index].kind == nnkExprColonExpr: if node[index].kind == nnkExprColonExpr:
yield (node[index][0].ident, node[index][1], index) yield (node[index][0].strVal, node[index][1], index)
elif node[index].kind == nnkIdent: elif node[index].kind == nnkIdent:
yield (node[index].ident, nil, index) yield (node[index].strVal, nil, index)
proc removePragmaNode(statement: NimNode, proc removePragmaNode(statement: NimNode,
pname: string): NimNode {.compileTime.} = pname: string): NimNode {.compileTime.} =
@ -91,9 +93,8 @@ proc removePragmaNode(statement: NimNode,
result = nil result = nil
var pragmas = if RoutineNodes.contains(statement.kind): statement.pragma() var pragmas = if RoutineNodes.contains(statement.kind): statement.pragma()
else: statement[1] else: statement[1]
let pnameIdent = toNimIdent(pname)
for ident, val, i in pragmas(pragmas): for ident, val, i in pragmas(pragmas):
if ident == pnameIdent: if ident.eqIdent(pname):
pragmas.del(i) pragmas.del(i)
return val return val
@ -104,19 +105,18 @@ proc removePragma(statement: NimNode, pname: string): bool =
return false return false
var pragmas = if RoutineNodes.contains(statement.kind): statement.pragma() var pragmas = if RoutineNodes.contains(statement.kind): statement.pragma()
else: statement[1] else: statement[1]
let pnameIdent = toNimIdent(pname)
for ident, val, i in pragmas(pragmas): for ident, val, i in pragmas(pragmas):
if ident == pnameIdent: if ident.eqIdent(pname):
pragmas.del(i) pragmas.del(i)
return true return true
proc removeStrPragma(statement: NimNode, proc removeStrPragma(statement: NimNode,
pname: string): string {.compileTime.} = pname: string): Option[string] {.compileTime.} =
## Removes the pragma from the node and returns value of the pragma ## Removes the pragma from the node and returns value of the pragma
## Works for routine nodes or nnkPragmaExpr ## Works for routine nodes or nnkPragmaExpr
let node = removePragmaNode(statement, pname) let node = removePragmaNode(statement, pname)
result = if node.isNil: nil result = if node.isNil: none(string)
else: $node else: some($node)
proc isExported(node: NimNode): bool {.compileTime.} = proc isExported(node: NimNode): bool {.compileTime.} =
if node.kind == nnkPragmaExpr: if node.kind == nnkPragmaExpr:
@ -178,8 +178,9 @@ proc parseVarSection(decl: NimNode): seq[VarDecl] =
else: else:
result.add(identDefsToVarDecls(decl[i])) result.add(identDefsToVarDecls(decl[i]))
proc parseType(definition, callSite: NimNode): ObjectDecl = proc parseType(ast: NimNode): ObjectDecl =
let body = callSite[^1] let definition = ast[0]
let body = ast[^1]
result = ObjectDecl( result = ObjectDecl(
fields: newSeq[VarDecl](), fields: newSeq[VarDecl](),
methods: newSeq[MethodDecl]() methods: newSeq[MethodDecl]()
@ -187,17 +188,17 @@ proc parseType(definition, callSite: NimNode): ObjectDecl =
(result.name, result.parentName) = extractNames(definition) (result.name, result.parentName) = extractNames(definition)
var isTool = false var isTool = false
for i in 2..(callSite.len - 2): for i in 1..(ast.len - 2):
let option = callSite[i] let option = ast[i]
if option.kind != nnkIdent: if option.kind != nnkIdent:
parseError(option, "type specifier expected") parseError(option, "type specifier expected")
if option.ident == toNimIdent("tool"): if option.strVal == "tool":
isTool = true isTool = true
else: else:
parseError(option, "valid type specifier expected") parseError(option, "valid type specifier expected")
result.isTool = isTool result.isTool = isTool
if result.parentName.isNil: result.parentName = "Object" if result.parentName.len == 0: result.parentName = "Object"
for statement in body: for statement in body:
case statement.kind: case statement.kind:
of nnkVarSection: of nnkVarSection:
@ -214,7 +215,7 @@ proc parseType(definition, callSite: NimNode): ObjectDecl =
macro invokeVarArgs(procIdent, objIdent; macro invokeVarArgs(procIdent, objIdent;
minArgs, maxArgs: static[int], numArgsIdent, minArgs, maxArgs: static[int], numArgsIdent,
argSeqIdent; argTypes: seq[NimNode], argSeqIdent; argTypes: seq[NimNode],
hasReturnValue, isStaticCall: static[bool]): typed = hasReturnValue, isStaticCall: static[bool]): untyped =
## Produces statement in form: ## Produces statement in form:
## ##
## .. code-block:: nim ## .. code-block:: nim
@ -271,8 +272,12 @@ macro invokeVarArgs(procIdent, objIdent;
invocation = newNimNode(nnkCall).add(ident("procCall"), invocation) invocation = newNimNode(nnkCall).add(ident("procCall"), invocation)
if hasReturnValue: if hasReturnValue:
let resultVariant = genSym(nskLet, "ret")
branchBody.add(
newNimNode(nnkLetSection).add(
newIdentDefs(resultVariant, ident("Variant"), newCall("toVariant", invocation))))
let theCall = newNimNode(nnkBracketExpr).add(newNimNode(nnkDotExpr).add( let theCall = newNimNode(nnkBracketExpr).add(newNimNode(nnkDotExpr).add(
newCall("toVariant", invocation), ident("godotVariant"))) resultVariant, ident("godotVariant")))
branchBody.add(getAst(initGodotVariantCall(ident("result"), theCall))) branchBody.add(getAst(initGodotVariantCall(ident("result"), theCall)))
else: else:
branchBody.add(invocation) branchBody.add(invocation)
@ -287,7 +292,7 @@ macro invokeVarArgs(procIdent, objIdent;
" arguments, but got " & $numArgs) " arguments, but got " & $numArgs)
result.add(newNimNode(nnkElse).add(getAst( result.add(newNimNode(nnkElse).add(getAst(
printInvokeErr($procIdent.ident, minArgs, maxArgs, numArgsIdent)))) printInvokeErr(procIdent.strVal, minArgs, maxArgs, numArgsIdent))))
proc typeError(nimType: string, value: string, godotType: VariantType, proc typeError(nimType: string, value: string, godotType: VariantType,
className: cstring, propertyName: cstring): string = className: cstring, propertyName: cstring): string =
@ -395,10 +400,9 @@ template registerGodotField(classNameLit, classNameIdent, propNameLit,
getFunc: getFuncIdent getFunc: getFuncIdent
) )
mixin godotTypeInfo mixin godotTypeInfo
static: const typeInfo = when compiles(godotTypeInfo(propTypeIdent)):
var typeInfo: GodotTypeInfo godotTypeInfo(propTypeIdent)
when compiles(godotTypeInfo(propTypeIdent)): else: GodotTypeInfo()
typeInfo = godotTypeInfo(propTypeIdent)
const hintStr = when hintStrLit != "NIM": const hintStr = when hintStrLit != "NIM":
hintStrLit hintStrLit
else: else:
@ -424,9 +428,6 @@ template registerGodotField(classNameLit, classNameIdent, propNameLit,
unsafeAddr attr, setFunc, getFunc) unsafeAddr attr, setFunc, getFunc)
hintStrGodot.deinit() hintStrGodot.deinit()
static:
import strutils, sets, sequtils
proc toGodotStyle(s: string): string {.compileTime.} = proc toGodotStyle(s: string): string {.compileTime.} =
result = newStringOfCap(s.len + 10) result = newStringOfCap(s.len + 10)
for c in s: for c in s:
@ -447,7 +448,7 @@ proc genType(obj: ObjectDecl): NimNode {.compileTime.} =
let objTy = newNimNode(nnkObjectTy) let objTy = newNimNode(nnkObjectTy)
typeDef.add(newNimNode(nnkRefTy).add(objTy)) typeDef.add(newNimNode(nnkRefTy).add(objTy))
objTy.add(newEmptyNode()) objTy.add(newEmptyNode())
if obj.parentName.isNil: if obj.parentName.len == 0:
objTy.add(newEmptyNode()) objTy.add(newEmptyNode())
else: else:
objTy.add(newNimNode(nnkOfInherit).add(ident(obj.parentName))) objTy.add(newNimNode(nnkOfInherit).add(ident(obj.parentName)))
@ -457,7 +458,8 @@ proc genType(obj: ObjectDecl): NimNode {.compileTime.} =
let initBody = newStmtList() let initBody = newStmtList()
for decl in obj.fields: for decl in obj.fields:
if not decl.defaultValue.isNil and decl.defaultValue.kind != nnkEmpty: if not decl.defaultValue.isNil and decl.defaultValue.kind != nnkEmpty:
initBody.add(newNimNode(nnkAsgn).add(decl.name, decl.defaultValue)) initBody.add(newNimNode(nnkAsgn).add(newDotExpr(ident("self"), decl.name),
decl.defaultValue))
let name = if not decl.isExported: decl.name let name = if not decl.isExported: decl.name
else: postfix(decl.name, "*") else: postfix(decl.name, "*")
recList.add(newIdentDefs(name, decl.typ)) recList.add(newIdentDefs(name, decl.typ))
@ -483,6 +485,7 @@ proc genType(obj: ObjectDecl): NimNode {.compileTime.} =
else: else:
initMethod.body.insert(0, initBody) initMethod.body.insert(0, initBody)
when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
# {.this: self.} for convenience # {.this: self.} for convenience
result.add(newNimNode(nnkPragma).add(newNimNode(nnkExprColonExpr).add( result.add(newNimNode(nnkPragma).add(newNimNode(nnkExprColonExpr).add(
ident("this"), ident("self") ident("this"), ident("self")
@ -506,23 +509,25 @@ proc genType(obj: ObjectDecl): NimNode {.compileTime.} =
result.add(meth.nimNode) result.add(meth.nimNode)
# Register Godot object # Register Godot object
let parentName = if obj.parentName.isNil: newStrLitNode("Object") let parentName = if obj.parentName.len == 0: newStrLitNode("Object")
else: newStrLitNode(obj.parentName) else: newStrLitNode(obj.parentName)
let classNameLit = newStrLitNode(obj.name) let classNameLit = newStrLitNode(obj.name)
let classNameIdent = ident(obj.name) let classNameIdent = ident(obj.name)
let isRef: bool = if obj.parentName.isNil: false let isRef: bool = if obj.parentName.len == 0: false
else: obj.parentName in refClasses else: obj.parentName in refClasses
# Wrapping bools with a newLit is required as a temporary workaround for
# https://github.com/nim-lang/Nim/issues/7375
result.add(getAst( result.add(getAst(
registerGodotClass(classNameIdent, classNameLit, isRef, parentName, registerGodotClass(classNameIdent, classNameLit, newLit(isRef), parentName,
genSym(nskProc, "createFunc"), obj.isTool))) genSym(nskProc, "createFunc"), newLit(obj.isTool))))
# Register fields (properties) # Register fields (properties)
for field in obj.fields: for field in obj.fields:
if field.isNoGodot: continue if field.isNoGodot: continue
let hintStr = if field.hintStr.isNil: "NIM" let hintStr = if field.hintStr.isNone: "NIM"
else: field.hintStr else: field.hintStr.get
let hint = if field.hint.isNil: "NIM" let hint = if field.hint.isNone: "NIM"
else: field.hint else: field.hint.get
let usage = let usage =
if field.usage.isNil: if field.usage.isNil:
newLit(ord(GodotPropertyUsage.Default) or newLit(ord(GodotPropertyUsage.Default) or
@ -545,17 +550,23 @@ proc genType(obj: ObjectDecl): NimNode {.compileTime.} =
template registerGodotMethod(classNameLit, classNameIdent, methodNameIdent, template registerGodotMethod(classNameLit, classNameIdent, methodNameIdent,
methodNameLit, minArgs, maxArgs, methodNameLit, minArgs, maxArgs,
argTypes, methFuncIdent, hasReturnValue) = argTypes, methFuncIdent, hasReturnValue) =
when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
{.emit: """/*TYPESECTION*/ {.emit: """/*TYPESECTION*/
N_NOINLINE(void, setStackBottom)(void* thestackbottom); N_NOINLINE(void, setStackBottom)(void* thestackbottom);
""".} """.}
proc methFuncIdent(obj: ptr GodotObject, methodData: pointer, proc methFuncIdent(obj: ptr GodotObject, methodData: pointer,
userData: pointer, numArgs: cint, userData: pointer, numArgs: cint,
args: var array[MAX_ARG_COUNT, ptr GodotVariant]): args: var array[MAX_ARG_COUNT, ptr GodotVariant]):
GodotVariant {.noconv.} = GodotVariant {.noconv.} =
var stackBottom {.volatile.}: pointer var stackBottom {.volatile.}: pointer
stackBottom = addr(stackBottom)
when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
{.emit: """ {.emit: """
setStackBottom((void*)(&`stackBottom`)); setStackBottom((void*)(&`stackBottom`));
""".} """.}
else:
nimGC_setStackBottom(stackBottom)
let self = cast[classNameIdent](userData) let self = cast[classNameIdent](userData)
const isStaticCall = methodNameLit == cstring"_ready" or const isStaticCall = methodNameLit == cstring"_ready" or
methodNameLit == cstring"_process" or methodNameLit == cstring"_process" or
@ -599,7 +610,7 @@ N_NOINLINE(void, setStackBottom)(void* thestackbottom);
let hasReturnValueBool = not (meth.returnType.isNil or let hasReturnValueBool = not (meth.returnType.isNil or
meth.returnType.kind == nnkEmpty or meth.returnType.kind == nnkEmpty or
(meth.returnType.kind == nnkIdent and (meth.returnType.kind == nnkIdent and
meth.returnType.ident == toNimIdent("void"))) meth.returnType.strVal == "void"))
let hasReturnValue = if hasReturnValueBool: ident("true") let hasReturnValue = if hasReturnValueBool: ident("true")
else: ident("false") else: ident("false")
result.add(getAst( result.add(getAst(
@ -625,11 +636,7 @@ N_NOINLINE(void, setStackBottom)(void* thestackbottom);
GodotMethodAttributes(), refDec) GodotMethodAttributes(), refDec)
result.add(getAst(registerRefIncDec(classNameLit))) result.add(getAst(registerRefIncDec(classNameLit)))
{.push warning[Deprecated]: off.} macro gdobj*(ast: varargs[untyped]): untyped =
# 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: ## Generates Godot type. Self-documenting example:
## ##
## .. code-block:: nim ## .. code-block:: nim
@ -637,7 +644,7 @@ macro gdobj*(definition: untyped, body: typed): typed {.immediate.} =
## ##
## gdobj MyObj of Node: ## gdobj MyObj of Node:
## var myField: int ## var myField: int
## ## Not exported to Godot (i.e. editor will not see this field). ## ## Not exported to Godot (i.e. editor and scripts will not see this field).
## ##
## var myString* {.gdExport, hint: Length, hintStr: "20".}: string ## var myString* {.gdExport, hint: Length, hintStr: "20".}: string
## ## Exported to Godot as ``my_string``. ## ## Exported to Godot as ``my_string``.
@ -650,12 +657,12 @@ macro gdobj*(definition: untyped, body: typed): typed {.immediate.} =
## ## Exported methods are exported to Godot by default, ## ## Exported methods are exported to Godot by default,
## ## and their Godot names are prefixed with ``_`` ## ## and their Godot names are prefixed with ``_``
## ## (in this case ``_ready``) ## ## (in this case ``_ready``)
## print("I am ready! myString is: " & myString) ## print("I am ready! myString is: " & self.myString)
## ##
## proc myProc*() {.gdExport.} = ## proc myProc*() {.gdExport.} =
## ## Exported to Godot as ``my_proc`` ## ## Exported to Godot as ``my_proc``
## print("myProc is called! Incrementing myField.") ## print("myProc is called! Incrementing myField.")
## inc myField ## inc self.myField
## ##
## If parent type is omitted, the type is inherited from ``Object``. ## If parent type is omitted, the type is inherited from ``Object``.
## ##
@ -673,7 +680,5 @@ macro gdobj*(definition: untyped, body: typed): typed {.immediate.} =
## `gdnew <godotnim.html#gdnew>`_ or by using ## `gdnew <godotnim.html#gdnew>`_ or by using
## `load <godotapi/resource_loader.html#load,string,string,bool>`_ or any other way ## `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>`_. ## that you can find in `Godot API <index.html#modules-godot-api>`_.
let typeDef = parseType(definition, callsite()) let typeDef = parseType(ast)
result = genType(typeDef) result = genType(typeDef)
{.push warning[Deprecated]: on.}

View file

@ -1,14 +1,14 @@
# Copyright 2018 Xored Software, Inc. # Copyright 2018 Xored Software, Inc.
import tables, typetraits, macros, unicode import tables, typetraits, macros, unicode, strutils, sets, options
import gdnativeapi import gdnativeapi
import core.godotcoretypes, core.godotbase import core/godotcoretypes, core/godotbase
import core.vector2, core.rect2, import core/vector2, core/rect2,
core.vector3, core.transform2d, core/vector3, core/transform2d,
core.planes, core.quats, core.aabb, core/planes, core/quats, core/aabb,
core.basis, core.transforms, core.colors, core/basis, core/transforms, core/colors,
core.nodepaths, core.rids, core.dictionaries, core/nodepaths, core/rids, core/dictionaries,
core.arrays, core.poolarrays, core.variants core/arrays, core/poolarrays, core/variants
import godotinternal import godotinternal
## This module defines ``NimGodotObject`` and ``toVariant``/``fromVariant`` ## This module defines ``NimGodotObject`` and ``toVariant``/``fromVariant``
@ -31,7 +31,7 @@ type
## The base type all Godot types inherit from. ## The base type all Godot types inherit from.
## Manages lifecycle of the wrapped ``GodotObject``. ## Manages lifecycle of the wrapped ``GodotObject``.
godotObject: ptr GodotObject godotObject: ptr GodotObject
linkedObject: NimGodotObject linkedObjectPtr: pointer
## Wrapper around native object that is the container of the Nim "script" ## Wrapper around native object that is the container of the Nim "script"
## This is needed for `of` checks and `as` conversions to work as ## This is needed for `of` checks and `as` conversions to work as
## expected. For example, Nim type may inherit from ``Spatial``, but the ## expected. For example, Nim type may inherit from ``Spatial``, but the
@ -39,6 +39,8 @@ type
## ``Particles`` is valid, but Nim type system is not aware of that. ## ``Particles`` is valid, but Nim type system is not aware of that.
## This works in both directions - for linked native object this ## This works in both directions - for linked native object this
## reference points to Nim object. ## reference points to Nim object.
## This is stored as a raw pointer to avoid reference cycles and therefore
## improve GC performance.
isRef*: bool isRef*: bool
isFinalized: bool isFinalized: bool
isNative: bool isNative: bool
@ -91,6 +93,8 @@ type
FNV1Hash = uint32 FNV1Hash = uint32
include "internal/backwardcompat.inc.nim"
proc isFinalized*(obj: NimGodotObject): bool {.inline.} = proc isFinalized*(obj: NimGodotObject): bool {.inline.} =
obj.isFinalized obj.isFinalized
@ -101,8 +105,6 @@ var classRegistryStatic* {.compileTime.}: TableRef[FNV1Hash, ObjectInfo]
static: static:
classRegistryStatic = newTable[FNV1Hash, ObjectInfo]() classRegistryStatic = newTable[FNV1Hash, ObjectInfo]()
static:
import sets, strutils
var nativeClasses {.compileTime.} = newSeq[string]() var nativeClasses {.compileTime.} = newSeq[string]()
var refClasses* {.compileTime.} = newSeq[string]() var refClasses* {.compileTime.} = newSeq[string]()
@ -112,13 +114,13 @@ template initFNV1Hash(hash: var FNV1Hash) =
template appendFNV1Hash(hash: var FNV1Hash, val: uint8) = template appendFNV1Hash(hash: var FNV1Hash, val: uint8) =
block: block:
let u64hash = hash.uint64 let u64hash = hash.uint64
hash = ( hash = ((
u64hash + u64hash +
(u64hash shl 1'u64) + (u64hash shl 1'u64) +
(u64hash shl 4'u64) + (u64hash shl 4'u64) +
(u64hash shl 7'u64) + (u64hash shl 7'u64) +
(u64hash shl 8'u64) + (u64hash shl 8'u64) +
(u64hash shl 24'u64)).uint32 xor val (u64hash shl 24'u64)) and 0xFFFFFFFF'u32).uint32 xor val
{.push stackTrace:off.} {.push stackTrace:off.}
proc lsb(c: ptr cwchar_t): char {.noinit, inline.} = proc lsb(c: ptr cwchar_t): char {.noinit, inline.} =
@ -185,12 +187,15 @@ proc deinit*(obj: NimGodotObject) =
obj.godotObject.deinit() obj.godotObject.deinit()
obj.godotObject = nil obj.godotObject = nil
proc linkedObject(obj: NimGodotObject): NimGodotObject {.inline.} =
cast[NimGodotObject](obj.linkedObjectPtr)
proc nimGodotObjectFinalizer*[T: NimGodotObject](obj: T) = proc nimGodotObjectFinalizer*[T: NimGodotObject](obj: T) =
if obj.godotObject.isNil or obj.isNative: return if obj.godotObject.isNil or obj.isNative: return
# important to set it before so that ``unreference`` is aware # important to set it before so that ``unreference`` is aware
obj.isFinalized = true obj.isFinalized = true
if obj.isRef and obj.godotObject.unreference() or if (obj.isRef or not obj.linkedObject.isNil and obj.linkedObject.isRef) and
not obj.linkedObject.isNil: obj.godotObject.unreference():
obj.deinit() obj.deinit()
macro baseNativeType(T: typedesc): cstring = macro baseNativeType(T: typedesc): cstring =
@ -204,7 +209,7 @@ macro baseNativeType(T: typedesc): cstring =
if typeName == "NimGodotObject": if typeName == "NimGodotObject":
break break
t = getType(t[1][1]) t = getType(t[1][1])
if baseT.isNil: if baseT.len == 0:
result = newNilLit() result = newNilLit()
else: else:
let rStr = newNimNode(nnkRStrLit) let rStr = newNimNode(nnkRStrLit)
@ -332,9 +337,6 @@ proc `as`*[T: NimGodotObject](obj: NimGodotObject, t: typedesc[T]): T =
elif not obj.linkedObject.isNil and system.`of`(obj.linkedObject, T): elif not obj.linkedObject.isNil and system.`of`(obj.linkedObject, T):
result = T(obj.linkedObject) result = T(obj.linkedObject)
else: else:
when not defined(release):
printError("Failed to cast object to " &
T.name & "\n" & getStackTrace())
result = nil result = nil
proc `of`*[T1, T2: NimGodotObject](obj: T1, t: typedesc[T2]): bool {.inline.} = proc `of`*[T1, T2: NimGodotObject](obj: T1, t: typedesc[T2]): bool {.inline.} =
@ -345,26 +347,20 @@ proc newRStrLit(s: string): NimNode {.compileTime.} =
result = newNimNode(nnkRStrLit) result = newNimNode(nnkRStrLit)
result.strVal = s result.strVal = s
static: macro toGodotName(T: typedesc): untyped =
import strutils
macro toGodotName(T: typedesc): string =
var godotName: string
if T is GodotString or T is string: if T is GodotString or T is string:
godotName = "String" newStrLitNode"String"
elif T is SomeFloat: elif T is SomeFloat:
godotName = "float" newStrLitNode"float"
elif T is SomeUnsignedInt or T is SomeSignedInt: elif T is SomeUnsignedInt or T is SomeSignedInt:
godotName = "int" newStrLitNode"int"
if godotName.isNil or godotName.len == 0:
let nameStr = (($T.getType()[1][1].symbol).split(':')[0])
godotName = case nameStr:
of "File", "Directory", "Thread", "Mutex", "Semaphore":
"_" & nameStr
else: else:
nameStr let nameStr = ((T.getType()[1][1].strVal).split(':')[0])
case nameStr:
result = newLit(godotName) of "File", "Directory", "Thread", "Mutex", "Semaphore":
newStrLitNode("_" & nameStr)
else:
newStrLitNode(nameStr)
macro asCString(s: static[string]): cstring = macro asCString(s: static[string]): cstring =
result = newNimNode(nnkCallStrLit).add( result = newNimNode(nnkCallStrLit).add(
@ -474,14 +470,17 @@ proc setGodotObject*(nimObj: NimGodotObject, obj: ptr GodotObject) {.inline.} =
proc setNativeObject*(nimObj: NimGodotObject, proc setNativeObject*(nimObj: NimGodotObject,
nativeObj: NimGodotObject) {.inline.} = nativeObj: NimGodotObject) {.inline.} =
## Used from Godot constructor produced by ``gdobj`` macro. Do not call. ## Used from Godot constructor produced by ``gdobj`` macro. Do not call.
nimObj.linkedObject = nativeObj GC_ref(nativeObj)
nativeObj.linkedObject = nimObj nimObj.linkedObjectPtr = cast[pointer](nativeObj)
nativeObj.linkedObjectPtr = cast[pointer](nimObj)
nativeObj.isNative = true nativeObj.isNative = true
proc removeGodotObject*(nimObj: NimGodotObject) {.inline.} = proc removeGodotObject*(nimObj: NimGodotObject) {.inline.} =
## Used from Godot destructor produced by ``gdobj`` macro. Do not call. ## Used from Godot destructor produced by ``gdobj`` macro. Do not call.
GC_unref(nimObj.linkedObject)
nimObj.godotObject = nil nimObj.godotObject = nil
nimObj.linkedObject.godotObject = nil nimObj.linkedObject.godotObject = nil
nimObj.linkedObjectPtr = nil
proc `==`*(self, other: NimGodotObject): bool {.inline.} = proc `==`*(self, other: NimGodotObject): bool {.inline.} =
## Compares objects by referential equality. ## Compares objects by referential equality.
@ -613,7 +612,11 @@ proc fromVariant*[T: SomeSignedInt or SomeUnsignedInt](
else: uint64) else: uint64)
intVal = when T is SomeSignedInt: val.asInt() intVal = when T is SomeSignedInt: val.asInt()
else: val.asUint() else: val.asUint()
if intVal > high(T) or intVal < low(T): const highT = when T is SomeSignedInt: high(T).int64
else: high(T).uint64
const lowT = when T is SomeSignedInt: low(T).int64
else: low(T).uint64
if intVal > highT or intVal < lowT:
result = ConversionResult.RangeError result = ConversionResult.RangeError
else: else:
self = T(intVal) self = T(intVal)
@ -717,7 +720,10 @@ proc fromVariant*(s: var string, val: Variant): ConversionResult =
if val.getType() == VariantType.String: if val.getType() == VariantType.String:
s = val.asString() s = val.asString()
elif val.getType() == VariantType.Nil: elif val.getType() == VariantType.Nil:
when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
s = nil s = nil
else:
s = ""
else: else:
result = ConversionResult.TypeError result = ConversionResult.TypeError
@ -791,6 +797,27 @@ proc fromVariant*[T: array](s: var T, val: Variant): ConversionResult =
else: else:
result = ConversionResult.TypeError result = ConversionResult.TypeError
proc godotTypeInfo*[T](OptT: typedesc[Option[T]]): GodotTypeInfo =
when compiles(godotTypeInfo(T)):
result.variantType = godotTypeInfo(T)
else:
result.variantType = VariantType.Nil
proc toVariant*[T](option: Option[T]): Variant =
if option.isSome():
result = toVariant(option.unsafeGet())
else:
result = newVariant()
proc fromVariant*[T](option: var Option[T], val: Variant): ConversionResult =
if val.getType() == VariantType.Nil:
option = none(T)
else:
var v: T
result = fromVariant(v, val)
if result == ConversionResult.OK:
option = some(result)
proc godotTypeInfo*(T: typedesc[Table|TableRef|OrderedTable|OrderedTableRef]): GodotTypeInfo {.inline.} = proc godotTypeInfo*(T: typedesc[Table|TableRef|OrderedTable|OrderedTableRef]): GodotTypeInfo {.inline.} =
result.variantType = VariantType.Dictionary result.variantType = VariantType.Dictionary
@ -837,6 +864,7 @@ proc fromVariant*[T: Table or TableRef or OrderedTable or OrderedTableRef](t: va
else: else:
result = ConversionResult.TypeError result = ConversionResult.TypeError
when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
{.emit: """/*TYPESECTION*/ {.emit: """/*TYPESECTION*/
N_LIB_EXPORT N_CDECL(void, NimMain)(void); N_LIB_EXPORT N_CDECL(void, NimMain)(void);
N_NOINLINE(void, setStackBottom)(void* thestackbottom); N_NOINLINE(void, setStackBottom)(void* thestackbottom);
@ -853,10 +881,16 @@ proc godot_nativescript_init(handle: pointer) {.
nativeLibHandle = handle nativeLibHandle = handle
var stackBottom {.volatile.}: pointer var stackBottom {.volatile.}: pointer
stackBottom = addr(stackBottom)
{.emit: """ {.emit: """
NimMain(); NimMain();
""".}
when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
{.emit: """
setStackBottom((void*)(&`stackBottom`)); setStackBottom((void*)(&`stackBottom`));
""".} """.}
else:
nimGC_setStackBottom(stackBottom)
GC_fullCollect() GC_fullCollect()
GC_disable() GC_disable()
@ -867,6 +901,7 @@ proc godot_gdnative_init(options: ptr GDNativeInitOptions) {.
proc godot_gdnative_terminate(options: ptr GDNativeTerminateOptions) {. proc godot_gdnative_terminate(options: ptr GDNativeTerminateOptions) {.
cdecl, exportc, dynlib.} = cdecl, exportc, dynlib.} =
if not options[].inEditor or not compileOption("threads"):
deallocHeap(runFinalizers = not options[].inEditor, allowGcAfterwards = false) deallocHeap(runFinalizers = not options[].inEditor, allowGcAfterwards = false)
const nimGcStepLengthUs {.intdefine.} = 2000 const nimGcStepLengthUs {.intdefine.} = 2000
@ -891,9 +926,13 @@ proc registerFrameCallback*(cb: proc () {.closure.}) =
proc godot_nativescript_frame() {.cdecl, exportc, dynlib.} = proc godot_nativescript_frame() {.cdecl, exportc, dynlib.} =
var stackBottom {.volatile.}: pointer var stackBottom {.volatile.}: pointer
stackBottom = addr(stackBottom)
when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
{.emit: """ {.emit: """
setStackBottom((void*)(&`stackBottom`)); setStackBottom((void*)(&`stackBottom`));
""".} """.}
else:
nimGC_setStackBottom(stackBottom)
for cb in idleCallbacks: for cb in idleCallbacks:
cb() cb()
GC_step(nimGcStepLengthUs, true, 0) GC_step(nimGcStepLengthUs, true, 0)

View file

@ -1 +1,2 @@
--path:"$projectdir/../" --path:"$projectdir/../"
-d:useRealtimeGc