Compare commits

..

50 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
Ruslan Mustakov
859f9f04fb OrderedTable to Variant conversion support 2018-09-21 16:34:09 +07:00
Evgeny Zuev
ceaf66a34c Make classRegistry use hashes instead of strings as keys for faster lookup
Up version to 0.7.16
2018-08-29 13:44:37 +07:00
Ruslan Mustakov
fd5f77e7c2 Fix gdobj to properly handle var block 2018-08-14 17:59:24 +07:00
Evgeny Zuev
8d68051f23 Fix system.of being preferred over godot.of in some cases
Fix `as` fails when argument `obj` is not convertible to `T`
Up version to 0.7.14
2018-06-21 17:53:01 +07:00
Ruslan Mustakov
13f5aba3fe Up version to 0.7.13 2018-06-04 17:26:26 +07:00
Ruslan Mustakov
b3ad6134d9 Fix doc generation 2018-06-04 16:24:52 +07:00
Ruslan Mustakov
1e8ccfea2b Fix handling of Error as an argument in Godot API 2018-06-04 14:28:14 +07:00
Ruslan Mustakov
9e61030817 Up version to 0.7.12 2018-06-04 11:50:37 +07:00
Ruslan Mustakov
66c939b9e6 Fix for latest Nim
Closes #23.
2018-06-04 11:50:37 +07:00
Ruslan Mustakov
76de026b4f Implement hash proc for Godot types 2018-06-04 11:50:37 +07:00
Ruslan Mustakov
4eb771e9be Support all the default values 2018-06-04 11:50:37 +07:00
Ruslan Mustakov
2dd0130c78 Avoid name clashes between properties and methods
Fixes #19.
2018-06-04 11:50:37 +07:00
Ruslan Mustakov
651c2d823c Handle nil object references properly
Fixes #26.
2018-06-04 11:50:37 +07:00
Ruslan Mustakov
8b1ac6d835 Fix compilation with C++ backend. Fixes #25. 2018-06-04 11:50:37 +07:00
Jon Renner
21ca9a088b export Vector2 normalize proc 2018-05-19 14:30:02 +07:00
Ruslan Mustakov
96dfc7de90 Fix for latest Nim 2018-05-16 15:06:57 +07:00
Ruslan Mustakov
a1d1481967 Add a remark to thread enter warning 2018-05-14 21:15:11 +07:00
Ruslan Mustakov
6e014bbc01 Make godotapigen use getter return type for property types
Fixes #20.
2018-04-24 11:12:49 +07:00
Ruslan Mustakov
dc6ebaf575 Fix GDNative API version check
Fixes #18.
2018-03-31 17:45:50 +07:00
Ruslan Mustakov
be6f01e3b7 More pool array features: subarray, mitems, mpairs 2018-02-22 18:55:52 +07:00
Ruslan Mustakov
d11856377e Implement Vector2 and Rect2 procs
This allows compiler to inline/optimize them, which cannot be done if
these procs are invoked via GDNative API.
2018-02-17 23:44:07 +07:00
Ruslan Mustakov
0aab6e17ef Update license year and fix doc to have Godot 3.0 download URL 2018-01-31 20:52:15 +07:00
Ruslan Mustakov
5ccf351b5a Fix Variant export 2018-01-31 20:30:13 +07:00
Ruslan Mustakov
f05eb090f7 Update after GDNative API changes 2018-01-25 17:52:58 +07:00
Ruslan Mustakov
e3216f09d0 Update ref types not to be var in parameters 2018-01-25 17:39:01 +07:00
40 changed files with 2243 additions and 1082 deletions

View file

@ -9,7 +9,7 @@
"godot/godotapigen.nim"], "godot/godotapigen.nim"],
"nim.buildOnSave": false, "nim.buildOnSave": false,
"nim.lintOnSave": true, "nim.lintOnSave": true,
"nim.licenseString": "# Copyright 2017 Xored Software, Inc.\n\n", "nim.licenseString": "# Copyright 2018 Xored Software, Inc.\n\n",
"files.exclude": { "files.exclude": {
"**/nimcache/**": true "**/nimcache/**": true
} }

View file

@ -2,7 +2,7 @@ godot-nim - Nim bindings for Godot Engine
The MIT License The MIT License
Copyright (c) 2017 Xored Software Inc. Copyright (c) 2018 Xored Software Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction, associated documentation files (the "Software"), to deal in the Software without restriction,

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/
@ -13,4 +13,4 @@ Documentation: https://pragmagic.github.io/godot-nim/
This project is licensed under the MIT license. Read [LICENSE](LICENSE) file for details. This project is licensed under the MIT license. Read [LICENSE](LICENSE) file for details.
Copyright (c) 2017 Xored Software, Inc. Copyright (c) 2018 Xored Software, Inc.

View file

@ -1,4 +1,4 @@
# Copyright 2017 Xored Software, Inc. # Copyright 2018 Xored Software, Inc.
import threadpool, os, osproc, strutils, sequtils, pegs import threadpool, os, osproc, strutils, sequtils, pegs
@ -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) =
@ -104,14 +104,15 @@ proc buildDocs*(outDir, godotNimDir, godotBin: string) =
createDir(godotApiFolder) createDir(godotApiFolder)
genApiFiles(godotApiFolder, godotBinAbs) genApiFiles(godotApiFolder, godotBinAbs)
for file in walkDirRec(godotApiFolder, {pcFile, pcDir}, [".nim"]): for file in walkDirRec(godotApiFolder, {pcFile, pcDir}, [".nim"]):
spawn execOrFail("nim doc -d:useRealtimeGc --path:godot " & quoted(file)) spawn execOrFail("nim doc -d:useRealtimeGc --path:godot -o:" &
quoted(outName(godotApiFolder, file)) & ' ' & quoted(file))
sync() sync()
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 @@
# Copyright 2017 Xored Software, Inc. # Copyright 2018 Xored Software, Inc.
import os, pegs, strutils import os, pegs, strutils
import docbuild import docbuild

View file

@ -5,6 +5,7 @@ Nim bindings for Godot Engine
:Author: Ruslan Mustakov :Author: Ruslan Mustakov
:Version: |godotnimversion| :Version: |godotnimversion|
:GitHub: `$GODOTNIM_GITHUB_URL <$GODOTNIM_GITHUB_URL>`_ :GitHub: `$GODOTNIM_GITHUB_URL <$GODOTNIM_GITHUB_URL>`_
:License: MIT
.. contents:: .. contents::
@ -32,25 +33,11 @@ which adds features for editing GDScript and Godot resource files.
Getting Started Getting Started
=============== ===============
Building Godot Getting Godot
-------------- --------------
The library requires a not yet released Godot version 3.0, which you can The library requires Godot version 3.0, which you can get here:
build yourself by running the commands below (requires https://godotengine.org/download
`Git <https://git-scm.com/downloads>`_,
`Python 2.7 <https://www.python.org/downloads/>`_,
`SCons <http://www.scons.org/>`_):
.. code-block:: bash
git clone https://github.com/godotengine/godot.git
cd godot
scons platform=<your_platform>
where ``<your_platform>`` can be ``windows``, ``osx``, ``x11``. After build
is finished, Godot binaries will be under the ``bin`` folder. More details
about compiling Godot can be found in `Godot documentation
<https://godot.readthedocs.io/en/stable/development/compiling/index.html>`_.
Installing Nim Installing Nim
------------- -------------
@ -63,7 +50,7 @@ Make sure you also have ``nimble`` (Nim's package manager) installed.
Creating Project Creating Project
---------------- ----------------
The fastest way to set up a Godot-Nim project is to use an existing stub: The fastest way to set up a Godot-Nim project is to use the existing stub:
.. code-block:: bash .. code-block:: bash
git clone --depth=1 https://github.com/pragmagic/godot-nim-stub.git myproject git clone --depth=1 https://github.com/pragmagic/godot-nim-stub.git myproject
@ -88,7 +75,7 @@ If you would like to use Nim in an existing project:
build scripts (``nakefile.nim``, ``src/stub.nimble``) according to your build scripts (``nakefile.nim``, ``src/stub.nimble``) according to your
own project structure. own project structure.
2. Copy ``project/nimlib.tres`` to your Godot project folder. It is a 2. Copy ``nimlib.gdnlib`` to your Godot project folder. It is a
GDNative library resource that contains paths to dynamic libraries GDNative library resource that contains paths to dynamic libraries
compiled by Nim. compiled by Nim.

View file

@ -1,4 +1,4 @@
version = "0.7.3" 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

@ -1,6 +1,9 @@
# Copyright (c) 2017 Xored Software, Inc. # Copyright (c) 2018 Xored Software, Inc.
import internal.godotinternaltypes, internal.godotstrings import hashes
import vector3
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.} =
@ -9,6 +12,9 @@ proc initAABB*(pos, size: Vector3): AABB {.inline.} =
proc `$`*(self: AABB): string {.inline.} = proc `$`*(self: AABB): string {.inline.} =
$getGDNativeAPI().aabbAsString(self) $getGDNativeAPI().aabbAsString(self)
proc hash*(self: AABB): Hash {.inline.} =
!$(self.position.hash() !& self.size.hash())
proc area*(self: AABB): float32 {.inline.} = proc area*(self: AABB): float32 {.inline.} =
getGDNativeAPI().aabbGetArea(self) getGDNativeAPI().aabbGetArea(self)
@ -25,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)
@ -40,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)
@ -52,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)
@ -61,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 2017 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
@ -62,16 +62,16 @@ proc newArray*(pba: PoolByteArray): Array {.inline.} =
new(result, arrayFinalizer) new(result, arrayFinalizer)
initGodotArray(result.godotArray, pba.godotPoolByteArray[]) initGodotArray(result.godotArray, pba.godotPoolByteArray[])
proc `[]=`*(self: var Array; idx: int; value: Variant) {.inline.} = proc `[]=`*(self: Array; idx: int; value: Variant) {.inline.} =
self.godotArray[idx.cint] = value.godotVariant[] self.godotArray[idx.cint] = value.godotVariant[]
proc `[]`*(self: Array; idx: int): Variant {.inline.} = proc `[]`*(self: Array; idx: int): Variant {.inline.} =
newVariant(self.godotArray[idx.cint]) newVariant(self.godotArray[idx.cint])
proc add*(self: var Array; value: Variant) {.inline.} = proc add*(self: Array; value: Variant) {.inline.} =
self.godotArray.add(value.godotVariant[]) self.godotArray.add(value.godotVariant[])
proc clear*(self: var Array) {.inline.} = proc clear*(self: Array) {.inline.} =
self.godotArray.clear() self.godotArray.clear()
proc count*(self: Array; value: Variant): int {.inline.} = proc count*(self: Array; value: Variant): int {.inline.} =
@ -80,7 +80,7 @@ proc count*(self: Array; value: Variant): int {.inline.} =
proc isEmpty*(self: Array): bool {.inline.} = proc isEmpty*(self: Array): bool {.inline.} =
self.godotArray.isEmpty() self.godotArray.isEmpty()
proc erase*(self: var Array; value: Variant) {.inline.} = proc erase*(self: Array; value: Variant) {.inline.} =
self.godotArray.erase(value.godotVariant[]) self.godotArray.erase(value.godotVariant[])
proc first*(self: Array): Variant {.inline.} = proc first*(self: Array): Variant {.inline.} =
@ -101,28 +101,28 @@ proc contains*(self: Array; value: Variant): bool {.inline.} =
proc hash*(self: Array): Hash {.inline.} = proc hash*(self: Array): Hash {.inline.} =
hash(self.godotArray.godotHash()) hash(self.godotArray.godotHash())
proc insert*(self: var Array; pos: int; value: Variant) {.inline.} = proc insert*(self: Array; pos: int; value: Variant) {.inline.} =
self.godotArray.insert(pos.cint, value.godotVariant[]) self.godotArray.insert(pos.cint, value.godotVariant[])
proc reverse*(self: var Array) {.inline.} = proc reverse*(self: Array) {.inline.} =
self.godotArray.reverse() self.godotArray.reverse()
proc popLast*(self: var Array): Variant {.inline.} = proc popLast*(self: Array): Variant {.inline.} =
newVariant(self.godotArray.popLast()) newVariant(self.godotArray.popLast())
proc popFirst*(self: var Array): Variant {.inline.} = proc popFirst*(self: Array): Variant {.inline.} =
newVariant(self.godotArray.popFirst()) newVariant(self.godotArray.popFirst())
proc addLast*(self: var Array; value: Variant) {.inline.} = proc addLast*(self: Array; value: Variant) {.inline.} =
self.godotArray.addLast(value.godotVariant[]) self.godotArray.addLast(value.godotVariant[])
proc addFirst*(self: var Array; value: Variant) {.inline.} = proc addFirst*(self: Array; value: Variant) {.inline.} =
self.godotArray.addFirst(value.godotVariant[]) self.godotArray.addFirst(value.godotVariant[])
proc delete*(self: var Array; idx: int) {.inline.} = proc delete*(self: Array; idx: int) {.inline.} =
self.godotArray.delete(idx.cint) self.godotArray.delete(idx.cint)
proc setLen*(self: var Array; size: int) {.inline.} = proc setLen*(self: Array; size: int) {.inline.} =
self.godotArray.setLen(size.cint) self.godotArray.setLen(size.cint)
proc rfind*(self: Array; what: Variant; fromIdx: int): int {.inline.} = proc rfind*(self: Array; what: Variant; fromIdx: int): int {.inline.} =
@ -131,7 +131,7 @@ proc rfind*(self: Array; what: Variant; fromIdx: int): int {.inline.} =
proc len*(self: Array): int {.inline.} = proc len*(self: Array): int {.inline.} =
self.godotArray.len.int self.godotArray.len.int
proc sort*(self: var Array) {.inline.} = proc sort*(self: Array) {.inline.} =
self.godotArray.sort() self.godotArray.sort()
iterator items*(self: Array): Variant = iterator items*(self: Array): Variant =

View file

@ -1,9 +1,12 @@
# Copyright (c) 2017 Xored Software, Inc. # Copyright (c) 2018 Xored Software, Inc.
import math, hashes
import math
import godotbase, vector3, quats import godotbase, vector3, quats
import godotcoretypes import godotcoretypes
{.push stackTrace: off.}
proc setCells*(basis: var Basis, xx, xy, xz, yx, yy, yz, zx, zy, zz: float32) = proc setCells*(basis: var Basis, xx, xy, xz, yx, yy, yz, zx, zy, zz: float32) =
basis.elements[0].x = xx basis.elements[0].x = xx
basis.elements[0].y = xy basis.elements[0].y = xy
@ -199,6 +202,9 @@ proc `$`*(self: Basis): string {.inline.} =
result.add(", ") result.add(", ")
result.add($self[i][j]) result.add($self[i][j])
proc hash*(self: Basis): Hash {.inline.} =
!$(self.elements[0].hash() !& self.elements[1].hash() !& self.elements[2].hash())
template cofac(row1, col1, row2, col2: int): float32 = template cofac(row1, col1, row2, col2: int): float32 =
self.elements[row1][col1] * self.elements[row2][col2] - self.elements[row1][col1] * self.elements[row2][col2] -
self.elements[row1][col2] * self.elements[row2][col1] self.elements[row1][col2] * self.elements[row2][col1]
@ -449,3 +455,5 @@ proc rotate*(self: var Vector3; axis: Vector3; phi: float32) =
proc rotated*(self: Vector3; axis: Vector3; phi: float32): Vector3 = proc rotated*(self: Vector3; axis: Vector3; phi: float32): Vector3 =
result = self result = self
result.rotate(axis, phi) result.rotate(axis, phi)
{.pop.} # stackTrace: off

View file

@ -1,4 +1,6 @@
# Copyright (c) 2017 Xored Software, Inc. # Copyright (c) 2018 Xored Software, Inc.
import hashes
import godotcoretypes, gdnativeapi import godotcoretypes, gdnativeapi
@ -33,6 +35,9 @@ proc `$`*(self: Color): string {.inline.} =
result.add(", ") result.add(", ")
result.add($self.a) result.add($self.a)
proc hash*(self: Color): Hash {.inline.} =
!$(self.r.hash() !& self.g.hash() !& self.b.hash() !& self.a.hash())
proc toHex(val: float32, target: var string, targetIdx: int) = proc toHex(val: float32, target: var string, targetIdx: int) =
let val = clamp(int(val * 255), 0, 255) let val = clamp(int(val * 255), 0, 255)
let nums = [(val and 0xF0) shr 4, val and 0xF] let nums = [(val and 0xF0) shr 4, val and 0xF]
@ -59,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 2017 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
@ -30,9 +30,12 @@ proc len*(self: Dictionary): int {.inline.} =
proc isEmpty*(self: Dictionary): bool {.inline.} = proc isEmpty*(self: Dictionary): bool {.inline.} =
self.godotDictionary.isEmpty() self.godotDictionary.isEmpty()
proc clear*(self: var Dictionary) {.inline.} = proc clear*(self: Dictionary) {.inline.} =
self.godotDictionary.clear() self.godotDictionary.clear()
proc hash*(self: Dictionary): Hash {.inline.} =
hash(self.godotDictionary.godotHash())
import variants, arrays import variants, arrays
proc newVariant*(dict: Dictionary): Variant {.inline.} = proc newVariant*(dict: Dictionary): Variant {.inline.} =
@ -40,7 +43,7 @@ proc newVariant*(dict: Dictionary): Variant {.inline.} =
initGodotVariant(result.godotVariant[], dict.godotDictionary) initGodotVariant(result.godotVariant[], dict.godotDictionary)
proc asDictionary*(self: Variant): Dictionary {.inline.} = proc asDictionary*(self: Variant): Dictionary {.inline.} =
newDictionary(self.godotVariant[].asGodotDictionary) newDictionary(self.godotVariant[].asGodotDictionary())
proc contains*(self: Dictionary; key: Variant): bool {.inline.}= proc contains*(self: Dictionary; key: Variant): bool {.inline.}=
self.godotDictionary.contains(key.godotVariant[]) self.godotDictionary.contains(key.godotVariant[])
@ -48,12 +51,9 @@ proc contains*(self: Dictionary; key: Variant): bool {.inline.}=
proc contains*(self: Dictionary; keys: Array): bool {.inline.} = proc contains*(self: Dictionary; keys: Array): bool {.inline.} =
self.godotDictionary.contains(keys.godotArray[]) self.godotDictionary.contains(keys.godotArray[])
proc del*(self: var Dictionary; key: Variant) {.inline.} = proc del*(self: Dictionary; key: Variant) {.inline.} =
self.godotDictionary.del(key.godotVariant[]) self.godotDictionary.del(key.godotVariant[])
proc hash*(self: Dictionary): Hash {.inline.} =
hash(self.godotDictionary.godotHash())
proc keys*(self: Dictionary): Array {.inline.} = proc keys*(self: Dictionary): Array {.inline.} =
newArray(self.godotDictionary.keys()) newArray(self.godotDictionary.keys())
@ -71,7 +71,7 @@ proc `[]`*(self: Dictionary; keyStr: string): Variant {.inline.} =
godotStr.deinit() godotStr.deinit()
godotVariant.deinit() godotVariant.deinit()
proc `[]=`*(self: var Dictionary; key, value: Variant) {.inline.} = proc `[]=`*(self: Dictionary; key, value: Variant) {.inline.} =
self.godotDictionary[key.godotVariant[]] = value.godotVariant[] self.godotDictionary[key.godotVariant[]] = value.godotVariant[]
proc `==`*(self, other: Dictionary): bool {.inline.} = proc `==`*(self, other: Dictionary): bool {.inline.} =

View file

@ -1,30 +1,64 @@
# Copyright (c) 2017 Xored Software, Inc. # Copyright (c) 2018 Xored Software, Inc.
import math import math, godotinternal
# math helpers # math helpers
{.push stackTrace: off.}
const EPSILON = 0.00001'f32 const EPSILON = 0.00001'f32
proc isEqualApprox*(a, b: float32): bool {.inline.} = proc isEqualApprox*(a, b: float32): bool {.inline, noinit.} =
abs(a - b) < EPSILON abs(a - b) < EPSILON
proc isEqualApprox*(a, b: float64): bool {.inline.} = proc isEqualApprox*(a, b: float64): bool {.inline, noinit.} =
abs(a - b) < EPSILON abs(a - b) < EPSILON
proc sign*(a: float32): float32 {.inline.} = proc sign*(a: float32): float32 {.inline, noinit.} =
if a < 0: -1.0'f32 else: 1.0'f32 if a < 0: -1.0'f32 else: 1.0'f32
proc sign*(a: float64): float64 {.inline.} = proc sign*(a: float64): float64 {.inline, noinit.} =
if a < 0: -1.0'f64 else: 1.0'f64 if a < 0: -1.0'f64 else: 1.0'f64
proc stepify*(value, step: float64): float64 = proc stepify*(value, step: float64): float64 {.inline, noinit.} =
if step != 0'f64: if step != 0'f64:
floor(value / step + 0.5'f64) * step floor(value / step + 0.5'f64) * step
else: else:
value value
proc stepify*(value, step: float32): float32 = proc stepify*(value, step: float32): float32 {.inline, noinit.} =
if step != 0'f32: if step != 0'f32:
floor(value / step + 0.5'f32) * step floor(value / step + 0.5'f32) * step
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.} =
if x <= y: x else: y
proc abs*(x: float32): float32 {.inline, noinit.} =
if x < 0.0: -x else: x
proc max*(x, y: float32): float32 {.inline, noinit.} =
if y <= x: x else: y
{.pop.} # stackTrace: off
template printWarning*(warning: typed) =
## Prints ``warning`` to Godot log, adding filename and line information.
let instInfo = instantiationInfo()
godotPrintWarning(cstring($warning), cstring"", cstring(instInfo.filename), instInfo.line.cint)
template printError*(error: typed) =
## Prints ``error`` to Godot log, adding filename and line information.
let instInfo = instantiationInfo()
godotPrintError(cstring($error), cstring"", cstring(instInfo.filename), instInfo.line.cint)
proc print*(parts: varargs[string, `$`]) =
## Prints concatenated ``parts`` to Godot log.
var combined = ""
for v in parts:
combined.add(v)
var s = combined.toGodotString()
godotPrint(s)
s.deinit()

View file

@ -1,4 +1,4 @@
# Copyright 2017 Xored Software, Inc. # Copyright 2018 Xored Software, Inc.
type type
Color* {.byref.} = object Color* {.byref.} = object

View file

@ -1,7 +1,9 @@
# Copyright 2017 Xored Software, Inc. # Copyright 2018 Xored Software, Inc.
import internal.godotinternaltypes, internal.godotnodepaths, import hashes
internal.godotstrings
import internal/godotinternaltypes, internal/godotnodepaths,
internal/godotstrings
type type
NodePath* = ref object NodePath* = ref object
@ -32,6 +34,9 @@ proc `$`*(self: NodePath): string {.inline.} =
result = $s result = $s
s.deinit() s.deinit()
proc hash*(self: NodePath): Hash {.inline.} =
($self).hash()
proc isAbsolute*(self: NodePath): bool {.inline.} = proc isAbsolute*(self: NodePath): bool {.inline.} =
self.path.isAbsolute() self.path.isAbsolute()

View file

@ -1,8 +1,10 @@
# Copyright (c) 2017 Xored Software, Inc. # Copyright (c) 2018 Xored Software, Inc.
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.} =
@ -20,14 +22,17 @@ proc initPlane*(normal: Vector3; d: float32): Plane {.inline.} =
proc `$`*(self: Plane): string {.inline.} = proc `$`*(self: Plane): string {.inline.} =
$getGDNativeAPI().planeAsString(self) $getGDNativeAPI().planeAsString(self)
proc hash*(self: Plane): Hash {.inline, noinit.} =
!$(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)
@ -40,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.} =
@ -55,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

@ -1,8 +1,11 @@
# Copyright 2017 Xored Software, Inc. # Copyright 2018 Xored Software, Inc.
import hashes
import godotcoretypes import godotcoretypes
import internal.godotinternaltypes, internal.godotpoolarrays, import internal/godotinternaltypes, internal/godotpoolarrays,
internal.godotstrings internal/godotstrings
import vector2, vector3, colors
template definePoolArrayBase(T, GodotT, DataT, fieldName, newProcName, template definePoolArrayBase(T, GodotT, DataT, fieldName, newProcName,
initProcName) = initProcName) =
@ -26,48 +29,11 @@ template definePoolArrayBase(T, GodotT, DataT, fieldName, newProcName,
new(result, poolArrayFinalizer) new(result, poolArrayFinalizer)
result.fieldName = arr result.fieldName = arr
template definePoolArray(T, GodotT, DataT, fieldName, newProcName, initProcName; proc hash*(arr: T): Hash =
noData = false) = for item in arr.fieldName.items():
result = result !&
proc newProcName*(arr: Array): T {.inline.} = (when type(item) is GodotString: ($item).hash() else: item.hash())
new(result, poolArrayFinalizer) result = !$result
initProcName(result.fieldName, arr.godotArray[])
proc add*(self: var T; arr: T) {.inline.} =
self.fieldName.add(arr.fieldName)
proc delete*(self: var T; idx: int) {.inline.} =
self.fieldName.delete(idx.cint)
proc reverse*(self: var T) {.inline.} =
self.fieldName.reverse()
proc setLen*(self: var T; size: int) {.inline.} =
self.fieldName.setLen(size.cint)
proc len*(self: T): int {.inline.} =
self.fieldName.len.int
when not noData:
proc add*(self: var T; data: DataT) {.inline.} =
self.fieldName.add(data)
proc insert*(self: var T; idx: int; data: DataT): Error {.inline.} =
self.fieldName.insert(idx.cint, data)
proc `[]=`*(self: var T; idx: int; data: DataT) {.inline.} =
self.fieldName[idx.cint] = data
proc `[]`*(self: T; idx: int): DataT {.inline.} =
self.fieldName[idx.cint]
iterator items*(arr: T): DataT =
for i in 0..<arr.len:
yield arr[i]
iterator pairs*(arr: T): tuple[key: int, val: DataT] =
for i in 0..<arr.len:
yield (i, arr[i])
definePoolArrayBase(PoolByteArray, GodotPoolByteArray, uint8, definePoolArrayBase(PoolByteArray, GodotPoolByteArray, uint8,
godotPoolByteArray, newPoolByteArray, godotPoolByteArray, newPoolByteArray,
@ -75,7 +41,7 @@ definePoolArrayBase(PoolByteArray, GodotPoolByteArray, uint8,
definePoolArrayBase(PoolIntArray, GodotPoolIntArray, cint, definePoolArrayBase(PoolIntArray, GodotPoolIntArray, cint,
godotPoolIntArray, newPoolIntArray, godotPoolIntArray, newPoolIntArray,
initGodotPoolIntArray) initGodotPoolIntArray)
definePoolArrayBase(PoolRealArray, GodotPoolRealArray, float64, definePoolArrayBase(PoolRealArray, GodotPoolRealArray, float32,
godotPoolRealArray, newPoolRealArray, godotPoolRealArray, newPoolRealArray,
initGodotPoolRealArray) initGodotPoolRealArray)
definePoolArrayBase(PoolVector2Array, GodotPoolVector2Array, Vector2, definePoolArrayBase(PoolVector2Array, GodotPoolVector2Array, Vector2,
@ -93,13 +59,70 @@ definePoolArrayBase(PoolStringArray, GodotPoolStringArray, string,
import arrays import arrays
template definePoolArray(T, GodotT, DataT, fieldName, newProcName, initProcName;
noData = false) =
proc newProcName*(arr: Array): T {.inline.} =
new(result, poolArrayFinalizer)
initProcName(result.fieldName, arr.godotArray[])
proc add*(self: T; arr: T) {.inline.} =
self.fieldName.add(arr.fieldName)
proc delete*(self: T; idx: int) {.inline.} =
self.fieldName.delete(idx.cint)
proc reverse*(self: T) {.inline.} =
self.fieldName.reverse()
proc setLen*(self: T; size: int) {.inline.} =
self.fieldName.setLen(size.cint)
proc len*(self: T): int {.inline.} =
self.fieldName.len.int
proc subarray*(self: T, idxFrom, idxTo: int): T {.inline.} =
## Indexes are inclusive, negative values count from the end of the array.
assert(idxFrom >= low(cint) and idxFrom <= high(cint) and
idxTo >= low(cint) and idxTo <= high(cint))
newProcName(self.fieldName.subarray(idxFrom.cint, idxTo.cint))
when not noData:
proc add*(self: T; data: DataT) {.inline.} =
self.fieldName.add(data)
proc insert*(self: T; idx: int; data: DataT): Error {.inline.} =
self.fieldName.insert(idx.cint, data)
proc `[]=`*(self: T; idx: int; data: DataT) {.inline.} =
self.fieldName[idx.cint] = data
proc `[]`*(self: T; idx: int): DataT {.inline.} =
self.fieldName[idx.cint]
iterator items*(arr: T): DataT =
for item in arr.fieldName.items:
yield item
iterator pairs*(arr: T): tuple[key: int, val: DataT] =
for pair in arr.fieldName.pairs:
yield (pair[0].int, pair[1])
iterator mitems*(arr: T): var DataT =
for item in arr.fieldName.mitems:
yield item
iterator mpairs*(arr: T): tuple[key: int, val: var DataT] =
for pair in arr.fieldName.mpairs:
yield (pair[0].int, pair[1])
definePoolArray(PoolByteArray, GodotPoolByteArray, uint8, definePoolArray(PoolByteArray, GodotPoolByteArray, uint8,
godotPoolByteArray, newPoolByteArray, godotPoolByteArray, newPoolByteArray,
initGodotPoolByteArray) initGodotPoolByteArray)
definePoolArray(PoolIntArray, GodotPoolIntArray, cint, definePoolArray(PoolIntArray, GodotPoolIntArray, cint,
godotPoolIntArray, newPoolIntArray, godotPoolIntArray, newPoolIntArray,
initGodotPoolIntArray) initGodotPoolIntArray)
definePoolArray(PoolRealArray, GodotPoolRealArray, float64, definePoolArray(PoolRealArray, GodotPoolRealArray, float32,
godotPoolRealArray, newPoolRealArray, godotPoolRealArray, newPoolRealArray,
initGodotPoolRealArray) initGodotPoolRealArray)
definePoolArray(PoolVector2Array, GodotPoolVector2Array, Vector2, definePoolArray(PoolVector2Array, GodotPoolVector2Array, Vector2,
@ -115,17 +138,17 @@ definePoolArray(PoolStringArray, GodotPoolStringArray, string,
godotPoolStringArray, newPoolStringArray, godotPoolStringArray, newPoolStringArray,
initGodotPoolStringArray, true) initGodotPoolStringArray, true)
proc add*(self: var PoolStringArray; data: string) = proc add*(self: PoolStringArray; data: string) =
var s = data.toGodotString() var s = data.toGodotString()
self.godotPoolStringArray.add(s) self.godotPoolStringArray.add(s)
s.deinit() s.deinit()
proc insert*(self: var PoolStringArray; idx: int; data: string): Error = proc insert*(self: PoolStringArray; idx: int; data: string): Error =
var s = data.toGodotString() var s = data.toGodotString()
result = self.godotPoolStringArray.insert(idx.cint, s) result = self.godotPoolStringArray.insert(idx.cint, s)
s.deinit() s.deinit()
proc `[]=`*(self: var PoolStringArray; idx: int; data: string) = proc `[]=`*(self: PoolStringArray; idx: int; data: string) =
var s = data.toGodotString() var s = data.toGodotString()
self.godotPoolStringArray[idx.cint] = s self.godotPoolStringArray[idx.cint] = s
s.deinit() s.deinit()

View file

@ -1,6 +1,8 @@
# Copyright (c) 2017 Xored Software, Inc. # Copyright (c) 2018 Xored Software, Inc.
import internal.godotinternaltypes, internal.godotstrings import hashes
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.} =
@ -17,6 +19,9 @@ proc initQuat*(axis: Vector3; angle: float32): Quat {.inline.} =
proc `$`*(self: Quat): string {.inline.} = proc `$`*(self: Quat): string {.inline.} =
$getGDNativeAPI().quatAsString(self) $getGDNativeAPI().quatAsString(self)
proc hash*(self: Quat): Hash {.inline.} =
!$(self.x.hash() !& self.y.hash() !& self.z.hash() !& self.w.hash())
proc length*(self: Quat): float32 {.inline.} = proc length*(self: Quat): float32 {.inline.} =
getGDNativeAPI().quatLength(self) getGDNativeAPI().quatLength(self)
@ -24,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
@ -76,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

@ -1,44 +1,153 @@
# Copyright (c) 2017 Xored Software, Inc. # Copyright (c) 2018 Xored Software, Inc.
import hashes
import vector2 import vector2
import internal.godotinternaltypes, internal.godotstrings import internal/godotinternaltypes, internal/godotstrings
import godotcoretypes, gdnativeapi import godotcoretypes, gdnativeapi
proc initRect2*(pos, size: Vector2): Rect2 {.inline.} = {.push stackTrace: off.}
proc initRect2*(): Rect2 {.inline, noinit.} =
Rect2()
proc initRect2*(pos, size: Vector2): Rect2 {.inline, noinit.} =
Rect2(position: pos, size: size) Rect2(position: pos, size: size)
proc initRect2*(x, y, sizeX, sizeY: float32): Rect2 {.inline.} = proc initRect2*(x, y, sizeX, sizeY: float32): Rect2 {.inline, noinit.} =
Rect2(position: vec2(x, y), size: vec2(sizeX, sizeY)) Rect2(position: vec2(x, y), size: vec2(sizeX, sizeY))
proc `$`*(self: Rect2): string {.inline.} = proc `$`*(self: Rect2): string {.inline, noinit.} =
$getGDNativeAPI().rect2AsString(self) $getGDNativeAPI().rect2AsString(self)
proc area*(self: Rect2): float32 {.inline.} = proc hash*(self: Rect2): Hash {.inline, noinit.} =
getGDNativeAPI().rect2GetArea(self) !$(self.position.hash() !& self.size.hash())
proc intersects*(a, b: Rect2): bool {.inline.} = proc area*(self: Rect2): float32 {.inline, noinit.} =
getGDNativeAPI().rect2Intersects(a, b) self.size.x * self.size.y
proc encloses*(a, b: Rect2): bool {.inline.} = proc intersects*(a, b: Rect2): bool {.inline, noinit.} =
getGDNativeAPI().rect2Encloses(a, b) if a.position.x >= (b.position.x + b.size.x):
return false
if a.position.x + a.size.x <= b.position.x:
return false
if a.position.y >= (b.position.y + b.size.y):
return false
if a.position.y + a.size.y <= b.position.y:
return false
result = true
proc hasNoArea*(self: Rect2): bool {.inline.} = proc distanceTo*(self: Rect2, p: Vector2): float32 {.noinit.} =
getGDNativeAPI().rect2HasNoArea(self) var inside = true
if p.x < self.position.x:
let d = self.position.x - p.x
result = d
inside = false
if p.y < self.position.y:
let d = self.position.y - p.y
result = if inside: d else: min(result, d)
inside = false
if p.x >= (self.position.x + self.size.x):
let d = p.x - (self.position.x + self.size.x)
result = if inside: d else: min(result, d)
inside = false
if p.y >= (self.position.y + self.size.y):
let d = p.y - (self.position.y + self.size.y)
result = if inside: d else: min(result, d)
inside = false
proc clip*(self, b: Rect2): Rect2 {.inline.} = if inside:
getGDNativeAPI().rect2Clip(self, b) result = 0'f32
proc merge*(self, b: Rect2): Rect2 {.inline.} = proc encloses*(a, b: Rect2): bool {.inline, noinit.} =
getGDNativeAPI().rect2Merge(self, b) b.position.x >= a.position.x and b.position.y >= a.position.y and
(b.position.x + b.size.x) < (a.position.x + a.size.x) and
(b.position.y + b.size.y) < (a.position.y + a.size.y)
proc contains*(self: Rect2; point: Vector2): bool {.inline.} = proc hasNoArea*(self: Rect2): bool {.inline, noinit.} =
getGDNativeAPI().rect2HasPoint(self, point) self.size.x <= 0 or self.size.y <= 0
proc grow*(self: Rect2; by: float32): Rect2 {.inline.} = proc clip*(self, b: Rect2): Rect2 {.inline, noinit.} =
getGDNativeAPI().rect2Grow(self, by) if not self.intersects(b):
return initRect2()
proc expand*(self: Rect2; to: Vector2): Rect2 {.inline.} = result = self
getGDNativeAPI().rect2Expand(self, to)
proc `==`*(a, b: Rect2): bool {.inline.} = result.position.x = max(b.position.x, self.position.x)
getGDNativeAPI().rect2OperatorEqual(a, b) result.position.y = max(b.position.y, self.position.y)
let bEnd = b.position + b.size
let selfEnd = self.position + self.size
result.size.x = min(bEnd.x, selfEnd.x) - result.position.x
result.size.y = min(bEnd.y, selfEnd.y) - result.position.y
proc merge*(self, b: Rect2): Rect2 {.inline, noinit.} =
result.position.x = min(b.position.x, self.position.x)
result.position.y = min(b.position.y, self.position.y)
result.size.x = max(b.position.x + b.size.x, self.position.x + self.size.x)
result.size.y = max(b.position.y + b.size.y, self.position.y + self.size.y)
result.size -= result.position
proc contains*(self: Rect2; point: Vector2): bool {.inline, noinit.} =
if point.x < self.position.x:
return false
if point.y < self.position.y:
return false
if point.x >= self.position.x + self.size.x:
return false
if point.y >= self.position.y + self.size.y:
return false
result = true
proc grow*(self: Rect2; by: float32): Rect2 {.inline, noinit.} =
## Returns Rect2 enlarged by the specified size in every direction.
result = self
result.position.x -= by
result.position.y -= by
result.size.x += by * 2
result.size.y += by * 2
proc growIndividual*(self: Rect2, left, top: float32,
right, bottom: float32): Rect2 {.inline, noinit.} =
result = self
result.position.x -= left
result.position.y -= top
result.size.x += left + right
result.size.y += top + bottom
proc expandTo*(self: var Rect2, to: Vector2) {.inline.} =
var startPoint = self.position
var endPoint = self.position + self.size
if to.x < startPoint.x:
startPoint.x = to.x
if to.y < startPoint.y:
startPoint.y = to.y
if to.x > endPoint.x:
endPoint.x = to.x
if to.y > endPoint.y:
endPoint.y = to.y
self.position = startPoint
self.size = endPoint - startPoint
proc expand*(self: Rect2; to: Vector2): Rect2 {.inline, noinit.} =
result = self
result.expandTo(to)
proc abs*(self: Rect2): Rect2 {.inline, noinit.} =
Rect2(position: vec2(self.position.x + min(self.size.x, 0'f32),
self.position.y + min(self.size.y, 0'f32)),
size: abs(self.size))
proc `==`*(a, b: Rect2): bool {.inline, noinit.} =
a.position == b.position and a.size == b.size
{.pop.} # stackTrace: off

View file

@ -1,6 +1,8 @@
# Copyright (c) 2017 Xored Software, Inc. # Copyright (c) 2018 Xored Software, Inc.
import godotcoretypes, internal.godotinternaltypes, gdnativeapi import hashes
import godotcoretypes, internal/godotinternaltypes, gdnativeapi
proc initRID*(): RID {.inline.} = proc initRID*(): RID {.inline.} =
getGDNativeAPI().ridNew(result) getGDNativeAPI().ridNew(result)
@ -14,6 +16,9 @@ proc id*(self: RID): uint32 {.inline.} =
proc `$`*(self: RID): string {.inline.} = proc `$`*(self: RID): string {.inline.} =
$self.id $self.id
proc hash*(self: RID): Hash {.inline.} =
self.id.hash()
proc `==`*(a, b: RID): bool {.inline.} = proc `==`*(a, b: RID): bool {.inline.} =
getGDNativeAPI().ridOperatorEqual(a, b) getGDNativeAPI().ridOperatorEqual(a, b)

View file

@ -1,6 +1,8 @@
# Copyright (c) 2017 Xored Software, Inc. # Copyright (c) 2018 Xored Software, Inc.
import internal.godotinternaltypes, internal.godotstrings import hashes, vector2
import internal/godotinternaltypes, internal/godotstrings
import godotcoretypes, gdnativeapi import godotcoretypes, gdnativeapi
proc initTransform2D*(): Transform2D {.inline.} = proc initTransform2D*(): Transform2D {.inline.} =
@ -15,60 +17,63 @@ proc initTransform2D*(xAxis, yAxis, origin: Vector2): Transform2D {.inline.} =
proc `$`*(self: Transform2D): string {.inline.} = proc `$`*(self: Transform2D): string {.inline.} =
$getGDNativeAPI().transform2DAsString(self) $getGDNativeAPI().transform2DAsString(self)
proc hash*(self: Transform2D): Hash {.inline, noinit.} =
!$(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

@ -1,8 +1,10 @@
# Copyright (c) 2017 Xored Software, Inc. # Copyright (c) 2018 Xored Software, Inc.
import internal.godotinternaltypes, internal.godotstrings import hashes
import internal/godotinternaltypes, internal/godotstrings
import godotcoretypes, gdnativeapi import godotcoretypes, gdnativeapi
import basis import basis, vector3
proc initTransform*(): Transform {.inline.} = proc initTransform*(): Transform {.inline.} =
result.basis = initBasis() result.basis = initBasis()
@ -21,51 +23,54 @@ proc initTransform*(basis: Basis, origin: Vector3): Transform {.inline.} =
proc `$`*(self: Transform): string {.inline.} = proc `$`*(self: Transform): string {.inline.} =
$getGDNativeAPI().transformAsString(self) $getGDNativeAPI().transformAsString(self)
proc hash*(self: Transform): Hash {.inline.} =
!$(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,8 +1,9 @@
import tables import tables, hashes
import godotcoretypes import godotcoretypes
import internal.godotinternaltypes, internal.godotvariants, import internal/godotinternaltypes, internal/godotvariants,
internal.godotstrings internal/godotstrings, internal/godotdictionaries,
internal/godotarrays
type type
Variant* = ref object Variant* = ref object
@ -72,12 +73,13 @@ proc newVariant*(r: cdouble): Variant {.inline.} =
proc newVariant*(s: string): Variant {.inline.} = proc newVariant*(s: string): Variant {.inline.} =
new(result, variantFinalizer) new(result, variantFinalizer)
if s.isNil: when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
initGodotVariant(result.godotVariant) if s.isNil:
else: initGodotVariant(result.godotVariant)
var godotStr = s.toGodotString() return
initGodotVariant(result.godotVariant, godotStr) var godotStr = s.toGodotString()
godotStr.deinit() initGodotVariant(result.godotVariant, godotStr)
godotStr.deinit()
import basis, nodepaths import basis, nodepaths
import planes, quats, rect2, aabb, rids import planes, quats, rect2, aabb, rids
@ -140,11 +142,7 @@ proc newVariant*(obj: ptr GodotObject): Variant {.inline.} =
new(result, variantFinalizer) new(result, variantFinalizer)
initGodotVariant(result.godotVariant, obj) initGodotVariant(result.godotVariant, obj)
import arrays, poolarrays import poolarrays
proc newVariant*(arr: Array): Variant {.inline.} =
new(result, variantFinalizer)
initGodotVariant(result.godotVariant, arr.godotArray[])
proc newVariant*(pba: PoolByteArray): Variant {.inline.} = proc newVariant*(pba: PoolByteArray): Variant {.inline.} =
new(result, variantFinalizer) new(result, variantFinalizer)
@ -177,81 +175,119 @@ proc newVariant*(pca: PoolColorArray): Variant {.inline.} =
proc asBool*(self: Variant): bool {.inline.} = proc asBool*(self: Variant): bool {.inline.} =
self.godotVariant.asBool() self.godotVariant.asBool()
proc asUInt*(self: Variant): uint64 = proc asUInt*(self: Variant): uint64 {.inline.} =
self.godotVariant.asUInt() self.godotVariant.asUInt()
proc asInt*(self: Variant): int64 = proc asInt*(self: Variant): int64 {.inline.} =
self.godotVariant.asInt() self.godotVariant.asInt()
proc asReal*(self: Variant): cdouble = proc asReal*(self: Variant): cdouble {.inline.} =
self.godotVariant.asReal() self.godotVariant.asReal()
proc asString*(self: Variant): string = proc asString*(self: Variant): string {.inline.} =
$self $self
proc asVector2*(self: Variant): Vector2 = proc asVector2*(self: Variant): Vector2 {.inline.} =
self.godotVariant.asVector2() self.godotVariant.asVector2()
proc asRect2*(self: Variant): Rect2 = proc asRect2*(self: Variant): Rect2 {.inline.} =
self.godotVariant.asRect2() self.godotVariant.asRect2()
proc asVector3*(self: Variant): Vector3 = proc asVector3*(self: Variant): Vector3 {.inline.} =
self.godotVariant.asVector3() self.godotVariant.asVector3()
proc asTransform2D*(self: Variant): Transform2D = proc asTransform2D*(self: Variant): Transform2D {.inline.} =
self.godotVariant.asTransform2D() self.godotVariant.asTransform2D()
proc asPlane*(self: Variant): Plane = proc asPlane*(self: Variant): Plane {.inline.} =
self.godotVariant.asPlane() self.godotVariant.asPlane()
proc asQuat*(self: Variant): Quat = proc asQuat*(self: Variant): Quat {.inline.} =
self.godotVariant.asQuat() self.godotVariant.asQuat()
proc asAABB*(self: Variant): AABB = proc asAABB*(self: Variant): AABB {.inline.} =
self.godotVariant.asAABB() self.godotVariant.asAABB()
proc asBasis*(self: Variant): Basis = proc asBasis*(self: Variant): Basis {.inline.} =
self.godotVariant.asBasis() self.godotVariant.asBasis()
proc asTransform*(self: Variant): Transform = proc asTransform*(self: Variant): Transform {.inline.} =
self.godotVariant.asTransform() self.godotVariant.asTransform()
proc asColor*(self: Variant): Color = proc asColor*(self: Variant): Color {.inline.} =
self.godotVariant.asColor() self.godotVariant.asColor()
proc asNodePath*(self: Variant): NodePath = proc asNodePath*(self: Variant): NodePath {.inline.} =
result = newNodePath(self.godotVariant.asNodePath()) result = newNodePath(self.godotVariant.asNodePath())
proc asRID*(self: Variant): RID = proc asRID*(self: Variant): RID {.inline.} =
self.godotVariant.asRID() self.godotVariant.asRID()
proc asGodotObject*(self: Variant): ptr GodotObject = proc asGodotObject*(self: Variant): ptr GodotObject {.inline.} =
self.godotVariant.asGodotObject() self.godotVariant.asGodotObject()
proc asArray*(self: Variant): Array = proc asPoolByteArray*(self: Variant): PoolByteArray {.inline.} =
newArray(self.godotVariant.asGodotArray())
proc asPoolByteArray*(self: Variant): PoolByteArray =
newPoolByteArray(self.godotVariant.asGodotPoolByteArray()) newPoolByteArray(self.godotVariant.asGodotPoolByteArray())
proc asPoolIntArray*(self: Variant): PoolIntArray = proc asPoolIntArray*(self: Variant): PoolIntArray {.inline.} =
newPoolIntArray(self.godotVariant.asGodotPoolIntArray()) newPoolIntArray(self.godotVariant.asGodotPoolIntArray())
proc asPoolRealArray*(self: Variant): PoolRealArray = proc asPoolRealArray*(self: Variant): PoolRealArray {.inline.} =
newPoolRealArray(self.godotVariant.asGodotPoolRealArray()) newPoolRealArray(self.godotVariant.asGodotPoolRealArray())
proc asPoolStringArray*(self: Variant): PoolStringArray = proc asPoolStringArray*(self: Variant): PoolStringArray {.inline.} =
newPoolStringArray(self.godotVariant.asGodotPoolStringArray()) newPoolStringArray(self.godotVariant.asGodotPoolStringArray())
proc asPoolVector2Array*(self: Variant): PoolVector2Array = proc asPoolVector2Array*(self: Variant): PoolVector2Array {.inline.} =
newPoolVector2Array(self.godotVariant.asGodotPoolVector2Array()) newPoolVector2Array(self.godotVariant.asGodotPoolVector2Array())
proc asPoolVector3Array*(self: Variant): PoolVector3Array = proc asPoolVector3Array*(self: Variant): PoolVector3Array {.inline.} =
newPoolVector3Array(self.godotVariant.asGodotPoolVector3Array()) newPoolVector3Array(self.godotVariant.asGodotPoolVector3Array())
proc asPoolColorArray*(self: Variant): PoolColorArray = proc asPoolColorArray*(self: Variant): PoolColorArray {.inline.} =
newPoolColorArray(self.godotVariant.asGodotPoolColorArray()) newPoolColorArray(self.godotVariant.asGodotPoolColorArray())
proc hash*(self: Variant): Hash =
proc objectHash(obj: ptr GodotObject): Hash =
if not obj.isNil: cast[int](obj).hash() else: 0.hash()
result = case self.getType():
of VariantType.Nil: Hash(0)
of VariantType.Bool: self.asBool().hash()
of VariantType.Int: self.asInt().hash()
of VariantType.Real: self.asReal().hash()
of VariantType.String: self.asString().hash()
of VariantType.Vector2: self.asVector2().hash()
of VariantType.Rect2: self.asRect2().hash()
of VariantType.Vector3: self.asVector3().hash()
of VariantType.Transform2D: self.asTransform2D().hash()
of VariantType.Plane: self.asPlane().hash()
of VariantType.Quat: self.asQuat().hash()
of VariantType.AABB: self.asAABB().hash()
of VariantType.Basis: self.asBasis().hash()
of VariantType.Transform: self.asTransform().hash()
of VariantType.Color: self.asColor().hash()
of VariantType.NodePath: self.asNodePath().hash()
of VariantType.RID: self.asRID().hash()
of VariantType.Object: self.asGodotObject().objectHash()
of VariantType.Dictionary: hash(self.godotVariant.asGodotDictionary().godotHash())
of VariantType.Array: hash(self.godotVariant.asGodotArray().godotHash())
of VariantType.PoolByteArray: self.asPoolByteArray().hash()
of VariantType.PoolIntArray: self.asPoolIntArray().hash()
of VariantType.PoolRealArray: self.asPoolRealArray().hash()
of VariantType.PoolStringArray: self.asPoolStringArray().hash()
of VariantType.PoolVector2Array: self.asPoolVector2Array().hash()
of VariantType.PoolVector3Array: self.asPoolVector3Array().hash()
of VariantType.PoolColorArray: self.asPoolColorArray().hash()
import arrays
proc newVariant*(arr: Array): Variant {.inline.} =
new(result, variantFinalizer)
initGodotVariant(result.godotVariant, arr.godotArray[])
proc asArray*(self: Variant): Array {.inline.} =
newArray(self.godotVariant.asGodotArray())
proc hasMethod*(self: Variant; meth: string): bool = proc hasMethod*(self: Variant; meth: string): bool =
var s = meth.toGodotString() var s = meth.toGodotString()
result = self.godotVariant.hasMethod(s) result = self.godotVariant.hasMethod(s)

View file

@ -1,125 +1,214 @@
# Copyright (c) 2017 Xored Software, Inc. # Copyright (c) 2018 Xored Software, Inc.
import internal.godotinternaltypes, internal.godotstrings import math, godotbase, hashes
import internal/godotinternaltypes, internal/godotstrings
import godotcoretypes, gdnativeapi import godotcoretypes, gdnativeapi
proc vec2*(): Vector2 {.inline.} = const EPSILON = 0.00001'f32
{.push stackTrace: off.}
proc vec2*(): Vector2 {.inline, noinit.} =
Vector2() Vector2()
proc vec2*(x, y: float32): Vector2 {.inline.} = proc vec2*(x, y: float32): Vector2 {.inline, noinit.} =
Vector2(x: x, y: y) Vector2(x: x, y: y)
proc `$`*(self: Vector2): string {.inline.} = proc `$`*(self: Vector2): string {.inline, noinit.} =
$getGDNativeAPI().vector2AsString(self) $getGDNativeAPI().vector2AsString(self)
proc normalized*(self: Vector2): Vector2 {.inline.} = proc hash*(self: Vector2): Hash {.inline, noinit.} =
getGDNativeAPI().vector2Normalized(self) !$(self.x.hash() !& self.y.hash())
proc length*(self: Vector2): float32 {.inline.} = proc `+`*(self, other: Vector2): Vector2 {.inline, noinit.} =
getGDNativeAPI().vector2Length(self) Vector2(x: self.x + other.x, y: self.y + other.y)
proc angle*(self: Vector2): float32 {.inline.} = proc `+=`*(self: var Vector2, other: Vector2) {.inline, noinit.} =
getGDNativeAPI().vector2Angle(self) self.x += other.x
self.y += other.y
proc lengthSquared*(self: Vector2): float32 {.inline.} = proc `-`*(self, other: Vector2): Vector2 {.inline, noinit.} =
getGDNativeAPI().vector2LengthSquared(self) Vector2(x: self.x - other.x, y: self.y - other.y)
proc isNormalized*(self: Vector2): bool {.inline.} = proc `-=`*(self: var Vector2, other: Vector2) {.inline, noinit.} =
getGDNativeAPI().vector2IsNormalized(self) self.x -= other.x
self.y -= other.y
proc distanceTo*(self, to: Vector2): float32 {.inline.} = proc `*`*(self, other: Vector2): Vector2 {.inline, noinit.} =
getGDNativeAPI().vector2DistanceTo(self, to) Vector2(x: self.x * other.x, y: self.y * other.y)
proc distanceSquaredTo*(self, to: Vector2): float32 {.inline.} = proc `*=`*(self: var Vector2, other: Vector2) {.inline, noinit.} =
getGDNativeAPI().vector2DistanceSquaredTo(self, to) self.x *= other.x
self.y *= other.y
proc angleTo*(self, to: Vector2): float32 {.inline.} = proc `*`*(self: Vector2, scalar: float32): Vector2 {.inline, noinit.} =
getGDNativeAPI().vector2AngleTo(self, to) Vector2(x: self.x * scalar, y: self.y * scalar)
proc angleToPoint*(self, to: Vector2): float32 {.inline.} = proc `*`*(scalar: float32, v: Vector2): Vector2 {.inline, noinit.} =
getGDNativeAPI().vector2AngleToPoint(self, to) v * scalar
proc lerp*(self, b: Vector2; t: float32): Vector2 {.inline.} = proc `*=`*(self: var Vector2, scalar: float32) {.inline, noinit.} =
getGDNativeAPI().vector2LinearInterpolate(self, b, t) self.x *= scalar
self.y *= scalar
proc cubicInterpolate*(self, b, preA, postB: Vector2; proc `/`*(self, other: Vector2): Vector2 {.inline, noinit.} =
t: float32): Vector2 {.inline.} = Vector2(x: self.x / other.x, y: self.y / other.y)
getGDNativeAPI().vector2CubicInterpolate(self, b, preA, postB, t)
proc rotated*(self: Vector2; phi: float32): Vector2 {.inline.} = proc `/=`*(self: var Vector2, other: Vector2) {.inline, noinit.} =
getGDNativeAPI().vector2Rotated(self, phi) self.x /= other.x
self.y /= other.y
proc tangent*(self: Vector2): Vector2 {.inline.} = proc `/`*(self: Vector2; scalar: float32): Vector2 {.inline, noinit.} =
getGDNativeAPI().vector2Tangent(self) Vector2(x: self.x / scalar, y: self.y / scalar)
proc floor*(self: Vector2): Vector2 {.inline.} = proc `/=`*(self: var Vector2; scalar: float32) {.inline, noinit.} =
getGDNativeAPI().vector2Floor(self)
proc snapped*(self: Vector2; by: Vector2): Vector2 {.inline.} =
getGDNativeAPI().vector2Snapped(self, by)
proc aspect*(self: Vector2): float32 {.inline.} =
getGDNativeAPI().vector2Aspect(self)
proc dot*(a, b: Vector2): float32 {.inline.} =
getGDNativeAPI().vector2Dot(a, b)
proc slide*(self, n: Vector2): Vector2 {.inline.} =
getGDNativeAPI().vector2Slide(self, n)
proc bounce*(self, n: Vector2): Vector2 {.inline.} =
getGDNativeAPI().vector2Bounce(self, n)
proc reflect*(self, n: Vector2): Vector2 {.inline.} =
getGDNativeAPI().vector2Reflect(self, n)
proc abs*(self: Vector2): Vector2 {.inline.} =
getGDNativeAPI().vector2Abs(self)
proc clamped*(self: Vector2; length: float32): Vector2 {.inline.} =
getGDNativeAPI().vector2Clamped(self, length)
proc `+`*(self, other: Vector2): Vector2 {.inline.} =
getGDNativeAPI().vector2OperatorAdd(self, other)
proc `+=`*(self: var Vector2, other: Vector2) {.inline.} =
self = self + other
proc `-`*(self, other: Vector2): Vector2 =
getGDNativeAPI().vector2OperatorSubtract(self, other)
proc `-=`*(self: var Vector2, other: Vector2) {.inline.} =
self = self - other
proc `*`*(self, other: Vector2): Vector2 =
getGDNativeAPI().vector2OperatorMultiplyVector(self, other)
proc `*=`*(self: var Vector2, other: Vector2) {.inline.} =
self = self * other
proc `*`*(self: Vector2, scalar: float32): Vector2 =
getGDNativeAPI().vector2OperatorMultiplyScalar(self, scalar)
proc `*=`*(self: var Vector2, scalar: float32) {.inline.} =
self = self * scalar
proc `/`*(self, other: Vector2): Vector2 =
getGDNativeAPI().vector2OperatorDivideVector(self, other)
proc `/=`*(self: var Vector2, other: Vector2) {.inline.} =
self = self / other
proc `/`*(self: Vector2; scalar: float32): Vector2 =
getGDNativeAPI().vector2OperatorDivideScalar(self, scalar)
proc `/=`*(self: var Vector2; scalar: float32) {.inline.} =
self = self / scalar self = self / scalar
proc `==`*(self, other: Vector2): bool {.inline.} = proc `==`*(self, other: Vector2): bool {.inline, noinit.} =
getGDNativeAPI().vector2OperatorEqual(self, other) self.x == other.x and self.y == other.y
proc `<`*(self, other: Vector2): bool {.inline.} = proc `<`*(self, other: Vector2): bool {.inline, noinit.} =
getGDNativeAPI().vector2OperatorLess(self, other) if self.x == other.x:
self.y < other.y
else:
self.x < other.x
proc `-`*(self: Vector2): Vector2 {.inline.} = proc `>`*(self, other: Vector2): bool {.inline, noinit.} =
getGDNativeAPI().vector2OperatorNeg(self) if self.x == other.x:
self.y > other.y
else:
self.x > other.x
proc `-`*(self: Vector2): Vector2 {.inline, noinit.} =
Vector2(x: -self.x, y: -self.y)
proc length*(self: Vector2): float32 {.inline, noinit.} =
sqrt(self.x * self.x + self.y * self.y)
proc lengthSquared*(self: Vector2): float32 {.inline, noinit.} =
self.x * self.x + self.y * self.y
proc normalize*(self: var Vector2) {.inline.} =
var len = self.x * self.x + self.y * self.y
if len != 0:
len = sqrt(len)
self.x /= len
self.y /= len
proc normalized*(self: Vector2): Vector2 {.inline, noinit.} =
result = self
result.normalize()
proc angle*(self: Vector2): float32 {.inline, noinit.} =
arctan2(self.y, self.x)
proc isNormalized*(self: Vector2): bool {.inline, noinit.} =
isEqualApprox(self.lengthSquared(), 1.0)
proc distanceTo*(self, to: Vector2): float32 {.inline, noinit.} =
sqrt((self.x - to.x) * (self.x - to.x) + (self.y - to.y) * (self.y - to.y))
proc distanceSquaredTo*(self, to: Vector2): float32 {.inline, noinit.} =
(self.x - to.x) * (self.x - to.x) + (self.y - to.y) * (self.y - to.y)
proc dot*(a, b: Vector2): float32 {.inline, noinit.} =
a.x * b.x + a.y * b.y
proc cross*(a, b: Vector2): float32 {.inline, noinit.} =
a.x * b.y - a.y * b.x
proc cross*(self: Vector2, scalar: float32): Vector2 {.inline, noinit.} =
Vector2(x: scalar * self.y, y: -scalar * self.x)
proc angleTo*(self, to: Vector2): float32 {.noinit.} =
arctan2(cross(self, to), dot(self, to))
proc angleToPoint*(self, to: Vector2): float32 {.inline, noinit.} =
arctan2(self.y - to.y, self.x - to.x)
proc floor*(self: Vector2): Vector2 {.inline, noinit.} =
Vector2(x: floor(self.x), y: floor(self.y))
proc planeProject*(self: Vector2, d: float32,
vec: Vector2): Vector2 {.noinit.} =
vec - self * (self.dot(vec) - d)
proc project*(self, other: Vector2): Vector2 {.noinit.} =
self * (other.dot(self) / self.dot(self))
proc lerp*(self, b: Vector2; t: float32): Vector2 {.inline, noinit.} =
result = self
result.x += t * (b.x - self.x)
result.y += t * (b.y - self.y)
proc cubicInterpolate*(self, b, preA, postB: Vector2;
t: float32): Vector2 {.noinit.} =
let p0 = preA
let p1 = self
let p2 = b
let p3 = postB
let t2 = t * t
let t3 = t2 * t
result = 0.5'f32 * ((p1 * 2.0'f32)) +
(-p0 + p2) * t +
(2.0 * p0 - 5.0 * p1 + 4 * p2 - p3) * t2 +
(-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3
proc setRotation*(self: var Vector2, radians: float32) {.inline, noinit.} =
self.x = cos(radians)
self.y = sin(radians)
proc rotated*(self: Vector2; phi: float32): Vector2 {.inline, noinit.} =
result.setRotation(phi)
result *= self.length()
proc tangent*(self: Vector2): Vector2 {.inline, noinit.} =
Vector2(x: self.y, y: -self.x)
proc snapped*(self: Vector2; by: Vector2): Vector2 {.inline, noinit.} =
Vector2(x: stepify(self.x, by.x), y: stepify(self.y, by.y))
proc aspect*(self: Vector2): float32 {.inline, noinit.} =
self.x / self.y
proc slide*(self, n: Vector2): Vector2 {.noinit.} =
when not defined(release):
if not n.isNormalized():
printError("Normal not normalized in slide. " & getStackTrace())
return vec2()
result = self - n * self.dot(n)
proc reflect*(self, n: Vector2): Vector2 {.noinit.} =
when not defined(release):
if not n.isNormalized():
printError("Normal not normalized in bounce. " & getStackTrace())
return vec2()
result = 2.0 * n * self.dot(n) - self
proc bounce*(self, n: Vector2): Vector2 {.inline, noinit.} =
-self.reflect(n)
proc abs*(self: Vector2): Vector2 {.inline, noinit.} =
Vector2(x: abs(self.x), y: abs(self.y))
proc clamped*(self: Vector2; length: float32): Vector2 {.noinit.} =
let len = self.length()
result = self
if len > 0 and length < len:
result /= len
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

View file

@ -1,8 +1,12 @@
# Copyright (c) 2017 Xored Software, Inc. # Copyright (c) 2018 Xored Software, Inc.
import math import math, hashes
import godotbase, godotcoretypes import godotbase, godotcoretypes
const EPSILON = 0.00001'f32
{.push stackTrace: off.}
proc vec3*(): Vector3 {.inline.} = proc vec3*(): Vector3 {.inline.} =
Vector3() Vector3()
@ -19,6 +23,9 @@ proc `$`*(self: Vector3): string {.inline.} =
result.add($self.z) result.add($self.z)
result.add(')') result.add(')')
proc hash*(self: Vector3): Hash {.inline, noinit.} =
!$(self.x.hash() !& self.y.hash() !& self.z.hash())
proc `+`*(a, b: Vector3): Vector3 {.inline.} = proc `+`*(a, b: Vector3): Vector3 {.inline.} =
result.x = a.x + b.x result.x = a.x + b.x
result.y = a.y + b.y result.y = a.y + b.y
@ -233,3 +240,15 @@ proc cubicInterpolate*(self, b, preA, postB: Vector3;
(-p0 + p2) * t + (-p0 + p2) * t +
(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

File diff suppressed because it is too large Load diff

View file

@ -1,14 +1,14 @@
# Copyright 2017 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,

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,8 @@
# Copyright 2017 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,
@ -93,6 +93,11 @@ proc getClassName*(o: ptr GodotObject): string =
# There are physics type not known by ClassDB # There are physics type not known by ClassDB
result = result[0..result.len-3] result = result[0..result.len-3]
proc getClassNameRaw*(o: ptr GodotObject): GodotString =
if getClassMethodBind.isNil:
getClassMethodBind = getMethod(cstring"Object", cstring"get_class")
getClassMethodBind.ptrCall(o, nil, addr result)
proc getGodotSingleton*(name: cstring): ptr GodotObject {.inline.} = proc getGodotSingleton*(name: cstring): ptr GodotObject {.inline.} =
getGDNativeAPI().globalGetSingleton(name) getGDNativeAPI().globalGetSingleton(name)

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) 2017 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

@ -1,4 +1,4 @@
# Copyright (c) 2017 Xored Software, Inc. # Copyright (c) 2018 Xored Software, Inc.
import godotinternaltypes, gdnativeapi import godotinternaltypes, gdnativeapi

View file

@ -1,4 +1,4 @@
# Copyright 2017 Xored Software, Inc. # Copyright 2018 Xored Software, Inc.
const MAX_ARG_COUNT* = 256 const MAX_ARG_COUNT* = 256
@ -16,22 +16,58 @@ type
GodotPoolByteArray* {.byref.} = object GodotPoolByteArray* {.byref.} = object
data: array[sizeof(int), byte] data: array[sizeof(int), byte]
GodotPoolByteArrayReadAccess* {.byref.} = object
data: array[1, byte]
GodotPoolByteArrayWriteAccess* {.byref.} = object
data: array[1, byte]
GodotPoolIntArray* {.byref.} = object GodotPoolIntArray* {.byref.} = object
data: array[sizeof(int), byte] data: array[sizeof(int), byte]
GodotPoolIntArrayReadAccess* {.byref.} = object
data: array[1, byte]
GodotPoolIntArrayWriteAccess* {.byref.} = object
data: array[1, byte]
GodotPoolRealArray* {.byref.} = object GodotPoolRealArray* {.byref.} = object
data: array[sizeof(int), byte] data: array[sizeof(int), byte]
GodotPoolRealArrayReadAccess* {.byref.} = object
data: array[1, byte]
GodotPoolRealArrayWriteAccess* {.byref.} = object
data: array[1, byte]
GodotPoolStringArray* {.byref.} = object GodotPoolStringArray* {.byref.} = object
data: array[sizeof(int), byte] data: array[sizeof(int), byte]
GodotPoolStringArrayReadAccess* {.byref.} = object
data: array[1, byte]
GodotPoolStringArrayWriteAccess* {.byref.} = object
data: array[1, byte]
GodotPoolVector2Array* {.byref.} = object GodotPoolVector2Array* {.byref.} = object
data: array[sizeof(int), byte] data: array[sizeof(int), byte]
GodotPoolVector2ArrayReadAccess* {.byref.} = object
data: array[1, byte]
GodotPoolVector2ArrayWriteAccess* {.byref.} = object
data: array[1, byte]
GodotPoolVector3Array* {.byref.} = object GodotPoolVector3Array* {.byref.} = object
data: array[sizeof(int), byte] data: array[sizeof(int), byte]
GodotPoolVector3ArrayReadAccess* {.byref.} = object
data: array[1, byte]
GodotPoolVector3ArrayWriteAccess* {.byref.} = object
data: array[1, byte]
GodotPoolColorArray* {.byref.} = object GodotPoolColorArray* {.byref.} = object
data: array[sizeof(int), byte] data: array[sizeof(int), byte]
GodotPoolColorArrayReadAccess* {.byref.} = object
data: array[1, byte]
GodotPoolColorArrayWriteAccess* {.byref.} = object
data: array[1, byte]
GodotString* {.byref.} = object GodotString* {.byref.} = object
data: array[sizeof(int), byte] data: array[sizeof(int), byte]
cwchar_t* {.importc: "wchar_t", nodecl.} = object
GodotCharString* {.byref.} = object GodotCharString* {.byref.} = object
data: array[sizeof(int), byte] data: array[sizeof(int), byte]
@ -80,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
@ -271,3 +308,6 @@ type
GodotClassConstructor* = proc (): ptr GodotObject {. GodotClassConstructor* = proc (): ptr GodotObject {.
noconv, gcsafe, locks: 0, raises: [], tags: [].} noconv, gcsafe, locks: 0, raises: [], tags: [].}
template offset*[T](p: ptr T, offset: int): ptr T =
cast[ptr T](cast[ByteAddress](p) +% (offset * sizeof(T)))

View file

@ -1,4 +1,4 @@
# Copyright 2017 Xored Software, Inc. # Copyright 2018 Xored Software, Inc.
import godotinternaltypes, gdnativeapi import godotinternaltypes, gdnativeapi

View file

@ -1,13 +1,15 @@
# Copyright (c) 2017 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,
appendArrayProc, insertProc, invertProc, pushBackProc, appendArrayProc, insertProc, invertProc, pushBackProc,
removeProc, resizeProc, setProc, getProc, sizeProc, removeProc, resizeProc, setProc, getProc, sizeProc,
destroyProc) = destroyProc, readProc, writeProc,
readAccessPtrProc, writeAccessPtrProc,
readAccessDestroyProc, writeAccessDestroyProc) =
proc initIdent*(dest: var ArrayT) {.inline.} = proc initIdent*(dest: var ArrayT) {.inline.} =
getGDNativeAPI().newProc(dest) getGDNativeAPI().newProc(dest)
@ -43,18 +45,74 @@ 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)
iterator items*(arr: ArrayT): DataT = iterator items*(self: ArrayT): DataT =
for i in 0.cint..<arr.len: let readAccess = getGDNativeAPI().readProc(self)
yield arr[i] let readPtr = getGDNativeAPI().readAccessPtrProc(readAccess)
for i in 0.cint..<self.len:
yield readPtr.offset(i)[]
getGDNativeAPI().readAccessDestroyProc(readAccess)
iterator pairs*(arr: ArrayT): tuple[key: cint, val: DataT] = iterator mitems*(self: var ArrayT): var DataT =
for i in 0.cint..<arr.len: let writeAccess = getGDNativeAPI().writeProc(self)
yield (i, arr[i]) let writePtr = getGDNativeAPI().writeAccessPtrProc(writeAccess)
for i in 0.cint..<self.len:
yield writePtr.offset(i)[]
getGDNativeAPI().writeAccessDestroyProc(writeAccess)
iterator pairs*(self: ArrayT): tuple[key: cint, val: DataT] =
let readAccess = getGDNativeAPI().readProc(self)
let readPtr = getGDNativeAPI().readAccessPtrProc(readAccess)
for i in 0.cint..<self.len:
yield (i, readPtr.offset(i)[])
getGDNativeAPI().readAccessDestroyProc(readAccess)
iterator mpairs*(self: var ArrayT): tuple[key: cint, val: var DataT] =
let writeAccess = getGDNativeAPI().writeProc(self)
let writePtr = getGDNativeAPI().writeAccessPtrProc(writeAccess)
for i in 0.cint..<self.len:
yield (i, writePtr.offset(i)[])
getGDNativeAPI().writeAccessDestroyProc(writeAccess)
proc subarray*(self: ArrayT, idxFrom, idxTo: cint): ArrayT =
## Indexes are inclusive, negative values count from the end of the array.
let ownLen = self.len
var actualIdxFrom = if idxFrom < 0: idxFrom + ownLen
else: idxFrom
var actualIdxTo = if idxTo < 0: idxTo + ownLen
else: idxTo
initIdent(result)
if actualIdxFrom < 0 or actualIdxFrom >= ownLen:
let instInfo = instantiationInfo()
getGDNativeAPI().printError(
cstring"Invalid subarray begin index", cstring"subarray", instInfo.filename, instInfo.line.cint)
return
if actualIdxTo < 0 or actualIdxTo >= ownLen:
let instInfo = instantiationInfo()
getGDNativeAPI().printError(
cstring"Invalid subarray end index", cstring"subarray", instInfo.filename, instInfo.line.cint)
return
let span = actualIdxTo - actualIdxFrom + 1
result.setLen(span)
let readAccess = getGDNativeAPI().readProc(self)
let writeAccess = getGDNativeAPI().writeProc(result)
let readPtr = getGDNativeAPI().readAccessPtrProc(readAccess).offset(actualIdxFrom)
copyMem(getGDNativeAPI().writeAccessPtrProc(writeAccess), readPtr, span)
getGDNativeAPI().readAccessDestroyProc(readAccess)
getGDNativeAPI().writeAccessDestroyProc(writeAccess)
genPoolArrayAPI(GodotPoolByteArray, initGodotPoolByteArray, byte, genPoolArrayAPI(GodotPoolByteArray, initGodotPoolByteArray, byte,
poolByteArrayNew, poolByteArrayNew,
@ -70,7 +128,13 @@ genPoolArrayAPI(GodotPoolByteArray, initGodotPoolByteArray, byte,
poolByteArraySet, poolByteArraySet,
poolByteArrayGet, poolByteArrayGet,
poolByteArraySize, poolByteArraySize,
poolByteArrayDestroy) poolByteArrayDestroy,
poolByteArrayRead,
poolByteArrayWrite,
poolByteArrayReadAccessPtr,
poolByteArrayWriteAccessPtr,
poolByteArrayReadAccessDestroy,
poolByteArrayWriteAccessDestroy)
genPoolArrayAPI(GodotPoolIntArray, initGodotPoolIntArray, cint, genPoolArrayAPI(GodotPoolIntArray, initGodotPoolIntArray, cint,
poolIntArrayNew, poolIntArrayNew,
@ -86,7 +150,13 @@ genPoolArrayAPI(GodotPoolIntArray, initGodotPoolIntArray, cint,
poolIntArraySet, poolIntArraySet,
poolIntArrayGet, poolIntArrayGet,
poolIntArraySize, poolIntArraySize,
poolIntArrayDestroy) poolIntArrayDestroy,
poolIntArrayRead,
poolIntArrayWrite,
poolIntArrayReadAccessPtr,
poolIntArrayWriteAccessPtr,
poolIntArrayReadAccessDestroy,
poolIntArrayWriteAccessDestroy)
genPoolArrayAPI(GodotPoolRealArray, initGodotPoolRealArray, float32, genPoolArrayAPI(GodotPoolRealArray, initGodotPoolRealArray, float32,
poolRealArrayNew, poolRealArrayNew,
@ -102,7 +172,13 @@ genPoolArrayAPI(GodotPoolRealArray, initGodotPoolRealArray, float32,
poolRealArraySet, poolRealArraySet,
poolRealArrayGet, poolRealArrayGet,
poolRealArraySize, poolRealArraySize,
poolRealArrayDestroy) poolRealArrayDestroy,
poolRealArrayRead,
poolRealArrayWrite,
poolRealArrayReadAccessPtr,
poolRealArrayWriteAccessPtr,
poolRealArrayReadAccessDestroy,
poolRealArrayWriteAccessDestroy)
genPoolArrayAPI(GodotPoolStringArray, initGodotPoolStringArray, GodotString, genPoolArrayAPI(GodotPoolStringArray, initGodotPoolStringArray, GodotString,
poolStringArrayNew, poolStringArrayNew,
@ -118,7 +194,13 @@ genPoolArrayAPI(GodotPoolStringArray, initGodotPoolStringArray, GodotString,
poolStringArraySet, poolStringArraySet,
poolStringArrayGet, poolStringArrayGet,
poolStringArraySize, poolStringArraySize,
poolStringArrayDestroy) poolStringArrayDestroy,
poolStringArrayRead,
poolStringArrayWrite,
poolStringArrayReadAccessPtr,
poolStringArrayWriteAccessPtr,
poolStringArrayReadAccessDestroy,
poolStringArrayWriteAccessDestroy)
genPoolArrayAPI(GodotPoolVector2Array, initGodotPoolVector2Array, Vector2, genPoolArrayAPI(GodotPoolVector2Array, initGodotPoolVector2Array, Vector2,
poolVector2ArrayNew, poolVector2ArrayNew,
@ -134,7 +216,13 @@ genPoolArrayAPI(GodotPoolVector2Array, initGodotPoolVector2Array, Vector2,
poolVector2ArraySet, poolVector2ArraySet,
poolVector2ArrayGet, poolVector2ArrayGet,
poolVector2ArraySize, poolVector2ArraySize,
poolVector2ArrayDestroy) poolVector2ArrayDestroy,
poolVector2ArrayRead,
poolVector2ArrayWrite,
poolVector2ArrayReadAccessPtr,
poolVector2ArrayWriteAccessPtr,
poolVector2ArrayReadAccessDestroy,
poolVector2ArrayWriteAccessDestroy)
genPoolArrayAPI(GodotPoolVector3Array, initGodotPoolVector3Array, Vector3, genPoolArrayAPI(GodotPoolVector3Array, initGodotPoolVector3Array, Vector3,
poolVector3ArrayNew, poolVector3ArrayNew,
@ -150,7 +238,13 @@ genPoolArrayAPI(GodotPoolVector3Array, initGodotPoolVector3Array, Vector3,
poolVector3ArraySet, poolVector3ArraySet,
poolVector3ArrayGet, poolVector3ArrayGet,
poolVector3ArraySize, poolVector3ArraySize,
poolVector3ArrayDestroy) poolVector3ArrayDestroy,
poolVector3ArrayRead,
poolVector3ArrayWrite,
poolVector3ArrayReadAccessPtr,
poolVector3ArrayWriteAccessPtr,
poolVector3ArrayReadAccessDestroy,
poolVector3ArrayWriteAccessDestroy)
genPoolArrayAPI(GodotPoolColorArray, initGodotPoolColorArray, Color, genPoolArrayAPI(GodotPoolColorArray, initGodotPoolColorArray, Color,
poolColorArrayNew, poolColorArrayNew,
@ -166,4 +260,10 @@ genPoolArrayAPI(GodotPoolColorArray, initGodotPoolColorArray, Color,
poolColorArraySet, poolColorArraySet,
poolColorArrayGet, poolColorArrayGet,
poolColorArraySize, poolColorArraySize,
poolColorArrayDestroy) poolColorArrayDestroy,
poolColorArrayRead,
poolColorArrayWrite,
poolColorArrayReadAccessPtr,
poolColorArrayWriteAccessPtr,
poolColorArrayReadAccessDestroy,
poolColorArrayWriteAccessDestroy)

View file

@ -1,4 +1,4 @@
# Copyright (c) 2017 Xored Software, Inc. # Copyright (c) 2018 Xored Software, Inc.
import godotinternaltypes, gdnativeapi import godotinternaltypes, gdnativeapi
@ -22,6 +22,12 @@ proc `&`*(self, b: GodotString): GodotString {.inline.} =
proc deinit*(self: var GodotString) {.inline.} = proc deinit*(self: var GodotString) {.inline.} =
getGDNativeAPI().stringDestroy(self) getGDNativeAPI().stringDestroy(self)
proc len*(self: GodotString): cint {.inline.} =
getGDNativeAPI().stringLength(self)
proc dataPtr*(self: GodotString): ptr cwchar_t {.inline.} =
getGDNativeAPI().stringWideStr(self)
proc `$`*(self: GodotString): string = proc `$`*(self: GodotString): string =
## Converts the ``GodotString`` into Nim string ## Converts the ``GodotString`` into Nim string
var charStr = getGDNativeAPI().stringUtf8(self) var charStr = getGDNativeAPI().stringUtf8(self)
@ -29,14 +35,16 @@ proc `$`*(self: GodotString): string =
result = newString(length) result = newString(length)
copyMem(addr result[0], getGDNativeAPI().charStringGetData(charStr), length) copyMem(addr result[0], getGDNativeAPI().charStringGetData(charStr), length)
getGDNativeAPI().charStringDestroy(charStr) getGDNativeAPI().charStringDestroy(charStr)
assert(result[length] == '\0')
proc toGodotString*(s: string): GodotString {.inline.} = proc toGodotString*(s: string): GodotString {.inline.} =
## Converts the Nim string into ``GodotString`` ## Converts the Nim string into ``GodotString``
if s.isNil: when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
initGodotString(result) if s.isNil:
initGodotString(result)
else:
initGodotString(result, cstring(s), cint(s.len + 1))
else: else:
initGodotString(result, unsafeAddr s[0], cint(s.len + 1)) 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 2017 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 2017 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:
@ -172,10 +172,15 @@ proc parseMethod(meth: NimNode): MethodDecl =
proc parseVarSection(decl: NimNode): seq[VarDecl] = proc parseVarSection(decl: NimNode): seq[VarDecl] =
assert(decl.kind == nnkVarSection) assert(decl.kind == nnkVarSection)
result = identDefsToVarDecls(decl[0]) for i in 0..<decl.len:
if i == 0:
result = identDefsToVarDecls(decl[i])
else:
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]()
@ -183,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:
@ -210,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
@ -267,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)
@ -283,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 =
@ -391,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:
@ -420,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:
@ -443,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)))
@ -453,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))
@ -479,10 +485,11 @@ proc genType(obj: ObjectDecl): NimNode {.compileTime.} =
else: else:
initMethod.body.insert(0, initBody) initMethod.body.insert(0, initBody)
# {.this: self.} for convenience when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
result.add(newNimNode(nnkPragma).add(newNimNode(nnkExprColonExpr).add( # {.this: self.} for convenience
ident("this"), ident("self") result.add(newNimNode(nnkPragma).add(newNimNode(nnkExprColonExpr).add(
))) ident("this"), ident("self")
)))
# Nim proc defintions # Nim proc defintions
var decls = newSeqOfCap[NimNode](obj.methods.len) var decls = newSeqOfCap[NimNode](obj.methods.len)
@ -502,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 = newCStringLit(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
@ -541,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) =
{.emit: """/*TYPESECTION*/ when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
{.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
{.emit: """ stackBottom = addr(stackBottom)
setStackBottom((void*)(&`stackBottom`)); when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
""".} {.emit: """
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
@ -594,8 +609,8 @@ N_NOINLINE(void, setStackBottom)(void* thestackbottom);
else: toGodotStyle(meth.name) else: toGodotStyle(meth.name)
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(
@ -621,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
@ -633,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``.
@ -646,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``.
## ##
@ -669,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 2017 Xored Software, Inc. # Copyright 2018 Xored Software, Inc.
import tables, typetraits, macros import tables, typetraits, macros, unicode, strutils, sets, options
import gdnativeapi import gdnativeapi
import core.godotcoretypes 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
@ -89,40 +91,71 @@ type
## values. ## values.
## See documentation of ``GodotPropertyHint`` for description of formats. ## See documentation of ``GodotPropertyHint`` for description of formats.
FNV1Hash = uint32
include "internal/backwardcompat.inc.nim"
proc isFinalized*(obj: NimGodotObject): bool {.inline.} = proc isFinalized*(obj: NimGodotObject): bool {.inline.} =
obj.isFinalized obj.isFinalized
template printWarning*(warning: typed) = var classRegistry {.threadvar.}: TableRef[FNV1Hash, ObjectInfo]
## Prints ``warning`` to Godot log, adding filename and line information. var classRegistryStatic* {.compileTime.}: TableRef[FNV1Hash, ObjectInfo]
let (filename, line) = instantiationInfo()
godotPrintWarning(cstring($warning), cstring"", cstring(filename), line.cint)
template printError*(error: typed) =
## Prints ``error`` to Godot log, adding filename and line information.
let (filename, line) = instantiationInfo()
godotPrintError(cstring($error), cstring"", cstring(filename), line.cint)
proc print*(parts: varargs[string, `$`]) =
## Prints concatenated ``parts`` to Godot log.
var combined = ""
for v in parts:
combined.add(v)
var s = combined.toGodotString()
godotPrint(s)
s.deinit()
var classRegistry {.threadvar.}: TableRef[cstring, ObjectInfo]
var classRegistryStatic* {.compileTime.}: TableRef[cstring, ObjectInfo]
## Compile-time variable used for implementation of several procedures ## Compile-time variable used for implementation of several procedures
## and macros ## and macros
static: static:
classRegistryStatic = newTable[cstring, 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]()
template initFNV1Hash(hash: var FNV1Hash) =
hash = 0x811c9dc5'u32
template appendFNV1Hash(hash: var FNV1Hash, val: uint8) =
block:
let u64hash = hash.uint64
hash = ((
u64hash +
(u64hash shl 1'u64) +
(u64hash shl 4'u64) +
(u64hash shl 7'u64) +
(u64hash shl 8'u64) +
(u64hash shl 24'u64)) and 0xFFFFFFFF'u32).uint32 xor val
{.push stackTrace:off.}
proc lsb(c: ptr cwchar_t): char {.noinit, inline.} =
{.emit: [result, " = (char)(", c[]," & 0xFF);"]}
{.pop.}
proc fnv1Hash(godotClassName: GodotString): FNV1Hash =
var charsCount = godotClassName.len
let charsPtr = godotClassName.dataPtr
if charsCount > 2 and
charsPtr.offset(charsCount - 2).lsb == 'S' and
charsPtr.offset(charsCount - 1).lsb == 'W':
charsCount -= 2
initFNV1Hash(result)
for i in 0..<charsCount:
let c = charsPtr.offset(i).lsb
appendFNV1Hash(result, c.uint8)
proc fnv1Hash(godotClassName: string): FNV1Hash {.compileTime.} =
var charsCount = godotClassName.len
if godotClassName.endsWith("SW"):
charsCount -= 2
initFNV1Hash(result)
var i = 0
for rune in runes(godotClassName):
if i >= charsCount:
break
let firstByte = uint8(rune.uint64 and 0xFF'u64)
appendFNV1Hash(result, firstByte)
# We don't really need to calculate hash of other bytes,
# since we only use hashes of ASCII strings
inc i
proc getClassName*(o: NimGodotObject): string = proc getClassName*(o: NimGodotObject): string =
o.godotObject.getClassName() o.godotObject.getClassName()
@ -154,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 =
@ -173,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)
@ -198,12 +234,12 @@ macro isResource(T: typedesc): bool =
result = if inherits(getType(T), "Resource"): ident("true") result = if inherits(getType(T), "Resource"): ident("true")
else: ident("false") else: ident("false")
template registerClass*(T: typedesc; godotClassName: cstring, template registerClass*(T: typedesc; godotClassName: string or cstring,
native: bool) = native: bool) =
## Registers the specified Godot type. ## Registers the specified Godot type.
## Used by ``gdobj`` macro and `godotapigen <godotapigen.html>`_. ## Used by ``gdobj`` macro and `godotapigen <godotapigen.html>`_.
if classRegistry.isNil: if classRegistry.isNil:
classRegistry = newTable[cstring, ObjectInfo]() classRegistry = newTable[FNV1Hash, ObjectInfo]()
let constructor = proc(): NimGodotObject = let constructor = proc(): NimGodotObject =
var t: T var t: T
new(t, nimGodotObjectFinalizer[T]) new(t, nimGodotObjectFinalizer[T])
@ -217,14 +253,22 @@ template registerClass*(T: typedesc; godotClassName: cstring,
isNative: native, isNative: native,
isRef: isRef isRef: isRef
) )
classRegistry[godotClassName] = objInfo classRegistry[fnv1Hash($godotClassName)] = objInfo
static: static:
let objInfoStatic = ObjectInfo( let objInfoStatic = ObjectInfo(
baseNativeClass: base, baseNativeClass: base,
isNative: native, isNative: native,
isRef: isRef, isRef: isRef,
) )
classRegistryStatic[godotClassName] = objInfoStatic let nameHash = fnv1Hash($godotClassName)
if not classRegistryStatic.contains(nameHash):
classRegistryStatic[nameHash] = objInfoStatic
elif not endsWith($godotClassName, "SW"):
# For simplicity we assume that all class names must have
# different hashes
# If this exception is ever raised, I guess, we should
# implement a proper collision resolving
raise newException(Exception, "Hash collision " & $godotClassName)
when isRef: when isRef:
static: static:
refClasses.add(T.name) refClasses.add(T.name)
@ -233,10 +277,10 @@ template registerClass*(T: typedesc; godotClassName: cstring,
nativeClasses.add(T.name) nativeClasses.add(T.name)
proc newNimGodotObject[T: NimGodotObject]( proc newNimGodotObject[T: NimGodotObject](
godotObject: ptr GodotObject, godotClassName: cstring, noRef: bool): T = godotObject: ptr GodotObject, godotClassName: GodotString, noRef: bool): T =
assert(not classRegistry.isNil) assert(not classRegistry.isNil)
assert(not godotObject.isNil) assert(not godotObject.isNil)
let objInfo = classRegistry.getOrDefault(godotClassName) let objInfo = classRegistry.getOrDefault(fnv1Hash(godotClassName))
if objInfo.constructor.isNil: if objInfo.constructor.isNil:
printError("Nim constructor not found for class " & $godotClassName) printError("Nim constructor not found for class " & $godotClassName)
else: else:
@ -259,9 +303,11 @@ proc asNimGodotObject*[T: NimGodotObject](
# Could be data from other bindings # Could be data from other bindings
result = nil result = nil
if result.isNil: if result.isNil:
var classNameStr = godotObject.getClassNameRaw()
result = newNimGodotObject[T]( result = newNimGodotObject[T](
godotObject, cstring(godotObject.getClassName()), godotObject, classNameStr,
forceNativeObject or noRef) forceNativeObject or noRef)
deinit(classNameStr)
proc newVariant*(obj: NimGodotObject): Variant {.inline.} = proc newVariant*(obj: NimGodotObject): Variant {.inline.} =
newVariant(obj.godotObject) newVariant(obj.godotObject)
@ -286,45 +332,35 @@ proc `as`*[T: NimGodotObject](obj: NimGodotObject, t: typedesc[T]): T =
## This can be used either in dot notation (``node.as(Button)``) or ## This can be used either in dot notation (``node.as(Button)``) or
## infix notation (``node as Button``). ## infix notation (``node as Button``).
if obj.isNil: return nil if obj.isNil: return nil
if obj of T: if system.`of`(obj, T):
result = T(obj) result = T(obj)
elif not obj.linkedObject.isNil and obj.linkedObject of 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`*[T: NimGodotObject](obj: NimGodotObject, proc `of`*[T1, T2: NimGodotObject](obj: T1, t: typedesc[T2]): bool {.inline.} =
t: typedesc[T]): bool {.inline.} =
## Godot-specific inheritance check. ## Godot-specific inheritance check.
not obj.isNil and (system.`of`(obj, T) or system.`of`(obj.linkedObject, T)) not obj.isNil and (system.`of`(obj, T2) or system.`of`(obj.linkedObject, T2))
proc newRStrLit(s: string): NimNode {.compileTime.} = 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: else:
let nameStr: string = (($T.getType()[1][1].symbol).split(':')[0]) let nameStr = ((T.getType()[1][1].strVal).split(':')[0])
godotName = case nameStr: case nameStr:
of "File", "Directory", "Thread", "Mutex", "Semaphore": of "File", "Directory", "Thread", "Mutex", "Semaphore":
"_" & nameStr newStrLitNode("_" & nameStr)
else: else:
nameStr newStrLitNode(nameStr)
result = newLit(godotName)
macro asCString(s: static[string]): cstring = macro asCString(s: static[string]): cstring =
result = newNimNode(nnkCallStrLit).add( result = newNimNode(nnkCallStrLit).add(
@ -383,17 +419,18 @@ proc newOwnObj[T: NimGodotObject](name: cstring): T =
proc gdnew*[T: NimGodotObject](): T = proc gdnew*[T: NimGodotObject](): T =
## Instantiates new object of type ``T``. ## Instantiates new object of type ``T``.
const godotName = asCString(toGodotName(T)) const godotName = toGodotName(T)
const objInfo = classRegistryStatic[godotName] const cGodotName = asCString(godotName)
const objInfo = classRegistryStatic[fnv1Hash(godotName)]
when objInfo.isNative: when objInfo.isNative:
let godotObject = getClassConstructor(godotName)() let godotObject = getClassConstructor(cGodotName)()
new(result, nimGodotObjectFinalizer[T]) new(result, nimGodotObjectFinalizer[T])
result.godotObject = godotObject result.godotObject = godotObject
when objInfo.isRef: when objInfo.isRef:
godotObject.initRef() godotObject.initRef()
result.isRef = true result.isRef = true
else: else:
result = newOwnObj[T](godotName) result = newOwnObj[T](cGodotName)
proc newCallError*(err: VariantCallError): ref CallError = proc newCallError*(err: VariantCallError): ref CallError =
## Instantiates ``CallError`` from Godot ``err``. ## Instantiates ``CallError`` from Godot ``err``.
@ -433,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.
@ -483,7 +523,7 @@ proc toVariant*(self: Variant): Variant {.inline.} =
if self.isNil: if self.isNil:
newVariant() newVariant()
else: else:
self newVariant(self)
proc fromVariant*(self: var Variant, proc fromVariant*(self: var Variant,
val: Variant): ConversionResult {.inline.} = val: Variant): ConversionResult {.inline.} =
@ -572,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)
@ -676,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:
s = nil when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
s = nil
else:
s = ""
else: else:
result = ConversionResult.TypeError result = ConversionResult.TypeError
@ -750,10 +797,31 @@ proc fromVariant*[T: array](s: var T, val: Variant): ConversionResult =
else: else:
result = ConversionResult.TypeError result = ConversionResult.TypeError
proc godotTypeInfo*(T: typedesc[Table|TableRef]): GodotTypeInfo {.inline.} = 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.} =
result.variantType = VariantType.Dictionary result.variantType = VariantType.Dictionary
proc toVariant*[T: Table or TableRef](t: T): Variant = proc toVariant*[T: Table or TableRef or OrderedTable or OrderedTableRef](t: T): Variant =
when t is ref: when t is ref:
if t.isNil: if t.isNil:
return newVariant() return newVariant()
@ -763,7 +831,7 @@ proc toVariant*[T: Table or TableRef](t: T): Variant =
dict[toVariant(k)] = toVariant(v) dict[toVariant(k)] = toVariant(v)
result = newVariant(dict) result = newVariant(dict)
proc fromVariant*[T: Table or TableRef](t: var T, proc fromVariant*[T: Table or TableRef or OrderedTable or OrderedTableRef](t: var T,
val: Variant): ConversionResult = val: Variant): ConversionResult =
if val.getType() == VariantType.Nil: if val.getType() == VariantType.Nil:
when t is ref: when t is ref:
@ -773,8 +841,12 @@ proc fromVariant*[T: Table or TableRef](t: var T,
mixin fromVariant mixin fromVariant
when t is Table: when t is Table:
t = initTable[type(t.keys()), type(t.values())]() t = initTable[type(t.keys()), type(t.values())]()
else: elif t is TableRef:
t = newTable[type(t.keys()), type(t.values())]() t = newTable[type(t.keys()), type(t.values())]()
elif t is OrderedTable:
t = initOrderedTable[type(t.keys()), type(t.values())]()
else:
t = newOrderedTable[type(t.keys()), type(t.values())]()
for k, v in dict: for k, v in dict:
var nimKey: type(t.keys()) var nimKey: type(t.keys())
var nimVal: type(t.values()) var nimVal: type(t.values())
@ -792,10 +864,11 @@ proc fromVariant*[T: Table or TableRef](t: var T,
else: else:
result = ConversionResult.TypeError result = ConversionResult.TypeError
{.emit: """/*TYPESECTION*/ when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
void NimMain(void); {.emit: """/*TYPESECTION*/
N_NOINLINE(void, setStackBottom)(void* thestackbottom); N_LIB_EXPORT N_CDECL(void, NimMain)(void);
""".} N_NOINLINE(void, setStackBottom)(void* thestackbottom);
""".}
var nativeLibHandle: pointer var nativeLibHandle: pointer
proc getNativeLibHandle*(): pointer = proc getNativeLibHandle*(): pointer =
@ -808,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();
setStackBottom((void*)(&`stackBottom`));
""".} """.}
when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
{.emit: """
setStackBottom((void*)(&`stackBottom`));
""".}
else:
nimGC_setStackBottom(stackBottom)
GC_fullCollect() GC_fullCollect()
GC_disable() GC_disable()
@ -822,7 +901,8 @@ 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.} =
deallocHeap(runFinalizers = not options[].inEditor, allowGcAfterwards = false) if not options[].inEditor or not compileOption("threads"):
deallocHeap(runFinalizers = not options[].inEditor, allowGcAfterwards = false)
const nimGcStepLengthUs {.intdefine.} = 2000 const nimGcStepLengthUs {.intdefine.} = 2000
@ -842,11 +922,17 @@ proc registerFrameCallback*(cb: proc () {.closure.}) =
else: else:
idleCallbacks.add(cb) idleCallbacks.add(cb)
{.push stackTrace: off.}
proc godot_nativescript_frame() {.cdecl, exportc, dynlib.} = proc godot_nativescript_frame() {.cdecl, exportc, dynlib.} =
var stackBottom {.volatile.}: pointer var stackBottom {.volatile.}: pointer
{.emit: """ stackBottom = addr(stackBottom)
setStackBottom((void*)(&`stackBottom`)); when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
""".} {.emit: """
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)
@ -859,7 +945,7 @@ proc godot_nativescript_thread_enter() {.cdecl, exportc, dynlib.} =
when compileOption("threads"): when compileOption("threads"):
setupForeignThreadGc() setupForeignThreadGc()
else: else:
const err = cstring"A foreign thread is created, but app is compiled without --threads:on. Bad things will happen if Nim code is invoked from this thread." const err = cstring"A foreign thread is created, but app is compiled without --threads:on. Bad things will happen if Nim code is invoked from this thread. If you see this warning when running the editor and you don't actually use threads, ignore it."
var s = err.toGodotString() var s = err.toGodotString()
godotPrint(s) godotPrint(s)
s.deinit() s.deinit()
@ -867,3 +953,5 @@ proc godot_nativescript_thread_enter() {.cdecl, exportc, dynlib.} =
proc godot_nativescript_thread_exit() {.cdecl, exportc, dynlib.} = proc godot_nativescript_thread_exit() {.cdecl, exportc, dynlib.} =
when compileOption("threads"): when compileOption("threads"):
teardownForeignThreadGc() teardownForeignThreadGc()
{.pop.} # stackTrace: off

View file

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