├── docs ├── nim.cfg ├── godotapi.rst ├── docpublish.nim ├── docbuild.nim └── index.rst ├── godot ├── core │ ├── nim.cfg │ ├── rids.nim │ ├── godotbase.nim │ ├── nodepaths.nim │ ├── planes.nim │ ├── quats.nim │ ├── colors.nim │ ├── aabb.nim │ ├── godotcoretypes.nim │ ├── transforms.nim │ ├── transform2d.nim │ ├── dictionaries.nim │ ├── arrays.nim │ ├── rect2.nim │ ├── poolarrays.nim │ ├── vector2.nim │ ├── vector3.nim │ ├── variants.nim │ └── basis.nim ├── internal │ ├── nim.cfg │ ├── backwardcompat.inc.nim │ ├── godotnodepaths.nim │ ├── godotstrings.nim │ ├── godotdictionaries.nim │ ├── godotarrays.nim │ ├── godotvariants.nim │ ├── godotpoolarrays.nim │ └── godotinternaltypes.nim ├── godot.nim.cfg ├── nim │ ├── nim.cfg │ ├── godotmacros.nim │ └── godotnim.nim ├── nimdoc.cfg ├── godot.nim └── godotinternal.nim ├── godot.nimble ├── .gitignore ├── .vscode └── settings.json ├── README.md ├── LICENSE └── .travis.yml /docs/nim.cfg: -------------------------------------------------------------------------------- 1 | --threads:on -------------------------------------------------------------------------------- /godot/core/nim.cfg: -------------------------------------------------------------------------------- 1 | --path:"$projectdir/../" -------------------------------------------------------------------------------- /godot/internal/nim.cfg: -------------------------------------------------------------------------------- 1 | --path:"$projectdir/../" -------------------------------------------------------------------------------- /godot/godot.nim.cfg: -------------------------------------------------------------------------------- 1 | --path:"$projectdir" 2 | -d:useRealtimeGc -------------------------------------------------------------------------------- /godot/nim/nim.cfg: -------------------------------------------------------------------------------- 1 | --path:"$projectdir/../" 2 | -d:useRealtimeGc -------------------------------------------------------------------------------- /godot.nimble: -------------------------------------------------------------------------------- 1 | version = "0.8.5" 2 | author = "Xored Software, Inc." 3 | description = "Godot Engine bindings" 4 | license = "MIT" 5 | srcDir = "godot" 6 | 7 | requires "nim >= 0.17.3", "compiler >= 0.17.3" 8 | -------------------------------------------------------------------------------- /godot/nimdoc.cfg: -------------------------------------------------------------------------------- 1 | doc.item.seesrc = """  Source 4 | Edit 5 | """ -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | nimcache/ 2 | 3 | /godot/apigen/apigen 4 | /godot/apigen/apigen.exe 5 | /godot/godotapigen 6 | /godot/godotapigen.exe 7 | 8 | /docgen 9 | /docs/docbuild 10 | /docs/docbuild.exe 11 | /docs/docpublish 12 | /docs/docpublish.exe 13 | 14 | .DS_Store -------------------------------------------------------------------------------- /docs/godotapi.rst: -------------------------------------------------------------------------------- 1 | =============== 2 | Godot API (Nim) 3 | =============== 4 | 5 | :Godot Git Hash: |godothash| 6 | 7 | .. contents:: 8 | 9 | This is an auto-generated index of Godot API. It's built from Git changeset 10 | $GODOTAPI_CHANGESET_HASH. 11 | 12 | $AUTO_GENERATED_GODOTAPI_LIST -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.tabSize": 2, 3 | "editor.rulers": [80], 4 | "editor.insertSpaces": true, 5 | "editor.detectIndentation": false, 6 | "files.eol": "\n", 7 | "files.trimTrailingWhitespace": true, 8 | "nim.project": ["godot/godot.nim", 9 | "godot/godotapigen.nim"], 10 | "nim.buildOnSave": false, 11 | "nim.lintOnSave": true, 12 | "nim.licenseString": "# Copyright 2018 Xored Software, Inc.\n\n", 13 | "files.exclude": { 14 | "**/nimcache/**": true 15 | } 16 | } -------------------------------------------------------------------------------- /godot/internal/backwardcompat.inc.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Xored Software, Inc. 2 | 3 | when (NimMajor, NimMinor, NimPatch) < (0, 19, 0): 4 | import macros, sets 5 | 6 | proc strVal(n: NimNode): string {.used.} = 7 | case n.kind 8 | of nnkIdent: 9 | $n.ident 10 | of nnkSym: 11 | $n.symbol 12 | else: 13 | macros.strVal(n) 14 | 15 | proc toHashSet[A](keys: openArray[A]): HashSet[A] {.inline, used.} = 16 | toSet(keys) 17 | 18 | proc initHashSet[A](): HashSet[A] {.inline, used.} = 19 | initSet[A]() 20 | -------------------------------------------------------------------------------- /godot/godot.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Xored Software, Inc. 2 | 3 | import core/godotbase, godotinternal 4 | import core/godotcoretypes 5 | import core/vector2, core/rect2, core/vector3, core/transform2d, core/planes, 6 | core/quats 7 | import core/aabb, core/basis, core/transforms, core/colors, core/nodepaths, 8 | core/rids 9 | import core/dictionaries, core/arrays, core/poolarrays, core/variants 10 | 11 | import nim/godotmacros, nim/godotnim 12 | 13 | export godotbase, godotcoretypes, vector2, rect2, vector3, transform2d, planes, 14 | quats, aabb, basis, transforms, colors, nodepaths, rids, dictionaries, 15 | arrays, poolarrays, variants 16 | export godotmacros, godotnim 17 | 18 | export GodotPropertyHint, GodotPropertyUsage -------------------------------------------------------------------------------- /godot/core/rids.nim: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018 Xored Software, Inc. 2 | 3 | import hashes 4 | 5 | import godotcoretypes, internal/godotinternaltypes, gdnativeapi 6 | 7 | proc initRID*(): RID {.inline.} = 8 | getGDNativeAPI().ridNew(result) 9 | 10 | proc initRID*(obj: ptr GodotObject): RID {.inline.} = 11 | getGDNativeAPI().ridNewWithResource(result, obj) 12 | 13 | proc id*(self: RID): uint32 {.inline.} = 14 | cast[uint32](getGDNativeAPI().ridGetId(self)) 15 | 16 | proc `$`*(self: RID): string {.inline.} = 17 | $self.id 18 | 19 | proc hash*(self: RID): Hash {.inline.} = 20 | self.id.hash() 21 | 22 | proc `==`*(a, b: RID): bool {.inline.} = 23 | getGDNativeAPI().ridOperatorEqual(a, b) 24 | 25 | proc `<`*(a, b: RID): bool {.inline.} = 26 | getGDNativeAPI().ridOperatorLess(a, b) 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nim bindings for Godot Engine 2 | 3 | Nim bindings for Godot 3 based on [GDNative](https://godotengine.org/article/dlscript-here). 4 | 5 | Documentation: https://pragmagic.github.io/godot-nim/ 6 | 7 | ## Made with godot-nim 8 | 9 | The library is production-ready and has been used to create these games: 10 | 11 | - [Frayhem](https://frayhem.com/) - mobile online 3v3 brawler 12 | - [Summon Age](https://summonage.com/) - mobile hero collection RPG 13 | - [Turing Complete](https://turingcomplete.game/) - computer science game 14 | 15 | ## Links 16 | 17 | - [Godot Engine](https://www.godotengine.org/) 18 | - [Nim](https://nim-lang.org/) 19 | 20 | ## License 21 | 22 | This project is licensed under the MIT license. Read [LICENSE](LICENSE) file for details. 23 | 24 | Copyright (c) 2018-2021 Gearage LLC. 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | godot-nim - Nim bindings for Godot Engine 2 | 3 | The MIT License 4 | 5 | Copyright (c) 2018 Xored Software Inc. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 8 | associated documentation files (the "Software"), to deal in the Software without restriction, 9 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all copies or substantial 14 | portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 17 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 19 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH 20 | THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /godot/internal/godotnodepaths.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Xored Software, Inc. 2 | 3 | import godotinternaltypes, gdnativeapi 4 | 5 | proc initGodotNodePath*(dest: var GodotNodePath; s: GodotString) {.inline.} = 6 | getGDNativeAPI().nodePathNew(dest, s) 7 | 8 | proc initGodotNodePath*(dest: var GodotNodePath; 9 | src: GodotNodePath) {.inline.} = 10 | getGDNativeAPI().nodePathNewCopy(dest, src) 11 | 12 | proc deinit*(self: var GodotNodePath) {.inline.} = 13 | getGDNativeAPI().nodePathDestroy(self) 14 | 15 | proc toGodotString*(self: GodotNodePath): GodotString {.inline.} = 16 | getGDNativeAPI().nodePathAsString(self) 17 | 18 | proc isAbsolute*(self: GodotNodePath): bool {.inline.} = 19 | getGDNativeAPI().nodePathIsAbsolute(self) 20 | 21 | proc nameCount*(self: GodotNodePath): cint {.inline.} = 22 | getGDNativeAPI().nodePathGetNameCount(self) 23 | 24 | proc getName*(self: GodotNodePath; idx: cint): GodotString {.inline.} = 25 | getGDNativeAPI().nodePathGetName(self, idx) 26 | 27 | proc subnameCount*(self: GodotNodePath): cint {.inline.} = 28 | getGDNativeAPI().nodePathGetSubnameCount(self) 29 | 30 | proc getSubname*(self: GodotNodePath; idx: cint): GodotString {.inline.} = 31 | getGDNativeAPI().nodePathGetSubname(self, idx) 32 | 33 | proc getConcatenatedSubnames*(self: GodotNodePath): GodotString {.inline.} = 34 | getGDNativeAPI().nodePathGetConcatenatedSubnames(self) 35 | 36 | proc isEmpty*(self: GodotNodePath): bool {.inline.} = 37 | getGDNativeAPI().nodePathIsEmpty(self) 38 | 39 | proc `==`*(a, b: GodotNodePath): bool {.inline.} = 40 | getGDNativeAPI().nodePathOperatorEqual(a, b) 41 | -------------------------------------------------------------------------------- /godot/core/godotbase.nim: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018 Xored Software, Inc. 2 | 3 | import math, godotinternal 4 | 5 | # math helpers 6 | 7 | {.push stackTrace: off.} 8 | const EPSILON = 0.00001'f32 9 | proc isEqualApprox*(a, b: float32): bool {.inline, noinit.} = 10 | abs(a - b) < EPSILON 11 | 12 | proc isEqualApprox*(a, b: float64): bool {.inline, noinit.} = 13 | abs(a - b) < EPSILON 14 | 15 | proc sign*(a: float32): float32 {.inline, noinit.} = 16 | if a < 0: -1.0'f32 else: 1.0'f32 17 | 18 | proc sign*(a: float64): float64 {.inline, noinit.} = 19 | if a < 0: -1.0'f64 else: 1.0'f64 20 | 21 | proc stepify*(value, step: float64): float64 {.inline, noinit.} = 22 | if step != 0'f64: 23 | floor(value / step + 0.5'f64) * step 24 | else: 25 | value 26 | 27 | proc stepify*(value, step: float32): float32 {.inline, noinit.} = 28 | if step != 0'f32: 29 | floor(value / step + 0.5'f32) * step 30 | else: 31 | value 32 | 33 | when (NimMajor, NimMinor, NimPatch) < (0, 20, 4): 34 | # Newer Nim has these procs in system module 35 | 36 | proc min*(x, y: float32): float32 {.inline, noinit.} = 37 | if x <= y: x else: y 38 | 39 | proc abs*(x: float32): float32 {.inline, noinit.} = 40 | if x < 0.0: -x else: x 41 | 42 | proc max*(x, y: float32): float32 {.inline, noinit.} = 43 | if y <= x: x else: y 44 | 45 | {.pop.} # stackTrace: off 46 | 47 | template printWarning*(warning: typed) = 48 | ## Prints ``warning`` to Godot log, adding filename and line information. 49 | let instInfo = instantiationInfo() 50 | godotPrintWarning(cstring($warning), cstring"", cstring(instInfo.filename), instInfo.line.cint) 51 | 52 | template printError*(error: typed) = 53 | ## Prints ``error`` to Godot log, adding filename and line information. 54 | let instInfo = instantiationInfo() 55 | godotPrintError(cstring($error), cstring"", cstring(instInfo.filename), instInfo.line.cint) 56 | 57 | proc print*(parts: varargs[string, `$`]) = 58 | ## Prints concatenated ``parts`` to Godot log. 59 | var combined = "" 60 | for v in parts: 61 | combined.add(v) 62 | var s = combined.toGodotString() 63 | godotPrint(s) 64 | s.deinit() 65 | -------------------------------------------------------------------------------- /godot/internal/godotstrings.nim: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018 Xored Software, Inc. 2 | 3 | import godotinternaltypes, gdnativeapi 4 | 5 | proc initGodotString(dest: var GodotString) {.inline, raises: [].} = 6 | getGDNativeAPI().stringNew(dest) 7 | 8 | proc initGodotString(dest: var GodotString; contents: cstring; 9 | size: cint) {.inline.} = 10 | ## Initializes ``dest`` from UTF-8 ``contents`` 11 | dest = getGDNativeAPI().stringCharsToUtf8WithLen(contents, size) 12 | 13 | proc `==`*(self, b: GodotString): bool {.inline.} = 14 | getGDNativeAPI().stringOperatorEqual(self, b) 15 | 16 | proc `<`*(self, b: GodotString): bool {.inline.} = 17 | getGDNativeAPI().stringOperatorLess(self, b) 18 | 19 | proc `&`*(self, b: GodotString): GodotString {.inline.} = 20 | getGDNativeAPI().stringOperatorPlus(self, b) 21 | 22 | proc deinit*(self: var GodotString) {.inline.} = 23 | getGDNativeAPI().stringDestroy(self) 24 | 25 | proc len*(self: GodotString): cint {.inline.} = 26 | getGDNativeAPI().stringLength(self) 27 | 28 | proc dataPtr*(self: GodotString): ptr cwchar_t {.inline.} = 29 | getGDNativeAPI().stringWideStr(self) 30 | 31 | proc `$`*(self: GodotString): string = 32 | ## Converts the ``GodotString`` into Nim string 33 | var charStr = getGDNativeAPI().stringUtf8(self) 34 | let length = getGDNativeAPI().charStringLength(charStr) 35 | result = newString(length) 36 | if length > 0: 37 | copyMem(addr result[0], getGDNativeAPI().charStringGetData(charStr), length) 38 | getGDNativeAPI().charStringDestroy(charStr) 39 | 40 | proc toGodotString*(s: string): GodotString {.inline.} = 41 | ## Converts the Nim string into ``GodotString`` 42 | when (NimMajor, NimMinor, NimPatch) < (0, 19, 0): 43 | if s.isNil: 44 | initGodotString(result) 45 | else: 46 | initGodotString(result, cstring(s), cint(s.len + 1)) 47 | else: 48 | initGodotString(result, cstring(s), cint(s.len + 1)) 49 | 50 | proc toGodotString*(s: cstring): GodotString {.inline.} = 51 | ## Converts the cstring into ``GodotString`` 52 | if s.isNil: 53 | initGodotString(result) 54 | else: 55 | initGodotString(result, s, cint(s.len + 1)) 56 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: c 3 | os: 4 | - osx 5 | compiler: clang 6 | env: 7 | global: 8 | - secure: o+IZkRS6J7bGYkiilm10KDeCTDIVHszZ9dPvb93cdUKX/9hFVRiUjDOvNXqBdyOv43JIAsRTppym4B2pfcp9cwLoVBJNW70GKhp6ChLZm3wFdabScWKemuG2YtAUyGiSmxbVmUZ4baltnADyGFHuYWgHLjx6AKO26SqrXRLJ0I1IzGNKKNIfoyZzm7qdFDGJRnSC7L+y1pOITK7dpy60D1vat4FhOLaz2K7L8T8tZYZFK7yyxKduFUlY3cy4z3TpjxMa9/ksCiPiuPDN5xOrVIw0AtgZ2gYodZJUEnfaRzFkgcZ4OJuTAMNMalu52mVAVAoDt4yc7BnbtfsYJzfIjTeLjjWKWz8mqqp/HpxcfVnmPKxV5zeN8UhbosT8vNjwretWbQcFndzt0ohK7E8uMsnDGER7sGPEhCZCttkId96gi7Ro1awPIKCqLaMqB43Bwo48nnW0oQgrfWe1ZKtREXWI4F1F2GMbU8Jsvv0N5GnPGd4RDieBH5KIkJXcttAwRk8AUQ4U5PVkQ/OK9xm9BH2tB0vrjZ4FZWnFPapKVcPUYw9deyyXOXwSMmDpuwkJIjqi3tRyBWJG9+tUlAJw8zyFkCPeN9kzyVH/PhbacwBMdSxew24VLAWWCUhQHCP+fcjpKio8uDUFQN3javIRV4N3mHJ9v0VAF7Ixzh8AviQ= 9 | 10 | addons: 11 | apt: 12 | sources: 13 | - ubuntu-toolchain-r-test 14 | - llvm-toolchain-trusty-3.9 15 | packages: 16 | - build-essential 17 | - scons 18 | - pkg-config 19 | - libx11-dev 20 | - libxcursor-dev 21 | - libasound2-dev 22 | - libfreetype6-dev 23 | - libgl1-mesa-dev 24 | - libglu1-mesa-dev 25 | - libssl-dev 26 | - libxinerama-dev 27 | - libxrandr-dev 28 | 29 | before_install: 30 | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then rvm --default use 2.3; brew update; brew install scons ; fi 31 | 32 | install: 33 | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export GODOT_PLATFORM=osx; else export GODOT_PLATFORM=x11; fi 34 | - git clone --depth=1 https://github.com/nim-lang/Nim.git 35 | - cd Nim 36 | - git checkout devel 37 | - sh ci/build.sh 38 | - export PATH=$PATH:"`pwd`/bin" 39 | - ./koch tools -d:release 40 | - nimble install -y 41 | - cd .. 42 | - git clone --depth=1 https://github.com/godotengine/godot.git godotengine 43 | - cd godotengine 44 | - scons -j 3 platform=$GODOT_PLATFORM 45 | - export GODOT_BIN="`pwd`/bin/godot.$GODOT_PLATFORM.tools.64" 46 | - cd .. 47 | 48 | script: 49 | - set -e 50 | - mkdir godotapi 51 | - nim c -d:release -r godot/godotapigen.nim "$GODOT_BIN" godotapi 52 | - nim c -d:useRealtimeGc --path:godot -c godotapi/godotall.nim 53 | - nim c -d:release -r docs/docpublish.nim 54 | -------------------------------------------------------------------------------- /godot/core/nodepaths.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Xored Software, Inc. 2 | 3 | import hashes 4 | 5 | import internal/godotinternaltypes, internal/godotnodepaths, 6 | internal/godotstrings 7 | 8 | type 9 | NodePath* = ref object 10 | path: GodotNodePath 11 | 12 | proc nodePathFinalizer(path: NodePath) = 13 | path.path.deinit() 14 | 15 | proc newNodePath*(path: GodotNodePath): NodePath = 16 | ## Moves the GodotNodePath into Nim wrapper. The ``path`` will be destroyed 17 | ## automatically when the result is no longer referenced. 18 | new(result, nodePathFinalizer) 19 | result.path = path 20 | 21 | proc newNodePath*(s: string): NodePath = 22 | new(result, nodePathFinalizer) 23 | var str = s.toGodotString() 24 | initGodotNodePath(result.path, str) 25 | str.deinit() 26 | 27 | proc godotNodePath*(path: NodePath): ptr GodotNodePath {.inline.} = 28 | ## WARNING: do not keep the returned value for longer than the lifetime of 29 | ## ``path`` 30 | result = addr path.path 31 | 32 | proc `$`*(self: NodePath): string {.inline.} = 33 | var s = self.path.toGodotString() 34 | result = $s 35 | s.deinit() 36 | 37 | proc hash*(self: NodePath): Hash {.inline.} = 38 | ($self).hash() 39 | 40 | proc isAbsolute*(self: NodePath): bool {.inline.} = 41 | self.path.isAbsolute() 42 | 43 | proc nameCount*(self: NodePath): int {.inline.} = 44 | int(self.path.nameCount()) 45 | 46 | proc getName*(self: NodePath; idx: int): string {.inline.} = 47 | var s = self.path.getName(idx.cint) 48 | result = $s 49 | s.deinit() 50 | 51 | proc subnameCount*(self: NodePath): int {.inline.} = 52 | int(self.path.subnameCount()) 53 | 54 | proc getSubname*(self: NodePath; idx: int): string {.inline.} = 55 | var s = self.path.getSubname(idx.cint) 56 | result = $s 57 | s.deinit() 58 | 59 | proc getConcatenatedSubnames*(self: NodePath): string {.inline.} = 60 | var s = self.path.getConcatenatedSubnames() 61 | result = $s 62 | s.deinit() 63 | 64 | proc isEmpty*(self: NodePath): bool {.inline.} = 65 | self.path.isEmpty() 66 | 67 | proc `==`*(a, b: NodePath): bool = 68 | if a.isNil and b.isNil: return true 69 | if a.isNil != b.isNil: return false 70 | result = a.path == b.path 71 | 72 | converter fromString*(s: string): NodePath = 73 | newNodePath(s) 74 | -------------------------------------------------------------------------------- /godot/internal/godotdictionaries.nim: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018 Xored Software, Inc. 2 | 3 | import godotinternaltypes, gdnativeapi 4 | 5 | proc initGodotDictionary*(dest: var GodotDictionary) {.inline.} = 6 | getGDNativeAPI().dictionaryNew(dest) 7 | 8 | proc initGodotDictionary*(dest: var GodotDictionary; 9 | src: GodotDictionary) {.inline.} = 10 | getGDNativeAPI().dictionaryNewCopy(dest, src) 11 | 12 | proc deinit*(self: var GodotDictionary) {.inline.} = 13 | getGDNativeAPI().dictionaryDestroy(self) 14 | 15 | proc len*(self: GodotDictionary): cint {.inline.} = 16 | getGDNativeAPI().dictionarySize(self) 17 | 18 | proc isEmpty*(self: GodotDictionary): bool {.inline.} = 19 | getGDNativeAPI().dictionaryEmpty(self) 20 | 21 | proc clear*(self: var GodotDictionary) {.inline.} = 22 | getGDNativeAPI().dictionaryClear(self) 23 | 24 | proc contains*(self: GodotDictionary; key: GodotVariant): bool {.inline.} = 25 | getGDNativeAPI().dictionaryHas(self, key) 26 | 27 | proc contains*(self: GodotDictionary; keys: GodotArray): bool {.inline.} = 28 | getGDNativeAPI().dictionaryHasAll(self, keys) 29 | 30 | proc del*(self: var GodotDictionary; key: GodotVariant) {.inline.} = 31 | getGDNativeAPI().dictionaryErase(self, key) 32 | 33 | proc godotHash*(self: GodotDictionary): cint {.inline.} = 34 | getGDNativeAPI().dictionaryHash(self, ) 35 | 36 | proc keys*(self: GodotDictionary): GodotArray {.inline.} = 37 | getGDNativeAPI().dictionaryKeys(self) 38 | 39 | proc values*(self: GodotDictionary): GodotArray {.inline.} = 40 | getGDNativeAPI().dictionaryValues(self) 41 | 42 | proc `[]`*(self: GodotDictionary; key: GodotVariant): GodotVariant {.inline.} = 43 | getGDNativeAPI().dictionaryGet(self, key) 44 | 45 | proc `[]=`*(self: var GodotDictionary; key, value: GodotVariant) {.inline.} = 46 | getGDNativeAPI().dictionarySet(self, key, value) 47 | 48 | proc mget*(self: var GodotDictionary; 49 | key: GodotVariant): ptr GodotVariant {.inline.} = 50 | getGDNativeAPI().dictionaryOperatorIndex(self, key) 51 | 52 | proc `==`*(self, other: GodotDictionary): bool {.inline.} = 53 | getGDNativeAPI().dictionaryOperatorEqual(self, other) 54 | 55 | proc toJson*(self: GodotDictionary): GodotString {.inline.} = 56 | getGDNativeAPI().dictionaryToJson(self) 57 | -------------------------------------------------------------------------------- /godot/core/planes.nim: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018 Xored Software, Inc. 2 | 3 | import hashes 4 | 5 | import vector3 6 | 7 | import internal/godotinternaltypes, internal/godotstrings 8 | import godotcoretypes, gdnativeapi 9 | 10 | proc initPlane*(a, b, c, d: float32): Plane {.inline.} = 11 | getGDNativeAPI().planeNewWithReals(result, a, b, c, d) 12 | 13 | proc initPlane*(v1, v2, v3: Vector3): Plane {.inline.} = 14 | getGDNativeAPI().planeNewWithVectors(result, v1, v2, v3) 15 | 16 | proc initPlane*(normal: Vector3; d: float32): Plane {.inline.} = 17 | result = Plane( 18 | normal: normal, 19 | d: d 20 | ) 21 | 22 | proc `$`*(self: Plane): string {.inline.} = 23 | $getGDNativeAPI().planeAsString(self) 24 | 25 | proc hash*(self: Plane): Hash {.inline, noinit.} = 26 | !$(self.normal.hash() !& self.d.hash()) 27 | 28 | proc normalized*(self: Plane): Plane {.inline.} = 29 | getGDNativeAPI().planeNormalized(self).toPlane() 30 | 31 | proc center*(self: Plane): Vector3 {.inline.} = 32 | getGDNativeAPI().planeCenter(self).toVector3() 33 | 34 | proc getAnyPoint*(self: Plane): Vector3 {.inline.} = 35 | getGDNativeAPI().planeGetAnyPoint(self).toVector3() 36 | 37 | proc isPointOver*(self: Plane; point: Vector3): bool {.inline.} = 38 | getGDNativeAPI().planeIsPointOver(self, point) 39 | 40 | proc distanceTo*(self: Plane; point: Vector3): float32 {.inline.} = 41 | getGDNativeAPI().planeDistanceTo(self, point) 42 | 43 | proc contains*(self: Plane; point: Vector3; 44 | epsilon: float32): bool {.inline.} = 45 | getGDNativeAPI().planeHasPoint(self, point, epsilon) 46 | 47 | proc project*(self: Plane; point: Vector3): Vector3 {.inline.} = 48 | getGDNativeAPI().planeProject(self, point).toVector3() 49 | 50 | proc intersect3*(self: Plane; dest: var Vector3; 51 | b, c: Plane): bool {.inline.} = 52 | getGDNativeAPI().planeIntersect3(self, dest, b, c) 53 | 54 | proc intersectsRay*(self: Plane; dest: var Vector3; 55 | v, dir: Vector3): bool {.inline.} = 56 | getGDNativeAPI().planeIntersectsRay(self, dest, v, dir) 57 | 58 | proc intersectsSegment*(self: Plane; dest: var Vector3; 59 | segmentBegin, segmentEnd: Vector3): bool {.inline.} = 60 | getGDNativeAPI().planeIntersectsSegment(self, dest, segmentBegin, segmentEnd) 61 | 62 | proc `-`*(self: Plane): Plane {.inline.} = 63 | getGDNativeAPI().planeOperatorNeg(self).toPlane() 64 | 65 | proc `==`*(a, b: Plane): bool {.inline.} = 66 | getGDNativeAPI().planeOperatorEqual(a, b) 67 | -------------------------------------------------------------------------------- /godot/core/quats.nim: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018 Xored Software, Inc. 2 | 3 | import hashes 4 | 5 | import internal/godotinternaltypes, internal/godotstrings 6 | import godotcoretypes, gdnativeapi 7 | 8 | proc initQuat*(x, y, z, w: float32): Quat {.inline.} = 9 | result = Quat( 10 | x: x, 11 | y: y, 12 | z: z, 13 | w: w 14 | ) 15 | 16 | proc initQuat*(axis: Vector3; angle: float32): Quat {.inline.} = 17 | getGDNativeAPI().quatNewWithAxisAngle(result, axis, angle) 18 | 19 | proc `$`*(self: Quat): string {.inline.} = 20 | $getGDNativeAPI().quatAsString(self) 21 | 22 | proc hash*(self: Quat): Hash {.inline.} = 23 | !$(self.x.hash() !& self.y.hash() !& self.z.hash() !& self.w.hash()) 24 | 25 | proc length*(self: Quat): float32 {.inline.} = 26 | getGDNativeAPI().quatLength(self) 27 | 28 | proc lengthSquared*(self: Quat): float32 {.inline.} = 29 | getGDNativeAPI().quatLengthSquared(self) 30 | 31 | proc normalized*(self: Quat): Quat {.inline.} = 32 | getGDNativeAPI().quatNormalized(self).toQuat() 33 | 34 | proc isNormalized*(self: Quat): bool {.inline.} = 35 | getGDNativeAPI().quatIsNormalized(self) 36 | 37 | proc inverse*(self: Quat): Quat {.inline.} = 38 | getGDNativeAPI().quatInverse(self).toQuat() 39 | 40 | proc dot*(a, b: Quat): float32 {.inline.} = 41 | getGDNativeAPI().quatDot(a, b) 42 | 43 | proc xform*(self: Quat; v: Vector3): Vector3 {.inline.} = 44 | getGDNativeAPI().quatXform(self, v).toVector3() 45 | 46 | proc slerp*(self: Quat; b: Quat; t: float32): Quat {.inline.} = 47 | getGDNativeAPI().quatSlerp(self, b, t).toQuat() 48 | 49 | proc slerpni*(self: Quat; b: Quat; t: float32): Quat {.inline.} = 50 | getGDNativeAPI().quatSlerpni(self, b, t).toQuat() 51 | 52 | proc cubicSlerp*(self, b, preA, postB: Quat; 53 | t: float32): Quat {.inline.} = 54 | getGDNativeAPI().quatCubicSlerp(self, b, preA, postB, t).toQuat() 55 | 56 | proc `*`*(a: Quat, b: float32): Quat {.inline.} = 57 | getGDNativeAPI().quatOperatorMultiply(a, b).toQuat() 58 | 59 | proc `*=`*(a: var Quat, b: float32) {.inline.} = 60 | a = a * b 61 | 62 | proc `+`*(a, b: Quat): Quat {.inline.} = 63 | getGDNativeAPI().quatOperatorAdd(a, b).toQuat() 64 | 65 | proc `+=`*(a: var Quat, b: Quat) {.inline.} = 66 | a = a + b 67 | 68 | proc `-`*(a, b: Quat): Quat {.inline.} = 69 | getGDNativeAPI().quatOperatorSubtract(a, b).toQuat() 70 | 71 | proc `-=`* (a: var Quat, b: Quat) {.inline.} = 72 | a = a - b 73 | 74 | proc `/`*(self: Quat; b: float32): Quat {.inline.} = 75 | getGDNativeAPI().quatOperatorDivide(self, b).toQuat() 76 | 77 | proc `/=`*(self: var Quat, b: float32) {.inline.} = 78 | self = self / b 79 | 80 | proc `==`*(a, b: Quat): bool {.inline.} = 81 | getGDNativeAPI().quatOperatorEqual(a, b) 82 | 83 | proc `-`*(self: Quat): Quat {.inline.} = 84 | getGDNativeAPI().quatOperatorNeg(self).toQuat() 85 | -------------------------------------------------------------------------------- /godot/core/colors.nim: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018 Xored Software, Inc. 2 | 3 | import hashes 4 | 5 | import godotcoretypes, gdnativeapi 6 | 7 | proc initColor*(r, g, b: float32; a: float32 = 1.0'f32): Color {.inline.} = 8 | Color( 9 | r: r, 10 | g: g, 11 | b: b, 12 | a: a 13 | ) 14 | 15 | proc initColor*(): Color {.inline.} = 16 | ## Initializes black color with 1.0 alpha 17 | initColor(0, 0, 0) 18 | 19 | proc h*(self: Color): float32 {.inline.} = 20 | getGDNativeAPI().colorGetH(self) 21 | 22 | proc s*(self: Color): float32 {.inline.} = 23 | getGDNativeAPI().colorGetS(self) 24 | 25 | proc v*(self: Color): float32 {.inline.} = 26 | getGDNativeAPI().colorGetV(self) 27 | 28 | proc `$`*(self: Color): string {.inline.} = 29 | result = newStringOfCap(50) 30 | result.add($self.r) 31 | result.add(", ") 32 | result.add($self.g) 33 | result.add(", ") 34 | result.add($self.b) 35 | result.add(", ") 36 | result.add($self.a) 37 | 38 | proc hash*(self: Color): Hash {.inline.} = 39 | !$(self.r.hash() !& self.g.hash() !& self.b.hash() !& self.a.hash()) 40 | 41 | proc toHex(val: float32, target: var string, targetIdx: int) = 42 | let val = clamp(int(val * 255), 0, 255) 43 | let nums = [(val and 0xF0) shr 4, val and 0xF] 44 | for i, num in nums: 45 | target[targetIdx + i] = if num < 10: chr(ord('0') + num) 46 | else: chr(ord('A') + (num - 10)) 47 | 48 | proc toHtml*(self: Color, withAlpha: bool): string = 49 | let size = if withAlpha: 8 else: 6 50 | result = newString(size) 51 | toHex(self.r, result, 0) 52 | toHex(self.g, result, 2) 53 | toHex(self.b, result, 4) 54 | if withAlpha: 55 | toHex(self.b, result, 6) 56 | 57 | proc toARGB32*(self: Color): uint32 {.inline.} = 58 | result = uint8(self.a * 255) 59 | result = (result shl 8) or uint8(self.r * 255) 60 | result = (result shl 8) or uint8(self.g * 255) 61 | result = (result shl 8) or uint8(self.b * 255) 62 | 63 | proc gray*(self: Color): float32 {.inline.} = 64 | getGDNativeAPI().colorGray(self) 65 | 66 | proc inverted*(self: Color): Color {.inline.} = 67 | getGDNativeAPI().colorInverted(self).toColor() 68 | 69 | proc contrasted*(self: Color): Color {.inline.} = 70 | getGDNativeAPI().colorContrasted(self).toColor() 71 | 72 | proc lerp*(self: Color; b: Color; t: float32): Color {.inline.} = 73 | getGDNativeAPI().colorLinearInterpolate(self, b, t).toColor() 74 | 75 | proc blend*(self: Color; over: Color): Color {.inline.} = 76 | getGDNativeAPI().colorBlend(self, over).toColor() 77 | 78 | proc `==`*(a, b: Color): bool {.inline.} = 79 | a.r == b.r and a.g == b.g and a.b == b.b and a.a == b.a 80 | 81 | proc `<`*(a, b: Color): bool = 82 | if a.r == b.r: 83 | if a.g == b.g: 84 | if a.b == b.b: 85 | return a.a < b.a 86 | return a.b < b.b 87 | return a.g < b.g 88 | return a.r < b.r 89 | -------------------------------------------------------------------------------- /godot/core/aabb.nim: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018 Xored Software, Inc. 2 | 3 | import hashes 4 | 5 | import vector3 6 | import internal/godotinternaltypes, internal/godotstrings 7 | import godotcoretypes, gdnativeapi 8 | 9 | proc initAABB*(pos, size: Vector3): AABB {.inline.} = 10 | AABB(position: pos, size: size) 11 | 12 | proc `$`*(self: AABB): string {.inline.} = 13 | $getGDNativeAPI().aabbAsString(self) 14 | 15 | proc hash*(self: AABB): Hash {.inline.} = 16 | !$(self.position.hash() !& self.size.hash()) 17 | 18 | proc area*(self: AABB): float32 {.inline.} = 19 | getGDNativeAPI().aabbGetArea(self) 20 | 21 | proc hasNoArea*(self: AABB): bool {.inline.} = 22 | getGDNativeAPI().aabbHasNoArea(self) 23 | 24 | proc hasNoSurface*(self: AABB): bool {.inline.} = 25 | getGDNativeAPI().aabbHasNoSurface(self) 26 | 27 | proc intersects*(self, other: AABB): bool {.inline.} = 28 | getGDNativeAPI().aabbIntersects(self, other) 29 | 30 | proc encloses*(self, other: AABB): bool {.inline.} = 31 | getGDNativeAPI().aabbEncloses(self, other) 32 | 33 | proc merge*(self, other: AABB): AABB {.inline.} = 34 | getGDNativeAPI().aabbMerge(self, other).toAABB() 35 | 36 | proc intersection*(self, other: AABB): AABB {.inline.} = 37 | getGDNativeAPI().aabbIntersection(self, other).toAABB() 38 | 39 | proc intersectsPlane*(self: AABB; plane: Plane): bool {.inline.} = 40 | getGDNativeAPI().aabbIntersectsPlane(self, plane) 41 | 42 | proc intersectsSegment*(self: AABB; start, to: Vector3): bool {.inline.} = 43 | getGDNativeAPI().aabbIntersectsSegment(self, start, to) 44 | 45 | proc contains*(self: AABB; point: Vector3): bool {.inline.} = 46 | getGDNativeAPI().aabbHasPoint(self, point) 47 | 48 | proc getSupport*(self: AABB; dir: Vector3): Vector3 {.inline.} = 49 | getGDNativeAPI().aabbGetSupport(self, dir).toVector3() 50 | 51 | proc getLongestAxis*(self: AABB): Vector3 {.inline.} = 52 | getGDNativeAPI().aabbGetLongestAxis(self).toVector3() 53 | 54 | proc getLongestAxisIndex*(self: AABB): cint {.inline.} = 55 | getGDNativeAPI().aabbGetLongestAxisIndex(self) 56 | 57 | proc getLongestAxisSize*(self: AABB): float32 {.inline.} = 58 | getGDNativeAPI().aabbGetLongestAxisSize(self) 59 | 60 | proc getShortestAxis*(self: AABB): Vector3 {.inline.} = 61 | getGDNativeAPI().aabbGetShortestAxis(self).toVector3() 62 | 63 | proc getShortestAxisIndex*(self: AABB): cint {.inline.} = 64 | getGDNativeAPI().aabbGetShortestAxisIndex(self) 65 | 66 | proc getShortestAxisSize*(self: AABB): float32 {.inline.} = 67 | getGDNativeAPI().aabbGetShortestAxisSize(self) 68 | 69 | proc expand*(self: AABB; toPoint: Vector3): AABB {.inline.} = 70 | getGDNativeAPI().aabbExpand(self, toPoint).toAABB() 71 | 72 | proc grow*(self: AABB; by: float32): AABB {.inline.} = 73 | getGDNativeAPI().aabbGrow(self, by).toAABB() 74 | 75 | proc getEndpoint*(self: AABB; idx: cint): Vector3 {.inline.} = 76 | getGDNativeAPI().aabbGetEndpoint(self, idx).toVector3() 77 | 78 | proc `==`*(a, b: AABB): bool {.inline.} = 79 | getGDNativeAPI().aabbOperatorEqual(a, b) 80 | -------------------------------------------------------------------------------- /godot/core/godotcoretypes.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Xored Software, Inc. 2 | 3 | type 4 | Color* {.byref.} = object 5 | r*: float32 6 | g*: float32 7 | b*: float32 8 | a*: float32 9 | 10 | Vector3* {.byref.} = object 11 | x*: float32 12 | y*: float32 13 | z*: float32 14 | 15 | Vector2* {.byref.} = object 16 | x*: float32 17 | y*: float32 18 | 19 | Plane* {.byref.} = object 20 | normal*: Vector3 21 | d*: float32 22 | 23 | Basis* {.byref.} = object 24 | elements*: array[3, Vector3] 25 | 26 | Quat* {.byref.} = object 27 | x*: float32 28 | y*: float32 29 | z*: float32 30 | w*: float32 31 | 32 | AABB* {.byref.} = object 33 | position*: Vector3 34 | size*: Vector3 35 | 36 | Rect2* {.byref.} = object 37 | position*: Vector2 38 | size*: Vector2 39 | 40 | Transform2D* {.byref.} = object 41 | elements*: array[3, Vector2] 42 | 43 | Transform* {.byref.} = object 44 | basis*: Basis 45 | origin*: Vector3 46 | 47 | RID* {.byref.} = object 48 | data: array[sizeof(int), byte] 49 | 50 | Error* {.size: sizeof(cint), pure.} = enum 51 | OK, 52 | Failed, ## Generic fail error 53 | Unavailable, ## What is requested is unsupported/unavailable 54 | Unconfigured, ## The object being used hasnt been properly set up yet 55 | Unauthorized, ## Missing credentials for requested resource 56 | ParameterRangeError, ## Parameter given out of range (5) 57 | OutOfMemory, ## Out of memory 58 | FileNotFound, 59 | FileBadDrive, 60 | FileBadPath, 61 | FileNoPermission, ## (10) 62 | FileAlreadyInUse, 63 | FileCantOpen, 64 | FileCantWrite, 65 | FileCantRead, 66 | FileUnrecognized, ## (15) 67 | FileCorrupt, 68 | FileMissingDependencies, 69 | FileEOF, 70 | CantOpen, ## Can't open a resource/socket/file 71 | CantCreate, ## (20) 72 | QueryFailed, 73 | AlreadyInUse, 74 | Locked, ## resource is locked 75 | Timeout, 76 | CantConnect, ## (25) 77 | CantResolve, 78 | ConnectionError, 79 | CantAquireResource, 80 | CantFork, 81 | InvalidData, ## Data passed is invalid (30) 82 | InvalidParameter, ## Parameter passed is invalid 83 | AlreadyExists, ## When adding, item already exists 84 | DoesNotExist, ## When retrieving/erasing, it item does not exist 85 | DatabaseCantRead, ## Database is full 86 | DatabaseCantWrite, ## Database is full (35) 87 | CompilationFailed, 88 | MethodNotFound, 89 | LinkFailed, 90 | ScriptFailed, 91 | CyclicLink, ## (40) 92 | InvalidDeclaration, 93 | DuplicateSymbol, 94 | PauseError, 95 | Busy, 96 | Skip, ## (45) 97 | Help, ## user requested help!! 98 | Bug, 99 | ## a bug in the software certainly happened, due to a double 100 | ## check failing or unexpected behavior. 101 | PrinterOnFire, ## the parallel port printer is engulfed in flames 102 | WTF ## shit happens, has never been used, though 103 | -------------------------------------------------------------------------------- /godot/core/transforms.nim: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018 Xored Software, Inc. 2 | 3 | import hashes 4 | 5 | import internal/godotinternaltypes, internal/godotstrings 6 | import godotcoretypes, gdnativeapi 7 | import basis, vector3 8 | 9 | proc initTransform*(): Transform {.inline.} = 10 | result.basis = initBasis() 11 | 12 | proc initTransform*(xAxis, yAxis, zAxis, 13 | origin: Vector3): Transform {.inline.} = 14 | var basis: Basis 15 | basis.setAxis(0, xAxis) 16 | basis.setAxis(1, yAxis) 17 | basis.setAxis(2, zAxis) 18 | Transform(basis: basis, origin: origin) 19 | 20 | proc initTransform*(basis: Basis, origin: Vector3): Transform {.inline.} = 21 | Transform(basis: basis, origin: origin) 22 | 23 | proc `$`*(self: Transform): string {.inline.} = 24 | $getGDNativeAPI().transformAsString(self) 25 | 26 | proc hash*(self: Transform): Hash {.inline.} = 27 | !$(self.basis.hash() !& self.origin.hash()) 28 | 29 | proc inverse*(self: Transform): Transform {.inline.} = 30 | getGDNativeAPI().transformInverse(self).toTransform() 31 | 32 | proc affineInverse*(self: Transform): Transform {.inline.} = 33 | getGDNativeAPI().transformAffineInverse(self).toTransform() 34 | 35 | proc orthonormalized*(self: Transform): Transform {.inline.} = 36 | getGDNativeAPI().transformOrthonormalized(self).toTransform() 37 | 38 | proc rotated*(self: Transform; axis: Vector3; 39 | phi: float32): Transform {.inline.} = 40 | getGDNativeAPI().transformRotated(self, axis, phi).toTransform() 41 | 42 | proc scaled*(self: Transform; scale: Vector3): Transform {.inline.} = 43 | getGDNativeAPI().transformScaled(self, scale).toTransform() 44 | 45 | proc translated*(self: Transform; offset: Vector3): Transform {.inline.} = 46 | getGDNativeAPI().transformTranslated(self, offset).toTransform() 47 | 48 | proc lookingAt*(self: Transform; target, up: Vector3): Transform {.inline.} = 49 | getGDNativeAPI().transformLookingAt(self, target, up).toTransform() 50 | 51 | proc xformPlane*(self: Transform; plane: Plane): Plane {.inline.} = 52 | getGDNativeAPI().transformXformPlane(self, plane).toPlane() 53 | 54 | proc xformInvPlane*(self: Transform; plane: Plane): Plane {.inline.} = 55 | getGDNativeAPI().transformXformInvPlane(self, plane).toPlane() 56 | 57 | proc xformVector3*(self: Transform; v: Vector3): Vector3 {.inline.} = 58 | getGDNativeAPI().transformXformVector3(self, v).toVector3() 59 | 60 | proc xformInvVector3*(self: Transform; v: Vector3): Vector3 {.inline.} = 61 | getGDNativeAPI().transformXformInvVector3(self, v).toVector3() 62 | 63 | proc xformAABB*(self: Transform; rect: AABB): AABB {.inline.} = 64 | getGDNativeAPI().transformXformAABB(self, rect).toAABB() 65 | 66 | proc xformInvAABB*(self: Transform; rect: AABB): AABB {.inline.} = 67 | getGDNativeAPI().transformXformInvAABB(self, rect).toAABB() 68 | 69 | proc `==`*(self: Transform; b: Transform): bool {.inline.} = 70 | getGDNativeAPI().transformOperatorEqual(self, b) 71 | 72 | proc `*`*(self, other: Transform): Transform {.inline.} = 73 | getGDNativeAPI().transformOperatorMultiply(self, other).toTransform() 74 | 75 | proc `*=`*(self: var Transform, other: Transform) {.inline.} = 76 | self = self * other 77 | -------------------------------------------------------------------------------- /godot/core/transform2d.nim: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018 Xored Software, Inc. 2 | 3 | import hashes, vector2 4 | 5 | import internal/godotinternaltypes, internal/godotstrings 6 | import godotcoretypes, gdnativeapi 7 | 8 | proc initTransform2D*(): Transform2D {.inline.} = 9 | getGDNativeAPI().transform2DNewIdentity(result) 10 | 11 | proc initTransform2D*(rot: float32; pos: Vector2): Transform2D {.inline.} = 12 | getGDNativeAPI().transform2DNew(result, rot, pos) 13 | 14 | proc initTransform2D*(xAxis, yAxis, origin: Vector2): Transform2D {.inline.} = 15 | getGDNativeAPI().transform2DNewAxisOrigin(result, xAxis, yAxis, origin) 16 | 17 | proc `$`*(self: Transform2D): string {.inline.} = 18 | $getGDNativeAPI().transform2DAsString(self) 19 | 20 | proc hash*(self: Transform2D): Hash {.inline, noinit.} = 21 | !$(self.elements[0].hash() !& self.elements[1].hash() !& self.elements[2].hash()) 22 | 23 | proc inverse*(self: Transform2D): Transform2D {.inline.} = 24 | getGDNativeAPI().transform2DInverse(self).toTransform2D() 25 | 26 | proc affineInverse*(self: Transform2D): Transform2D {.inline.} = 27 | getGDNativeAPI().transform2DAffineInverse(self).toTransform2D() 28 | 29 | proc rotation*(self: Transform2D): float32 {.inline.} = 30 | getGDNativeAPI().transform2DGetRotation(self) 31 | 32 | proc origin*(self: Transform2D): Vector2 {.inline.} = 33 | getGDNativeAPI().transform2DGetOrigin(self).toVector2() 34 | 35 | proc scale*(self: Transform2D): Vector2 {.inline.} = 36 | getGDNativeAPI().transform2DGetScale(self).toVector2() 37 | 38 | proc orthonormalized*(self: Transform2D): Transform2D {.inline.} = 39 | getGDNativeAPI().transform2DOrthonormalized(self).toTransform2D() 40 | 41 | proc rotated*(self: Transform2D; phi: float32): Transform2D {.inline.} = 42 | getGDNativeAPI().transform2DRotated(self, phi).toTransform2D() 43 | 44 | proc scaled*(self: Transform2D; scale: Vector2): Transform2D {.inline.} = 45 | getGDNativeAPI().transform2DScaled(self, scale).toTransform2D() 46 | 47 | proc translated*(self: Transform2D; offset: Vector2): Transform2D {.inline.} = 48 | getGDNativeAPI().transform2DTranslated(self, offset).toTransform2D() 49 | 50 | proc xformVector2*(self: Transform2D; v: Vector2): Vector2 {.inline.} = 51 | getGDNativeAPI().transform2DXformVector2(self, v).toVector2() 52 | 53 | proc xformInvVector2*(self: Transform2D; v: Vector2): Vector2 {.inline.} = 54 | getGDNativeAPI().transform2DXformInvVector2(self, v).toVector2() 55 | 56 | proc basisXformVector2*(self: Transform2D; v: Vector2): Vector2 {.inline.} = 57 | getGDNativeAPI().transform2DBasisXformVector2(self, v).toVector2() 58 | 59 | proc basisXformInvVector2*(self: Transform2D; v: Vector2): Vector2 {.inline.} = 60 | getGDNativeAPI().transform2DBasisXformInvVector2(self, v).toVector2() 61 | 62 | proc xformRect2*(self: Transform2D; rect: Rect2): Rect2 {.inline.} = 63 | getGDNativeAPI().transform2DXformRect2(self, rect).toRect2() 64 | 65 | proc xformInvRect2*(self: Transform2D; rect: Rect2): Rect2 {.inline.} = 66 | getGDNativeAPI().transform2DXformInvRect2(self, rect).toRect2() 67 | 68 | proc interpolateWith*(self, m: Transform2D; 69 | c: float32): Transform2D {.inline.} = 70 | getGDNativeAPI().transform2DInterpolateWith(self, m, c).toTransform2D() 71 | 72 | proc `==`*(a, b: Transform2D): bool {.inline.} = 73 | getGDNativeAPI().transform2DOperatorEqual(a, b) 74 | 75 | proc `*`*(a, b: Transform2D): Transform2D {.inline.} = 76 | getGDNativeAPI().transform2DOperatorMultiply(a, b).toTransform2D() 77 | 78 | proc `*=`*(a: var Transform2D, b: Transform2D) {.inline.} = 79 | a = a * b 80 | -------------------------------------------------------------------------------- /docs/docpublish.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Xored Software, Inc. 2 | 3 | import os, pegs, strutils 4 | import docbuild 5 | 6 | const indexTemplate = """ 7 | godot-nim docs index 8 | 9 |

Documentation of Nim bindings for Godot Engine (GitHub)


10 | $VERSION_LIST 11 | 12 | 13 | """ 14 | 15 | proc execOrQuit(cmd: string) = 16 | let ret = execShellCmd(cmd) 17 | if ret != 0: 18 | quit(ret) 19 | 20 | proc walkDirRecRelative(dir: string, cb: proc (file: string), start = "") = 21 | for kind, path in walkDir(dir, relative = true): 22 | if kind in {pcFile, pcLinkToFile}: 23 | cb(if start.len > 0: start / path else: path) 24 | elif kind in {pcDir, pcLinkToDir}: 25 | let fullPath = if start.len > 0: start / path else: path 26 | walkDirRecRelative(dir / fullPath, cb, fullPath) 27 | 28 | proc publish(docDir, gitHubToken, repoSlug, branch, tag, changeset: string) = 29 | let release = if branch == "master": branch else: tag 30 | let commitComment = if release == "master": 31 | "Update master documentation for changeset " & changeset 32 | else: 33 | "Update documentation for " & tag 34 | 35 | const repoDir = "gh-pages" 36 | execOrQuit( 37 | "git clone --depth=1 --branch=gh-pages https://github.com/$#.git $#" % 38 | [repoSlug, repoDir]) 39 | try: 40 | removeDir(repoDir/release) 41 | createDir(repoDir/release) 42 | var versionList = newStringOfCap(4096) 43 | for kind, path in walkDir(repoDir, relative = true): 44 | if kind == pcDir and not path.startsWith("."): 45 | versionList.add("$1
" % path) 46 | let index = indexTemplate.replace("$REPO_SLUG", repoSlug). 47 | replace("$VERSION_LIST", versionList) 48 | writeFile(repoDir/"index.html", index) 49 | 50 | walkDirRecRelative(docDir) do (file: string): 51 | createDir(parentDir(repoDir/release/file)) 52 | copyFile(docDir/file, repoDir/release/file) 53 | 54 | setCurrentDir(repoDir) 55 | try: 56 | execOrQuit("git add --all") 57 | execOrQuit("git commit -m \"$#\"" % commitComment) 58 | execOrQuit("git push -fq \"https://$#@github.com/$#.git\" gh-pages" % 59 | [gitHubToken, repoSlug]) 60 | finally: 61 | setCurrentDir("..") 62 | finally: 63 | removeDir(repoDir) 64 | 65 | when isMainModule: 66 | proc getEnvOrQuit(key: string): string = 67 | result = getEnv(key) 68 | if result.len == 0: 69 | echo "Expected environment variable: " & key 70 | quit(1) 71 | 72 | let pr = getEnv("TRAVIS_PULL_REQUEST") 73 | if pr.len > 0 and pr != "false": 74 | echo "This is a PR build. Skipping." 75 | quit(0) 76 | 77 | let repoSlug = getEnvOrQuit("TRAVIS_REPO_SLUG") 78 | let branch = getEnvOrQuit("TRAVIS_BRANCH") 79 | let changeset = getEnvOrQuit("TRAVIS_COMMIT") 80 | let tag = getEnv("TRAVIS_TAG") 81 | 82 | # let repoSlug = "pragmagic/godot-nim" 83 | # let branch = "master" 84 | # let changeset = "0fd0101432c1fed1004f50b035fcf74f75f004a8" 85 | # let tag = "" 86 | 87 | let gitHubToken = getEnvOrQuit("GITHUB_TOKEN") 88 | 89 | if branch != "master" and not (tag =~ peg"^ 'v' \d+ '.' \d+ '.' \d+ $"): 90 | echo "This is not master or tagged changeset. Skipping." 91 | quit(0) 92 | 93 | let godotBin = getEnvOrQuit("GODOT_BIN") 94 | 95 | const docDir = "docgen" 96 | buildDocs(docDir, getCurrentDir(), godotBin) 97 | publish(docDir, gitHubToken, repoSlug, branch, tag, changeset) 98 | -------------------------------------------------------------------------------- /godot/core/dictionaries.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Xored Software, Inc. 2 | 3 | import hashes 4 | import internal/godotinternaltypes, internal/godotdictionaries, 5 | internal/godotvariants, internal/godotstrings 6 | 7 | type 8 | Dictionary* = ref object 9 | godotDictionary: GodotDictionary 10 | 11 | proc dictionaryFinalizer(dict: Dictionary) = 12 | dict.godotDictionary.deinit() 13 | 14 | proc newDictionary*(): Dictionary {.inline.} = 15 | new(result, dictionaryFinalizer) 16 | initGodotDictionary(result.godotDictionary) 17 | 18 | proc newDictionary*(dict: GodotDictionary): Dictionary {.inline.} = 19 | new(result, dictionaryFinalizer) 20 | result.godotDictionary = dict 21 | 22 | proc godotDictionary*(dict: Dictionary): ptr GodotDictionary = 23 | ## WARNING: do not keep the returned value for longer than the lifetime of 24 | ## ``dict`` 25 | addr dict.godotDictionary 26 | 27 | proc len*(self: Dictionary): int {.inline.} = 28 | self.godotDictionary.len.int 29 | 30 | proc isEmpty*(self: Dictionary): bool {.inline.} = 31 | self.godotDictionary.isEmpty() 32 | 33 | proc clear*(self: Dictionary) {.inline.} = 34 | self.godotDictionary.clear() 35 | 36 | proc hash*(self: Dictionary): Hash {.inline.} = 37 | hash(self.godotDictionary.godotHash()) 38 | 39 | import variants, arrays 40 | 41 | proc newVariant*(dict: Dictionary): Variant {.inline.} = 42 | new(result, variantFinalizer) 43 | initGodotVariant(result.godotVariant[], dict.godotDictionary) 44 | 45 | proc asDictionary*(self: Variant): Dictionary {.inline.} = 46 | newDictionary(self.godotVariant[].asGodotDictionary()) 47 | 48 | proc contains*(self: Dictionary; key: Variant): bool {.inline.}= 49 | self.godotDictionary.contains(key.godotVariant[]) 50 | 51 | proc contains*(self: Dictionary; keys: Array): bool {.inline.} = 52 | self.godotDictionary.contains(keys.godotArray[]) 53 | 54 | proc del*(self: Dictionary; key: Variant) {.inline.} = 55 | self.godotDictionary.del(key.godotVariant[]) 56 | 57 | proc keys*(self: Dictionary): Array {.inline.} = 58 | newArray(self.godotDictionary.keys()) 59 | 60 | proc values*(self: Dictionary): Array {.inline.} = 61 | newArray(self.godotDictionary.values()) 62 | 63 | proc `[]`*(self: Dictionary; key: Variant): Variant {.inline.} = 64 | newVariant(self.godotDictionary[key.godotVariant[]]) 65 | 66 | proc `[]`*(self: Dictionary; keyStr: string): Variant {.inline.} = 67 | var godotVariant: GodotVariant 68 | var godotStr = keyStr.toGodotString() 69 | initGodotVariant(godotVariant, godotStr) 70 | result = newVariant(self.godotDictionary[godotVariant]) 71 | godotStr.deinit() 72 | godotVariant.deinit() 73 | 74 | proc `[]=`*(self: Dictionary; key, value: Variant) {.inline.} = 75 | self.godotDictionary[key.godotVariant[]] = value.godotVariant[] 76 | 77 | proc `==`*(self, other: Dictionary): bool {.inline.} = 78 | if self.isNil and other.isNil: return true 79 | if self.isNil != other.isNil: return false 80 | result = self.godotDictionary == other.godotDictionary 81 | 82 | proc toJson*(self: Dictionary): string {.inline.} = 83 | var s = self.godotDictionary.toJson() 84 | result = $s 85 | s.deinit() 86 | 87 | iterator keys*(dict: Dictionary): Variant = 88 | let keyArr = dict.keys() 89 | for key in keyArr: 90 | yield key 91 | 92 | iterator values*(dict: Dictionary): Variant = 93 | let valArr = dict.values() 94 | for val in valArr: 95 | yield val 96 | 97 | iterator pairs*(dict: Dictionary): tuple[key, val: Variant] = 98 | for key in keys(dict): 99 | yield (key, dict[key]) 100 | 101 | proc `$`*(self: Dictionary): string = 102 | result = newStringOfCap(32) 103 | result.add('{') 104 | for k, v in self: 105 | if result.len > 1: 106 | result.add(", ") 107 | result.add($k) 108 | result.add(": ") 109 | result.add($v) 110 | result.add('}') 111 | -------------------------------------------------------------------------------- /godot/core/arrays.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Xored Software, Inc. 2 | 3 | import hashes 4 | import internal/godotinternaltypes, internal/godotarrays 5 | 6 | type 7 | Array* = ref object 8 | godotArray: GodotArray 9 | 10 | proc godotArray*(arr: Array): ptr GodotArray {.inline.} = 11 | ## WARNING: do not keep the returned value for longer than the lifetime of 12 | ## ``arr`` 13 | addr arr.godotArray 14 | 15 | proc arrayFinalizer(arr: Array) = 16 | arr.godotArray.deinit() 17 | 18 | proc newArray*(arr: GodotArray): Array {.inline.} = 19 | new(result, arrayFinalizer) 20 | result.godotArray = arr 21 | 22 | import variants 23 | 24 | proc newArray*(s: varargs[Variant]): Array = 25 | new(result, arrayFinalizer) 26 | initGodotArray(result.godotArray) 27 | for v in s: 28 | result.godotArray.add(v.godotVariant[]) 29 | 30 | proc newArray*(s: openarray[Variant]): Array = 31 | result = newArray() 32 | for v in s: 33 | result.godotArray.add(v.godotVariant[]) 34 | 35 | import poolarrays 36 | 37 | proc newArray*(pca: PoolColorArray): Array {.inline.} = 38 | new(result, arrayFinalizer) 39 | initGodotArray(result.godotArray, pca.godotPoolColorArray[]) 40 | 41 | proc newArray*(pv3a: PoolVector3Array): Array {.inline.} = 42 | new(result, arrayFinalizer) 43 | initGodotArray(result.godotArray, pv3a.godotPoolVector3Array[]) 44 | 45 | proc newArray*(pv2a: PoolVector2Array): Array {.inline.} = 46 | new(result, arrayFinalizer) 47 | initGodotArray(result.godotArray, pv2a.godotPoolVector2Array[]) 48 | 49 | proc newArray*(psa: PoolStringArray): Array {.inline.} = 50 | new(result, arrayFinalizer) 51 | initGodotArray(result.godotArray, psa.godotPoolStringArray[]) 52 | 53 | proc newArray*(pra: PoolRealArray): Array {.inline.} = 54 | new(result, arrayFinalizer) 55 | initGodotArray(result.godotArray, pra.godotPoolRealArray[]) 56 | 57 | proc newArray*(pia: PoolIntArray): Array {.inline.} = 58 | new(result, arrayFinalizer) 59 | initGodotArray(result.godotArray, pia.godotPoolIntArray[]) 60 | 61 | proc newArray*(pba: PoolByteArray): Array {.inline.} = 62 | new(result, arrayFinalizer) 63 | initGodotArray(result.godotArray, pba.godotPoolByteArray[]) 64 | 65 | proc `[]=`*(self: Array; idx: int; value: Variant) {.inline.} = 66 | self.godotArray[idx.cint] = value.godotVariant[] 67 | 68 | proc `[]`*(self: Array; idx: int): Variant {.inline.} = 69 | newVariant(self.godotArray[idx.cint]) 70 | 71 | proc add*(self: Array; value: Variant) {.inline.} = 72 | self.godotArray.add(value.godotVariant[]) 73 | 74 | proc clear*(self: Array) {.inline.} = 75 | self.godotArray.clear() 76 | 77 | proc count*(self: Array; value: Variant): int {.inline.} = 78 | self.godotArray.count(value.godotVariant[]).int 79 | 80 | proc isEmpty*(self: Array): bool {.inline.} = 81 | self.godotArray.isEmpty() 82 | 83 | proc erase*(self: Array; value: Variant) {.inline.} = 84 | self.godotArray.erase(value.godotVariant[]) 85 | 86 | proc first*(self: Array): Variant {.inline.} = 87 | newVariant(self.godotArray.first()) 88 | 89 | proc last*(self: Array): Variant {.inline.} = 90 | newVariant(self.godotArray.last()) 91 | 92 | proc find*(self: Array; what: Variant; f: int): int {.inline.} = 93 | self.godotArray.find(what.godotVariant[], f.cint).int 94 | 95 | proc findLast*(self: Array; what: Variant): int {.inline.} = 96 | self.godotArray.findLast(what.godotVariant[]).int 97 | 98 | proc contains*(self: Array; value: Variant): bool {.inline.} = 99 | self.godotArray.contains(value.godotVariant[]) 100 | 101 | proc hash*(self: Array): Hash {.inline.} = 102 | hash(self.godotArray.godotHash()) 103 | 104 | proc insert*(self: Array; pos: int; value: Variant) {.inline.} = 105 | self.godotArray.insert(pos.cint, value.godotVariant[]) 106 | 107 | proc reverse*(self: Array) {.inline.} = 108 | self.godotArray.reverse() 109 | 110 | proc popLast*(self: Array): Variant {.inline.} = 111 | newVariant(self.godotArray.popLast()) 112 | 113 | proc popFirst*(self: Array): Variant {.inline.} = 114 | newVariant(self.godotArray.popFirst()) 115 | 116 | proc addLast*(self: Array; value: Variant) {.inline.} = 117 | self.godotArray.addLast(value.godotVariant[]) 118 | 119 | proc addFirst*(self: Array; value: Variant) {.inline.} = 120 | self.godotArray.addFirst(value.godotVariant[]) 121 | 122 | proc delete*(self: Array; idx: int) {.inline.} = 123 | self.godotArray.delete(idx.cint) 124 | 125 | proc setLen*(self: Array; size: int) {.inline.} = 126 | self.godotArray.setLen(size.cint) 127 | 128 | proc rfind*(self: Array; what: Variant; fromIdx: int): int {.inline.} = 129 | self.godotArray.rfind(what.godotVariant[], fromIdx.cint).int 130 | 131 | proc len*(self: Array): int {.inline.} = 132 | self.godotArray.len.int 133 | 134 | proc sort*(self: Array) {.inline.} = 135 | self.godotArray.sort() 136 | 137 | iterator items*(self: Array): Variant = 138 | for i in 0..= (b.position.x + b.size.x): 31 | return false 32 | if a.position.x + a.size.x <= b.position.x: 33 | return false 34 | if a.position.y >= (b.position.y + b.size.y): 35 | return false 36 | if a.position.y + a.size.y <= b.position.y: 37 | return false 38 | result = true 39 | 40 | proc distanceTo*(self: Rect2, p: Vector2): float32 {.noinit.} = 41 | var inside = true 42 | if p.x < self.position.x: 43 | let d = self.position.x - p.x 44 | result = d 45 | inside = false 46 | if p.y < self.position.y: 47 | let d = self.position.y - p.y 48 | result = if inside: d else: min(result, d) 49 | inside = false 50 | if p.x >= (self.position.x + self.size.x): 51 | let d = p.x - (self.position.x + self.size.x) 52 | result = if inside: d else: min(result, d) 53 | inside = false 54 | if p.y >= (self.position.y + self.size.y): 55 | let d = p.y - (self.position.y + self.size.y) 56 | result = if inside: d else: min(result, d) 57 | inside = false 58 | 59 | if inside: 60 | result = 0'f32 61 | 62 | proc encloses*(a, b: Rect2): bool {.inline, noinit.} = 63 | b.position.x >= a.position.x and b.position.y >= a.position.y and 64 | (b.position.x + b.size.x) < (a.position.x + a.size.x) and 65 | (b.position.y + b.size.y) < (a.position.y + a.size.y) 66 | 67 | proc hasNoArea*(self: Rect2): bool {.inline, noinit.} = 68 | self.size.x <= 0 or self.size.y <= 0 69 | 70 | proc clip*(self, b: Rect2): Rect2 {.inline, noinit.} = 71 | if not self.intersects(b): 72 | return initRect2() 73 | 74 | result = self 75 | 76 | result.position.x = max(b.position.x, self.position.x) 77 | result.position.y = max(b.position.y, self.position.y) 78 | 79 | let bEnd = b.position + b.size 80 | let selfEnd = self.position + self.size 81 | 82 | result.size.x = min(bEnd.x, selfEnd.x) - result.position.x 83 | result.size.y = min(bEnd.y, selfEnd.y) - result.position.y 84 | 85 | proc merge*(self, b: Rect2): Rect2 {.inline, noinit.} = 86 | result.position.x = min(b.position.x, self.position.x) 87 | result.position.y = min(b.position.y, self.position.y) 88 | 89 | result.size.x = max(b.position.x + b.size.x, self.position.x + self.size.x) 90 | result.size.y = max(b.position.y + b.size.y, self.position.y + self.size.y) 91 | result.size -= result.position 92 | 93 | proc contains*(self: Rect2; point: Vector2): bool {.inline, noinit.} = 94 | if point.x < self.position.x: 95 | return false 96 | if point.y < self.position.y: 97 | return false 98 | 99 | if point.x >= self.position.x + self.size.x: 100 | return false 101 | if point.y >= self.position.y + self.size.y: 102 | return false 103 | 104 | result = true 105 | 106 | proc grow*(self: Rect2; by: float32): Rect2 {.inline, noinit.} = 107 | ## Returns Rect2 enlarged by the specified size in every direction. 108 | result = self 109 | 110 | result.position.x -= by 111 | result.position.y -= by 112 | 113 | result.size.x += by * 2 114 | result.size.y += by * 2 115 | 116 | proc growIndividual*(self: Rect2, left, top: float32, 117 | right, bottom: float32): Rect2 {.inline, noinit.} = 118 | result = self 119 | result.position.x -= left 120 | result.position.y -= top 121 | result.size.x += left + right 122 | result.size.y += top + bottom 123 | 124 | proc expandTo*(self: var Rect2, to: Vector2) {.inline.} = 125 | var startPoint = self.position 126 | var endPoint = self.position + self.size 127 | 128 | if to.x < startPoint.x: 129 | startPoint.x = to.x 130 | if to.y < startPoint.y: 131 | startPoint.y = to.y 132 | 133 | if to.x > endPoint.x: 134 | endPoint.x = to.x 135 | if to.y > endPoint.y: 136 | endPoint.y = to.y 137 | 138 | self.position = startPoint 139 | self.size = endPoint - startPoint 140 | 141 | proc expand*(self: Rect2; to: Vector2): Rect2 {.inline, noinit.} = 142 | result = self 143 | result.expandTo(to) 144 | 145 | proc abs*(self: Rect2): Rect2 {.inline, noinit.} = 146 | Rect2(position: vec2(self.position.x + min(self.size.x, 0'f32), 147 | self.position.y + min(self.size.y, 0'f32)), 148 | size: abs(self.size)) 149 | 150 | proc `==`*(a, b: Rect2): bool {.inline, noinit.} = 151 | a.position == b.position and a.size == b.size 152 | 153 | {.pop.} # stackTrace: off -------------------------------------------------------------------------------- /godot/godotinternal.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Xored Software, Inc. 2 | 3 | import internal/godotinternaltypes, internal/godotarrays, 4 | internal/godotnodepaths, internal/godotpoolarrays, internal/godotstrings, 5 | internal/godotvariants, internal/godotdictionaries 6 | 7 | import gdnativeapi 8 | export godotinternaltypes, godotarrays, godotnodepaths, godotpoolarrays, 9 | godotstrings, godotvariants, godotdictionaries 10 | 11 | proc getMethod*(className: cstring; 12 | methodName: cstring): ptr GodotMethodBind {.inline.} = 13 | getGDNativeAPI().methodBindGetMethod(className, methodName) 14 | 15 | proc ptrCall*(methodBind: ptr GodotMethodBind; 16 | instance: ptr GodotObject; 17 | args: ptr array[MAX_ARG_COUNT, pointer]; 18 | ret: pointer) {.inline.} = 19 | getGDNativeAPI().methodBindPtrCall(methodBind, instance, args, ret) 20 | 21 | proc call*(methodBind: ptr GodotMethodBind; 22 | instance: ptr GodotObject; 23 | args: ptr array[MAX_ARG_COUNT, ptr GodotVariant]; argCount: cint; 24 | callError: var VariantCallError): GodotVariant {.inline.} = 25 | getGDNativeAPI().methodBindCall( 26 | methodBind, instance, args, argCount, callError) 27 | 28 | proc nativeScriptRegisterClass*(libHandle: pointer; name, base: cstring; 29 | createFunc: GodotInstanceCreateFunc; 30 | destroyFunc: GodotInstanceDestroyFunc) 31 | {.inline.} = 32 | getGDNativeAPI().nativeScriptRegisterClass( 33 | libHandle, name, base, createFunc, destroyFunc) 34 | 35 | proc nativeScriptRegisterToolClass*(libHandle: pointer; name, base: cstring; 36 | createFunc: GodotInstanceCreateFunc; 37 | destroyFunc: GodotInstanceDestroyFunc) 38 | {.inline.} = 39 | getGDNativeAPI().nativeScriptRegisterToolClass( 40 | libHandle, name, base, createFunc, destroyFunc) 41 | 42 | proc nativeScriptRegisterMethod*(libHandle: pointer; 43 | name: cstring; function_name: cstring; 44 | attr: GodotMethodAttributes; 45 | meth: GodotInstanceMethod) {.inline.} = 46 | getGDNativeAPI().nativeScriptRegisterMethod( 47 | libHandle, name, functionName, attr, meth) 48 | 49 | proc nativeScriptRegisterProperty*(libHandle: pointer; 50 | name, path: cstring; 51 | attr: ptr GodotPropertyAttributes; 52 | setFunc: GodotPropertySetFunc; 53 | getFunc: GodotPropertyGetFunc) {.inline.} = 54 | getGDNativeAPI().nativeScriptRegisterProperty( 55 | libHandle, name, path, attr, setFunc, getFunc) 56 | 57 | proc nativeScriptRegisterSignal*(libHandle: pointer; name: cstring; 58 | signal: GodotSignal) {.inline.} = 59 | getGDNativeAPI().nativeScriptRegisterSignal(libHandle, name, signal) 60 | 61 | proc getUserdata*(instance: ptr GodotObject): pointer {.inline.} = 62 | getGDNativeAPI().nativeScriptGetUserdata(instance) 63 | 64 | proc getClassConstructor*(className: cstring): GodotClassConstructor 65 | {.inline.} = 66 | getGDNativeAPI().getClassConstructor(className) 67 | 68 | proc deinit*(o: ptr GodotObject) {.inline.} = 69 | getGDNativeAPI().objectDestroy(o) 70 | 71 | # print using Godot's error handler list 72 | 73 | proc godotPrintError*(description, function, file: cstring; 74 | line: cint) {.inline.} = 75 | getGDNativeAPI().printError(description, function, file, line) 76 | 77 | proc godotPrintWarning*(description, function, file: cstring; 78 | line: cint) {.inline.} = 79 | getGDNativeAPI().printWarning(description, function, file, line) 80 | 81 | proc godotPrint*(message: GodotString) {.inline.} = 82 | getGDNativeAPI().print(message) 83 | 84 | var getClassMethodBind: ptr GodotMethodBind 85 | proc getClassName*(o: ptr GodotObject): string = 86 | if getClassMethodBind.isNil: 87 | getClassMethodBind = getMethod(cstring"Object", cstring"get_class") 88 | var ret: GodotString 89 | getClassMethodBind.ptrCall(o, nil, addr ret) 90 | result = $ret 91 | deinit(ret) 92 | if result.len > 2 and result[^2] == 'S' and result[^1] == 'W': 93 | # There are physics type not known by ClassDB 94 | result = result[0..result.len-3] 95 | 96 | proc getClassNameRaw*(o: ptr GodotObject): GodotString = 97 | if getClassMethodBind.isNil: 98 | getClassMethodBind = getMethod(cstring"Object", cstring"get_class") 99 | getClassMethodBind.ptrCall(o, nil, addr result) 100 | 101 | proc getGodotSingleton*(name: cstring): ptr GodotObject {.inline.} = 102 | getGDNativeAPI().globalGetSingleton(name) 103 | 104 | # System Functions 105 | 106 | proc godotAlloc*(bytes: cint): pointer {.inline.} = 107 | ## Allocates the specified number of bytes. 108 | ## Using this instead of stdlib proc will help Godot track how much memory 109 | ## is in use in debug mode. 110 | getGDNativeAPI().alloc(bytes) 111 | 112 | proc godotRealloc*(p: pointer; bytes: cint): pointer {.inline.} = 113 | ## Reallocates the pointer for the specified number of bytes. 114 | ## Using this instead of stdlib proc will help Godot track how much memory 115 | ## is in use in debug mode. 116 | getGDNativeAPI().realloc(p, bytes) 117 | 118 | proc godotFree*(p: pointer) {.inline.} = 119 | ## Frees the memory pointed to by the pointer. 120 | ## Using this instead of stdlib proc will help Godot track how much memory 121 | ## is in use in debug mode. 122 | getGDNativeAPI().free(p) 123 | -------------------------------------------------------------------------------- /docs/docbuild.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Xored Software, Inc. 2 | 3 | import threadpool, os, osproc, strutils, sequtils, pegs 4 | 5 | import "../godot/godotapigen.nim" 6 | 7 | const dirs = ["godot"/"core", "godot"/"internal", "godot"/"nim"] 8 | const files = ["godot"/"godotapigen.nim", "godot"/"godotinternal.nim", 9 | "godot"/"godot.nim"] 10 | const indexFile = "docs"/"index.rst" 11 | const gitHubUrl = "https://github.com/pragmagic/godot-nim" 12 | 13 | proc outName(outDir, file: string): string = 14 | outDir / file.extractFilename().changeFileExt("html") 15 | 16 | template quoted(s: string): string = 17 | ('"' & s & '"') 18 | 19 | proc execOrFail(cmd: string) = 20 | echo "[exec] " & cmd 21 | let ret = execShellCmd(cmd) 22 | if ret != 0: 23 | raise newException( 24 | Exception, "Command quit with exit code " & $ret & ": " & cmd) 25 | 26 | template withDir(dir: string, body: typed) = 27 | let curDir = getCurrentDir() 28 | setCurrentDir(dir) 29 | try: 30 | body 31 | finally: 32 | setCurrentDir(curDir) 33 | 34 | iterator walkDirRec(dir: string, filter: set[PathComponent], 35 | extensions: openarray[string]): string = 36 | for file in walkDirRec(dir, filter): 37 | if not extensions.anyIt(file.endsWith(it)): continue 38 | yield file 39 | 40 | proc genApiFiles(targetDir, godotBin: string) = 41 | let jsonFile = targetDir / "api.json" 42 | try: 43 | execOrFail(quoted(godotBin) & 44 | " --gdnative-generate-json-api " & quoted(jsonFile)) 45 | except: 46 | # this fails unstably even if api.json is created successfully 47 | discard 48 | if not fileExists(jsonFile): 49 | raise newException(Exception, "Failed to generate Godot API wrappers") 50 | 51 | genApi(targetDir, jsonFile) 52 | 53 | writeFile(targetDir / "nim.cfg", "path=\"$projectdir/../../godot\"") 54 | 55 | proc extractVersion(nimbleFile: string): string = 56 | let contents = readFile(nimbleFile) 57 | var matches: array[1, string] 58 | doAssert match(contents, peg"""'version' \s* '=' \s* '"' {@} '"' """, matches) 59 | result = matches[0] 60 | 61 | proc fixupHrefs(file: string) = 62 | var contents = readFile(file) 63 | contents = contents.replacef( 64 | peg"""'href="' ('internal'/'core'/'nim') '/' {@} '"' """, 65 | "href=\"$#\"") 66 | if file.contains("godotapi"): 67 | contents = contents.replacef( 68 | peg"""'href="' {('godotinternal' / 'godot') '.html"'} """, 69 | "href=\"../$#") 70 | writeFile(file, contents) 71 | 72 | proc getGitHash(): string = 73 | result = execProcess("git rev-parse HEAD") 74 | if result.len > 0: 75 | result = result.replace("\L", "").replace("\r", "") 76 | 77 | proc buildDocs*(outDir, godotNimDir, godotBin: string) = 78 | removeDir(outDir) 79 | createDir(outDir) 80 | let outDirAbs = expandFilename(outDir) 81 | let godotBinAbs = expandFilename(godotBin) 82 | 83 | setCurrentDir(godotNimDir) 84 | 85 | let godotNimVersion = extractVersion("godot.nimble") 86 | putEnv("godotnimversion", godotNimVersion) 87 | putEnv("godotnimgithub", gitHubUrl) 88 | let gitCommit = getGitHash() 89 | 90 | var allNimFiles = newSeq[string]() 91 | allNimFiles.add(files) 92 | for dir in dirs: 93 | for file in walkDirRec(dir, {pcFile, pcDir}, [".nim"]): 94 | allNimFiles.add(file) 95 | for file in allNimFiles: 96 | spawn execOrFail( 97 | "nim doc -d:useRealtimeGc --path:godot -o:" & 98 | quoted(outName(outDirAbs, file)) & 99 | " --git.url:" & quoted(gitHubUrl) & 100 | " --git.commit:" & quoted(gitCommit) & 101 | ' ' & quoted(file)) 102 | 103 | let godotApiFolder = outDirAbs / "godotapi" 104 | createDir(godotApiFolder) 105 | genApiFiles(godotApiFolder, godotBinAbs) 106 | for file in walkDirRec(godotApiFolder, {pcFile, pcDir}, [".nim"]): 107 | spawn execOrFail("nim doc -d:useRealtimeGc --path:godot -o:" & 108 | quoted(outName(godotApiFolder, file)) & ' ' & quoted(file)) 109 | 110 | sync() 111 | 112 | var gitHash: string 113 | withDir(godotBinAbs.parentDir()): 114 | gitHash = getGitHash() 115 | if gitHash.len == 0: 116 | raise newException(Exception, 117 | "Godot executable is not under Git repository") 118 | 119 | var indexContent = readFile(indexFile) 120 | var apiList = newStringOfCap(4096) 121 | for file in walkDirRec(godotApiFolder, {pcFile, pcDir}): 122 | if not file.endsWith(".html"): 123 | removeFile(file) 124 | else: 125 | let moduleHtml = file.extractFileName() 126 | let moduleName = moduleHtml.changeFileExt("") 127 | apiList.add("* `" & moduleName & " `_\L") 128 | indexContent = indexContent.replace("$GODOTAPI_CHANGESET_HASH", gitHash). 129 | replace("$AUTO_GENERATED_GODOTAPI_LIST", apiList). 130 | replace("$GODOTNIM_GITHUB_URL", gitHubUrl) 131 | 132 | let tmpRst = outDirAbs/"index.rst" 133 | writeFile(tmpRst, indexContent) 134 | try: 135 | execOrFail("nim rst2html -o:" & quoted(outName(outDirAbs, tmpRst)) & 136 | ' ' & quoted(tmpRst)) 137 | finally: 138 | removeFile(tmpRst) 139 | 140 | for file in walkDirRec(outDir, {pcFile, pcDir}, [".html"]): 141 | spawn fixupHrefs(file) 142 | 143 | sync() 144 | 145 | when isMainModule: 146 | const outDir = "docgen" 147 | 148 | if not fileExists("godot.nimble"): 149 | echo "Must be executed from godot-nim root dir" 150 | quit(-1) 151 | 152 | let godotBin = getEnv("GODOT_BIN") 153 | if godotBin.len == 0: 154 | echo "GODOT_BIN environment variable must point to Godot executable" 155 | quit(-1) 156 | 157 | try: 158 | buildDocs(outDir, getCurrentDir(), godotBin) 159 | except: 160 | echo getCurrentExceptionMsg() 161 | quit(-1) 162 | -------------------------------------------------------------------------------- /godot/internal/godotarrays.nim: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018 Xored Software, Inc. 2 | 3 | import godotinternaltypes, gdnativeapi, core/godotcoretypes 4 | 5 | proc len*(self: GodotArray): cint {.inline.} = 6 | getGDNativeAPI().arraySize(self) 7 | 8 | import hashes 9 | 10 | proc initGodotArray*(dest: var GodotArray) {.inline.} = 11 | getGDNativeAPI().arrayNew(dest) 12 | 13 | proc initGodotArray*(dest: var GodotArray; 14 | pca: GodotPoolColorArray) {.inline.} = 15 | getGDNativeAPI().arrayNewPoolColorArray(dest, pca) 16 | 17 | proc initGodotArray*(dest: var GodotArray; 18 | pv3a: GodotPoolVector3Array) {.inline.} = 19 | getGDNativeAPI().arrayNewPoolVector3Array(dest, pv3a) 20 | 21 | proc initGodotArray*(dest: var GodotArray; 22 | pv2a: GodotPoolVector2Array) {.inline.} = 23 | getGDNativeAPI().arrayNewPoolVector2Array(dest, pv2a) 24 | 25 | proc initGodotArray*(dest: var GodotArray; 26 | psa: GodotPoolStringArray) {.inline.} = 27 | getGDNativeAPI().arrayNewPoolStringArray(dest, psa) 28 | 29 | proc initGodotArray*(dest: var GodotArray; 30 | pra: GodotPoolRealArray) {.inline.} = 31 | getGDNativeAPI().arrayNewPoolRealArray(dest, pra) 32 | 33 | proc initGodotArray*(dest: var GodotArray; 34 | pia: GodotPoolIntArray) {.inline.} = 35 | getGDNativeAPI().arrayNewPoolIntArray(dest, pia) 36 | 37 | proc initGodotArray*(dest: var GodotArray; 38 | pba: GodotPoolByteArray) {.inline.} = 39 | getGDNativeAPI().arrayNewPoolByteArray(dest, pba) 40 | 41 | proc initGodotArray*(dest: var GodotArray; src: GodotArray) {.inline.} = 42 | getGDNativeAPI().arrayNewCopy(dest, src) 43 | 44 | proc deinit*(self: var GodotArray) {.inline.} = 45 | getGDNativeAPI().arrayDestroy(self) 46 | 47 | proc `[]=`*(self: var GodotArray; idx: cint; value: GodotVariant) {.inline.} = 48 | getGDNativeAPI().arraySet(self, idx, value) 49 | 50 | proc `[]`*(self: GodotArray; idx: cint): GodotVariant {.inline.} = 51 | getGDNativeAPI().arrayGet(self, idx) 52 | 53 | proc mget*(self: var GodotArray; idx: cint): ptr GodotVariant {.inline.} = 54 | getGDNativeAPI().arrayOperatorIndex(self, idx) 55 | 56 | proc add*(self: var GodotArray; value: GodotVariant) {.inline.} = 57 | getGDNativeAPI().arrayPushBack(self, value) 58 | 59 | proc clear*(self: var GodotArray) {.inline.} = 60 | getGDNativeAPI().arrayClear(self) 61 | 62 | proc count*(self: GodotArray; value: GodotVariant): cint {.inline.} = 63 | getGDNativeAPI().arrayCount(self, value) 64 | 65 | proc isEmpty*(self: GodotArray): bool {.inline.} = 66 | getGDNativeAPI().arrayEmpty(self) 67 | 68 | proc erase*(self: var GodotArray; value: GodotVariant) {.inline.} = 69 | getGDNativeAPI().arrayErase(self, value) 70 | 71 | proc first*(self: GodotArray): GodotVariant {.inline.} = 72 | getGDNativeAPI().arrayFront(self) 73 | 74 | proc last*(self: GodotArray): GodotVariant {.inline.} = 75 | getGDNativeAPI().arrayBack(self) 76 | 77 | proc find*(self: GodotArray; what: GodotVariant; 78 | fromIdx: cint): cint {.inline.} = 79 | getGDNativeAPI().arrayFind(self, what, fromIdx) 80 | 81 | proc findLast*(self: GodotArray; what: GodotVariant): cint {.inline.} = 82 | getGDNativeAPI().arrayFindLast(self, what) 83 | 84 | proc contains*(self: GodotArray; value: GodotVariant): bool {.inline.} = 85 | getGDNativeAPI().arrayHas(self, value) 86 | 87 | proc godotHash*(self: GodotArray): cint {.inline.} = 88 | getGDNativeAPI().arrayHash(self) 89 | 90 | proc hash*(self: GodotArray): Hash {.inline.} = 91 | hash(godotHash(self)) 92 | 93 | proc insert*(self: var GodotArray; pos: cint; 94 | value: GodotVariant): Error {.discardable, inline.} = 95 | getGDNativeAPI().arrayInsert(self, pos, value) 96 | 97 | proc reverse*(self: var GodotArray) {.inline.} = 98 | getGDNativeAPI().arrayInvert(self) 99 | 100 | proc popLast*(self: var GodotArray): GodotVariant {.inline.} = 101 | getGDNativeAPI().arrayPopBack(self) 102 | 103 | proc popFirst*(self: var GodotArray): GodotVariant {.inline.} = 104 | getGDNativeAPI().arrayPopFront(self) 105 | 106 | proc addLast*(self: var GodotArray; value: GodotVariant) {.inline.} = 107 | getGDNativeAPI().arrayPushBack(self, value) 108 | 109 | proc addFirst*(self: var GodotArray; value: GodotVariant) {.inline.} = 110 | getGDNativeAPI().arrayPushFront(self, value) 111 | 112 | proc delete*(self: var GodotArray; idx: cint) {.inline.} = 113 | getGDNativeAPI().arrayRemove(self, idx) 114 | 115 | proc setLen*(self: var GodotArray; size: cint) {.inline.} = 116 | getGDNativeAPI().arrayResize(self, size) 117 | 118 | proc rfind*(self: GodotArray; what: GodotVariant; 119 | fromIdx: cint): cint {.inline.} = 120 | getGDNativeAPI().arrayRFind(self, what, fromIdx) 121 | 122 | proc sort*(self: var GodotArray) {.inline.} = 123 | getGDNativeAPI().arraySort(self) 124 | 125 | proc sortCustom*(self: var GodotArray; obj: ptr GodotObject; 126 | funcName: GodotString) {.inline.} = 127 | getGDNativeAPI().arraySortCustom(self, obj, funcName) 128 | 129 | proc binarySearch*(self: var GodotArray, val: ptr GodotVariant, 130 | before: bool) {.inline.} = 131 | getGDNativeAPI().arrayBSearch(self, val, before) 132 | 133 | proc binarySearchCustom*(self: var GodotArray, val: ptr GodotVariant, 134 | obj: ptr GodotObject, funcName: GodotString, 135 | before: bool) {.inline.} = 136 | getGDNativeAPI().arrayBSearchCustom(self, val, obj, funcName, before) 137 | 138 | iterator items*(self: GodotArray): GodotVariant = 139 | for i in 0.cint.. 1: 160 | result.add(", ") 161 | result.add($item) 162 | result.add(']') 163 | -------------------------------------------------------------------------------- /godot/core/poolarrays.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Xored Software, Inc. 2 | 3 | import hashes 4 | 5 | import godotcoretypes 6 | import internal/godotinternaltypes, internal/godotpoolarrays, 7 | internal/godotstrings 8 | import vector2, vector3, colors 9 | 10 | template definePoolArrayBase(T, GodotT, DataT, fieldName, newProcName, 11 | initProcName) = 12 | type 13 | T* = ref object 14 | fieldName: GodotT 15 | 16 | proc poolArrayFinalizer(arr: T) = 17 | arr.fieldName.deinit() 18 | 19 | proc newProcName*(): T {.inline.} = 20 | new(result, poolArrayFinalizer) 21 | initProcName(result.fieldName) 22 | 23 | proc fieldName*(self: T): ptr GodotT {.inline.} = 24 | ## WARNING: do not keep the returned value for longer than the lifetime of 25 | ## the array. 26 | addr self.fieldName 27 | 28 | proc newProcName*(arr: GodotT): T {.inline.} = 29 | new(result, poolArrayFinalizer) 30 | result.fieldName = arr 31 | 32 | proc hash*(arr: T): Hash = 33 | for item in arr.fieldName.items(): 34 | result = result !& 35 | (when type(item) is GodotString: ($item).hash() else: item.hash()) 36 | result = !$result 37 | 38 | definePoolArrayBase(PoolByteArray, GodotPoolByteArray, uint8, 39 | godotPoolByteArray, newPoolByteArray, 40 | initGodotPoolByteArray) 41 | definePoolArrayBase(PoolIntArray, GodotPoolIntArray, cint, 42 | godotPoolIntArray, newPoolIntArray, 43 | initGodotPoolIntArray) 44 | definePoolArrayBase(PoolRealArray, GodotPoolRealArray, float32, 45 | godotPoolRealArray, newPoolRealArray, 46 | initGodotPoolRealArray) 47 | definePoolArrayBase(PoolVector2Array, GodotPoolVector2Array, Vector2, 48 | godotPoolVector2Array, newPoolVector2Array, 49 | initGodotPoolVector2Array) 50 | definePoolArrayBase(PoolVector3Array, GodotPoolVector3Array, Vector3, 51 | godotPoolVector3Array, newPoolVector3Array, 52 | initGodotPoolVector3Array) 53 | definePoolArrayBase(PoolColorArray, GodotPoolColorArray, Color, 54 | godotPoolColorArray, newPoolColorArray, 55 | initGodotPoolColorArray) 56 | definePoolArrayBase(PoolStringArray, GodotPoolStringArray, string, 57 | godotPoolStringArray, newPoolStringArray, 58 | initGodotPoolStringArray) 59 | 60 | import arrays 61 | 62 | template definePoolArray(T, GodotT, DataT, fieldName, newProcName, initProcName; 63 | noData = false) = 64 | 65 | proc newProcName*(arr: Array): T {.inline.} = 66 | new(result, poolArrayFinalizer) 67 | initProcName(result.fieldName, arr.godotArray[]) 68 | 69 | proc add*(self: T; arr: T) {.inline.} = 70 | self.fieldName.add(arr.fieldName) 71 | 72 | proc delete*(self: T; idx: int) {.inline.} = 73 | self.fieldName.delete(idx.cint) 74 | 75 | proc reverse*(self: T) {.inline.} = 76 | self.fieldName.reverse() 77 | 78 | proc setLen*(self: T; size: int) {.inline.} = 79 | self.fieldName.setLen(size.cint) 80 | 81 | proc len*(self: T): int {.inline.} = 82 | self.fieldName.len.int 83 | 84 | proc subarray*(self: T, idxFrom, idxTo: int): T {.inline.} = 85 | ## Indexes are inclusive, negative values count from the end of the array. 86 | assert(idxFrom >= low(cint) and idxFrom <= high(cint) and 87 | idxTo >= low(cint) and idxTo <= high(cint)) 88 | newProcName(self.fieldName.subarray(idxFrom.cint, idxTo.cint)) 89 | 90 | when not noData: 91 | proc add*(self: T; data: DataT) {.inline.} = 92 | self.fieldName.add(data) 93 | 94 | proc insert*(self: T; idx: int; data: DataT): Error {.inline.} = 95 | self.fieldName.insert(idx.cint, data) 96 | 97 | proc `[]=`*(self: T; idx: int; data: DataT) {.inline.} = 98 | self.fieldName[idx.cint] = data 99 | 100 | proc `[]`*(self: T; idx: int): DataT {.inline.} = 101 | self.fieldName[idx.cint] 102 | 103 | iterator items*(arr: T): DataT = 104 | for item in arr.fieldName.items: 105 | yield item 106 | 107 | iterator pairs*(arr: T): tuple[key: int, val: DataT] = 108 | for pair in arr.fieldName.pairs: 109 | yield (pair[0].int, pair[1]) 110 | 111 | iterator mitems*(arr: T): var DataT = 112 | for item in arr.fieldName.mitems: 113 | yield item 114 | 115 | iterator mpairs*(arr: T): tuple[key: int, val: var DataT] = 116 | for pair in arr.fieldName.mpairs: 117 | yield (pair[0].int, pair[1]) 118 | 119 | definePoolArray(PoolByteArray, GodotPoolByteArray, uint8, 120 | godotPoolByteArray, newPoolByteArray, 121 | initGodotPoolByteArray) 122 | definePoolArray(PoolIntArray, GodotPoolIntArray, cint, 123 | godotPoolIntArray, newPoolIntArray, 124 | initGodotPoolIntArray) 125 | definePoolArray(PoolRealArray, GodotPoolRealArray, float32, 126 | godotPoolRealArray, newPoolRealArray, 127 | initGodotPoolRealArray) 128 | definePoolArray(PoolVector2Array, GodotPoolVector2Array, Vector2, 129 | godotPoolVector2Array, newPoolVector2Array, 130 | initGodotPoolVector2Array) 131 | definePoolArray(PoolVector3Array, GodotPoolVector3Array, Vector3, 132 | godotPoolVector3Array, newPoolVector3Array, 133 | initGodotPoolVector3Array) 134 | definePoolArray(PoolColorArray, GodotPoolColorArray, Color, 135 | godotPoolColorArray, newPoolColorArray, 136 | initGodotPoolColorArray) 137 | definePoolArray(PoolStringArray, GodotPoolStringArray, string, 138 | godotPoolStringArray, newPoolStringArray, 139 | initGodotPoolStringArray, true) 140 | 141 | proc add*(self: PoolStringArray; data: string) = 142 | var s = data.toGodotString() 143 | self.godotPoolStringArray.add(s) 144 | s.deinit() 145 | 146 | proc insert*(self: PoolStringArray; idx: int; data: string): Error = 147 | var s = data.toGodotString() 148 | result = self.godotPoolStringArray.insert(idx.cint, s) 149 | s.deinit() 150 | 151 | proc `[]=`*(self: PoolStringArray; idx: int; data: string) = 152 | var s = data.toGodotString() 153 | self.godotPoolStringArray[idx.cint] = s 154 | s.deinit() 155 | 156 | proc `[]`*(self: PoolStringArray; idx: int): string = 157 | var s = self.godotPoolStringArray[idx.cint] 158 | result = $s 159 | s.deinit() 160 | 161 | iterator items*(arr: PoolStringArray): string = 162 | for i in 0..`*(self, other: Vector2): bool {.inline, noinit.} = 78 | if self.x == other.x: 79 | self.y > other.y 80 | else: 81 | self.x > other.x 82 | 83 | proc `-`*(self: Vector2): Vector2 {.inline, noinit.} = 84 | Vector2(x: -self.x, y: -self.y) 85 | 86 | proc length*(self: Vector2): float32 {.inline, noinit.} = 87 | sqrt(self.x * self.x + self.y * self.y) 88 | 89 | proc lengthSquared*(self: Vector2): float32 {.inline, noinit.} = 90 | self.x * self.x + self.y * self.y 91 | 92 | proc normalize*(self: var Vector2) {.inline.} = 93 | var len = self.x * self.x + self.y * self.y 94 | if len != 0: 95 | len = sqrt(len) 96 | self.x /= len 97 | self.y /= len 98 | 99 | proc normalized*(self: Vector2): Vector2 {.inline, noinit.} = 100 | result = self 101 | result.normalize() 102 | 103 | proc angle*(self: Vector2): float32 {.inline, noinit.} = 104 | arctan2(self.y, self.x) 105 | 106 | proc isNormalized*(self: Vector2): bool {.inline, noinit.} = 107 | isEqualApprox(self.lengthSquared(), 1.0) 108 | 109 | proc distanceTo*(self, to: Vector2): float32 {.inline, noinit.} = 110 | sqrt((self.x - to.x) * (self.x - to.x) + (self.y - to.y) * (self.y - to.y)) 111 | 112 | proc distanceSquaredTo*(self, to: Vector2): float32 {.inline, noinit.} = 113 | (self.x - to.x) * (self.x - to.x) + (self.y - to.y) * (self.y - to.y) 114 | 115 | proc dot*(a, b: Vector2): float32 {.inline, noinit.} = 116 | a.x * b.x + a.y * b.y 117 | 118 | proc cross*(a, b: Vector2): float32 {.inline, noinit.} = 119 | a.x * b.y - a.y * b.x 120 | 121 | proc cross*(self: Vector2, scalar: float32): Vector2 {.inline, noinit.} = 122 | Vector2(x: scalar * self.y, y: -scalar * self.x) 123 | 124 | proc angleTo*(self, to: Vector2): float32 {.noinit.} = 125 | arctan2(cross(self, to), dot(self, to)) 126 | 127 | proc angleToPoint*(self, to: Vector2): float32 {.inline, noinit.} = 128 | arctan2(self.y - to.y, self.x - to.x) 129 | 130 | proc floor*(self: Vector2): Vector2 {.inline, noinit.} = 131 | Vector2(x: floor(self.x), y: floor(self.y)) 132 | 133 | proc planeProject*(self: Vector2, d: float32, 134 | vec: Vector2): Vector2 {.noinit.} = 135 | vec - self * (self.dot(vec) - d) 136 | 137 | proc project*(self, other: Vector2): Vector2 {.noinit.} = 138 | self * (other.dot(self) / self.dot(self)) 139 | 140 | proc lerp*(self, b: Vector2; t: float32): Vector2 {.inline, noinit.} = 141 | result = self 142 | result.x += t * (b.x - self.x) 143 | result.y += t * (b.y - self.y) 144 | 145 | proc cubicInterpolate*(self, b, preA, postB: Vector2; 146 | t: float32): Vector2 {.noinit.} = 147 | let p0 = preA 148 | let p1 = self 149 | let p2 = b 150 | let p3 = postB 151 | 152 | let t2 = t * t 153 | let t3 = t2 * t 154 | 155 | result = 0.5'f32 * ((p1 * 2.0'f32)) + 156 | (-p0 + p2) * t + 157 | (2.0 * p0 - 5.0 * p1 + 4 * p2 - p3) * t2 + 158 | (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3 159 | 160 | proc setRotation*(self: var Vector2, radians: float32) {.inline, noinit.} = 161 | self.x = cos(radians) 162 | self.y = sin(radians) 163 | 164 | proc rotated*(self: Vector2; phi: float32): Vector2 {.inline, noinit.} = 165 | result.setRotation(phi) 166 | result *= self.length() 167 | 168 | proc tangent*(self: Vector2): Vector2 {.inline, noinit.} = 169 | Vector2(x: self.y, y: -self.x) 170 | 171 | proc snapped*(self: Vector2; by: Vector2): Vector2 {.inline, noinit.} = 172 | Vector2(x: stepify(self.x, by.x), y: stepify(self.y, by.y)) 173 | 174 | proc aspect*(self: Vector2): float32 {.inline, noinit.} = 175 | self.x / self.y 176 | 177 | proc slide*(self, n: Vector2): Vector2 {.noinit.} = 178 | when not defined(release): 179 | if not n.isNormalized(): 180 | printError("Normal not normalized in slide. " & getStackTrace()) 181 | return vec2() 182 | result = self - n * self.dot(n) 183 | 184 | proc reflect*(self, n: Vector2): Vector2 {.noinit.} = 185 | when not defined(release): 186 | if not n.isNormalized(): 187 | printError("Normal not normalized in bounce. " & getStackTrace()) 188 | return vec2() 189 | result = 2.0 * n * self.dot(n) - self 190 | 191 | proc bounce*(self, n: Vector2): Vector2 {.inline, noinit.} = 192 | -self.reflect(n) 193 | 194 | proc abs*(self: Vector2): Vector2 {.inline, noinit.} = 195 | Vector2(x: abs(self.x), y: abs(self.y)) 196 | 197 | proc clamped*(self: Vector2; length: float32): Vector2 {.noinit.} = 198 | let len = self.length() 199 | result = self 200 | if len > 0 and length < len: 201 | result /= len 202 | result *= length 203 | 204 | proc moveToward*(vFrom, to: Vector2, delta: float32): Vector2 = 205 | let 206 | vd = to - vFrom 207 | vLen = vd.length 208 | 209 | if vLen <= delta or vLen < EPSILON: 210 | result = to 211 | else: 212 | result = vFrom + (vd / vLen) * delta 213 | 214 | {.pop.} # stackTrace: off 215 | -------------------------------------------------------------------------------- /godot/core/vector3.nim: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018 Xored Software, Inc. 2 | 3 | import math, hashes 4 | import godotbase, godotcoretypes 5 | 6 | const EPSILON = 0.00001'f32 7 | 8 | {.push stackTrace: off.} 9 | 10 | proc vec3*(): Vector3 {.inline.} = 11 | Vector3() 12 | 13 | proc vec3*(x, y, z: float32): Vector3 {.inline.} = 14 | Vector3(x: x, y: y, z: z) 15 | 16 | proc `$`*(self: Vector3): string {.inline.} = 17 | result = newStringOfCap(40) 18 | result.add('(') 19 | result.add($self.x) 20 | result.add(", ") 21 | result.add($self.y) 22 | result.add(", ") 23 | result.add($self.z) 24 | result.add(')') 25 | 26 | proc hash*(self: Vector3): Hash {.inline, noinit.} = 27 | !$(self.x.hash() !& self.y.hash() !& self.z.hash()) 28 | 29 | proc `+`*(a, b: Vector3): Vector3 {.inline.} = 30 | result.x = a.x + b.x 31 | result.y = a.y + b.y 32 | result.z = a.z + b.z 33 | 34 | proc `+=`*(a: var Vector3, b: Vector3) {.inline.} = 35 | a.x += b.x 36 | a.y += b.y 37 | a.z += b.z 38 | 39 | proc `-`*(a, b: Vector3): Vector3 {.inline.} = 40 | result.x = a.x - b.x 41 | result.y = a.y - b.y 42 | result.z = a.z - b.z 43 | 44 | proc `-=`*(a: var Vector3, b: Vector3) {.inline.} = 45 | a.x -= b.x 46 | a.y -= b.y 47 | a.z -= b.z 48 | 49 | proc `*`*(a, b: Vector3): Vector3 {.inline.} = 50 | result.x = a.x * b.x 51 | result.y = a.y * b.y 52 | result.z = a.z * b.z 53 | 54 | proc `*=`*(a: var Vector3, b: Vector3) {.inline.}= 55 | a.x *= b.x 56 | a.y *= b.y 57 | a.z *= b.z 58 | 59 | proc `*`*(a: Vector3; b: float32): Vector3 {.inline.} = 60 | result.x = a.x * b 61 | result.y = a.y * b 62 | result.z = a.z * b 63 | 64 | proc `*`*(b: float32; a: Vector3): Vector3 {.inline.} = 65 | a * b 66 | 67 | proc `*=`*(a: var Vector3; b: float32) {.inline.} = 68 | a.x *= b 69 | a.y *= b 70 | a.z *= b 71 | 72 | proc `/`*(a, b: Vector3): Vector3 = 73 | result.x = a.x / b.x 74 | result.y = a.y / b.y 75 | result.z = a.z / b.z 76 | 77 | proc `/=`*(a: var Vector3; b: Vector3) {.inline.} = 78 | a.x /= b.x 79 | a.y /= b.y 80 | a.z /= b.z 81 | 82 | proc `/`*(a: Vector3; b: float32): Vector3 = 83 | result.x = a.x / b 84 | result.y = a.y / b 85 | result.z = a.z / b 86 | 87 | proc `/=`*(a: var Vector3; b: float32) {.inline.} = 88 | a.x /= b 89 | a.y /= b 90 | a.z /= b 91 | 92 | proc `==`*(a, b: Vector3): bool {.inline.} = 93 | a.x == b.x and a.y == b.y and a.z == b.z 94 | 95 | proc `<`*(a, b: Vector3): bool = 96 | if a.x == b.x: 97 | if a.y == b.y: 98 | return a.z < b.z 99 | return a.y < b.y 100 | return a.x < b.x 101 | 102 | proc `-`*(self: Vector3): Vector3 = 103 | result.x = -self.x 104 | result.y = -self.y 105 | result.z = -self.z 106 | 107 | proc `[]`*(self: Vector3, idx: range[0..2]): float32 {.inline.} = 108 | cast[array[3, float32]](self)[idx] 109 | 110 | proc `[]`*(self: var Vector3, idx: range[0..2]): var float32 {.inline.} = 111 | cast[ptr array[3, float32]](addr self)[][idx] 112 | 113 | proc `[]=`*(self: var Vector3, idx: range[0..2], 114 | val: float32) {.inline.} = 115 | case idx: 116 | of 0: self.x = val 117 | of 1: self.y = val 118 | of 2: self.z = val 119 | 120 | proc minAxis*(self: Vector3): int {.inline.} = 121 | if self.x < self.y: 122 | if self.x < self.z: 0 else: 2 123 | else: 124 | if self.y < self.z: 1 else: 2 125 | 126 | proc maxAxis*(self: Vector3): int {.inline.} = 127 | if self.x < self.y: 128 | if self.y < self.z: 2 else: 1 129 | else: 130 | if self.x < self.z: 2 else: 0 131 | 132 | proc length*(self: Vector3): float32 {.inline.} = 133 | let x2 = self.x * self.x 134 | let y2 = self.y * self.y 135 | let z2 = self.z * self.z 136 | 137 | result = sqrt(x2 + y2 + z2) 138 | 139 | proc lengthSquared*(self: Vector3): float32 {.inline.} = 140 | let x2 = self.x * self.x 141 | let y2 = self.y * self.y 142 | let z2 = self.z * self.z 143 | 144 | result = x2 + y2 + z2 145 | 146 | proc normalize*(self: var Vector3) {.inline.} = 147 | let len = self.length() 148 | if len == 0: 149 | self.x = 0 150 | self.y = 0 151 | self.z = 0 152 | else: 153 | self.x /= len 154 | self.y /= len 155 | self.z /= len 156 | 157 | proc normalized*(self: Vector3): Vector3 {.inline.} = 158 | result = self 159 | result.normalize() 160 | 161 | proc isNormalized*(self: Vector3): bool {.inline.} = 162 | self.lengthSquared().isEqualApprox(1.0'f32) 163 | 164 | proc zero*(self: var Vector3) {.inline.} = 165 | self.x = 0 166 | self.y = 0 167 | self.z = 0 168 | 169 | proc inverse*(self: Vector3): Vector3 {.inline.} = 170 | vec3(1.0'f32 / self.x, 1.0'f32 / self.y, 1.0'f32 / self.z) 171 | 172 | proc cross*(self, other: Vector3): Vector3 {.inline.} = 173 | vec3( 174 | self.y * other.z - self.z * other.y, 175 | self.z * other.x - self.x * other.z, 176 | self.x * other.y - self.y * other.x) 177 | 178 | proc dot*(self, other: Vector3): float32 {.inline.} = 179 | self.x * other.x + self.y * other.y + self.z * other.z 180 | 181 | proc abs*(self: Vector3): Vector3 {.inline.} = 182 | vec3(abs(self.x), abs(self.y), abs(self.z)) 183 | 184 | proc sign*(self: Vector3): Vector3 {.inline.} = 185 | vec3(sign(self.x), sign(self.y), sign(self.z)) 186 | 187 | proc floor*(self: Vector3): Vector3 {.inline.} = 188 | vec3(floor(self.x), floor(self.y), floor(self.z)) 189 | 190 | proc ceil*(self: Vector3): Vector3 {.inline.} = 191 | vec3(ceil(self.x), ceil(self.y), ceil(self.z)) 192 | 193 | proc lerp*(self: Vector3, other: Vector3, t: float32): Vector3 {.inline.} = 194 | vec3( 195 | self.x + t * (other.x - self.x), 196 | self.y + t * (other.y - self.y), 197 | self.z + t * (other.z - self.z) 198 | ) 199 | 200 | proc distanceTo*(self, other: Vector3): float32 {.inline.} = 201 | (other - self).length() 202 | 203 | proc distanceSquaredTo*(self, other: Vector3): float32 {.inline.} = 204 | (other - self).lengthSquared() 205 | 206 | proc angleTo*(self, other: Vector3): float32 {.inline.} = 207 | arctan2(self.cross(other).length(), self.dot(other)) 208 | 209 | proc slide*(self, n: Vector3): Vector3 {.inline.} = 210 | assert(n.isNormalized()) 211 | result = self - n * self.dot(n) 212 | 213 | proc reflect*(self, n: Vector3): Vector3 {.inline.} = 214 | assert(n.isNormalized()) 215 | result = 2.0'f32 * n * self.dot(n) - self 216 | 217 | proc bounce*(self, n: Vector3): Vector3 {.inline.} = 218 | -self.reflect(n) 219 | 220 | proc snap*(self: var Vector3, other: Vector3) = 221 | self.x = stepify(self.x, other.x) 222 | self.y = stepify(self.y, other.y) 223 | self.z = stepify(self.z, other.z) 224 | 225 | proc snapped*(self: Vector3, other: Vector3): Vector3 = 226 | result = self 227 | result.snap(other) 228 | 229 | proc cubicInterpolate*(self, b, preA, postB: Vector3; 230 | t: float32): Vector3 = 231 | let p0 = preA 232 | let p1 = self 233 | let p2 = b 234 | let p3 = postB 235 | 236 | let t2 = t * t 237 | let t3 = t2 * t 238 | 239 | result = 0.5 * ((p1 * 2.0) + 240 | (-p0 + p2) * t + 241 | (2.0 * p0 - 5.0 * p1 + 4 * p2 - p3) * t2 + 242 | (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3) 243 | 244 | proc moveToward*(vFrom, to: Vector3, delta: float32): Vector3 = 245 | let 246 | vd = to - vFrom 247 | vLen = vd.length 248 | 249 | if vLen <= delta or vLen < EPSILON: 250 | result = to 251 | else: 252 | result = vFrom + (vd / vLen) * delta 253 | 254 | {.pop.} # stackTrace: off -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | ============================= 2 | Nim bindings for Godot Engine 3 | ============================= 4 | 5 | :Author: Ruslan Mustakov 6 | :Version: |godotnimversion| 7 | :GitHub: `$GODOTNIM_GITHUB_URL <$GODOTNIM_GITHUB_URL>`_ 8 | :License: MIT 9 | 10 | .. contents:: 11 | 12 | ``godot-nim`` library allows to create games on 13 | `Godot Engine `_ with 14 | `Nim programming language `_. Nim is a statically typed 15 | language with an elegant Python-like syntax that compiles to native code. 16 | It is garbage-collected, but its GC supports real-time mode which this library 17 | makes use of. It means the GC will never run during game frames and will use 18 | fixed amount of frame idle time to collect garbage. This leads to no stalls 19 | and close to zero compromise on performance comparing to native languages with 20 | manual memory management. 21 | 22 | If you are not familiar with Nim yet, it is recommended to go through the 23 | `official tutorial `_. 24 | 25 | `VSCode `_ is the recommended editor for 26 | working with Nim code. It is cross-platform and has the excellent 27 | `nim plugin `_ 28 | that supports most of the features you would expect from an IDE. 29 | It also has `godot-tools plugin `_ 30 | which adds features for editing GDScript and Godot resource files. 31 | 32 | 33 | Getting Started 34 | =============== 35 | 36 | Getting Godot 37 | -------------- 38 | 39 | The library requires Godot version 3.0, which you can get here: 40 | https://godotengine.org/download 41 | 42 | Installing Nim 43 | ------------- 44 | 45 | The library requires Nim version 0.18.0 or newer, which you can get here: 46 | https://nim-lang.org/install.html 47 | 48 | Make sure you also have ``nimble`` (Nim's package manager) installed. 49 | 50 | Creating Project 51 | ---------------- 52 | 53 | The fastest way to set up a Godot-Nim project is to use the existing stub: 54 | 55 | .. code-block:: bash 56 | git clone --depth=1 https://github.com/pragmagic/godot-nim-stub.git myproject 57 | 58 | (you can then delete the .git directory within to untie the project from the 59 | stub repository) 60 | 61 | The stub contains the necessary build configuration to compile your code for 62 | desktop and mobile platforms, as well as a couple of very simple scenes to 63 | help you get started. Consult the stub's `README 64 | `_ for information about 65 | compiling the project. 66 | 67 | 68 | Adding Nim to Existing Project 69 | ------------------------------ 70 | 71 | If you would like to use Nim in an existing project: 72 | 73 | 1. Copy ``nakefile.nim`` file and ``src`` directory from the stub described 74 | in the previous section above your Godot project folder. Adjust paths in 75 | build scripts (``nakefile.nim``, ``src/stub.nimble``) according to your 76 | own project structure. 77 | 78 | 2. Copy ``nimlib.gdnlib`` to your Godot project folder. It is a 79 | GDNative library resource that contains paths to dynamic libraries 80 | compiled by Nim. 81 | 82 | Next Steps 83 | ---------- 84 | 85 | Once you are familiarized with the build process (it's as simple as running 86 | ``nake build`` after you are set up), it is recommended to go through 87 | `godotmacros `_ and `godotnim `_ module 88 | documentations. They describe special macros and procedures needed to define 89 | or instantiate Godot objects. After you learned that, the rest is similar to 90 | using any Nim library. These bindings do not limit any of Nim's capabilities, 91 | and you can use any Nim types as fields or parameters of Godot objects and 92 | their procedures (but, obviously, you may not be able to export some of them 93 | to Godot editor or GDScript, unless you define your own converters). 94 | 95 | 96 | Modules 97 | ======= 98 | 99 | The binding library consists of three major modules: 100 | 101 | * `godot <#modules-godot-module>`_ - Contains core types and macro definitions. 102 | You need to import this in any module that defines or makes use of Godot 103 | types. 104 | 105 | * `godotinternal <#modules-godotinternal-module>`_ - Contains raw wrappers over 106 | few core types, such as ``GodotVariant``, ``GodotString``, ``GodotNodePath``, 107 | ``GodotDictionary``, pool arrays. These are used by ``godotapigen`` and macro 108 | implementations, and you don't have to use them at all in your code, unless 109 | you want to go into low-level details for some reason. Each of those types 110 | needs to be destructed manually with ``deinit`` procedure. 111 | 112 | * `godotapigen `_ - Wrapper generator based on data from 113 | Godot's ``ClassDB``. You only need to use it as a part of the build process. 114 | 115 | 116 | godot Module 117 | ------------ 118 | 119 | Contains core types and macro definitions. You need to import this in any 120 | module that defines or makes use of Godot types. The sumbodules below are 121 | exported and you don't have to import any of them directly. 122 | 123 | * `godotnim `_ Defines ``NimGodotObject`` and Varaint converters 124 | for standard Nim types. 125 | * `godotmacros `_ Defines ``gdobj`` macro for defining 126 | Godot objects. 127 | * `variants `_ ``Variant`` type represents a "dynamic object" 128 | that many Godot procedures make use of. 129 | * `arrays `_ Defines ``Array`` of Variants. 130 | * `basis `_ Defines 3D ``Basis``. 131 | * `colors `_ Defines ARGB ``Color``. 132 | * `dictionaries `_ Defines ``Variant`` -> ``Variant`` 133 | ``Dictionary``. 134 | * `nodepaths `_ Defines ``NodePath`` - a path to a ``Node``. 135 | * `planes `_ Defines 3D ``Plane``. 136 | * `poolarrays `_ Defines pooled arrays: ``PoolByteArray``, 137 | ``PoolIntArray``, ``PoolRealArray``, ``PoolVector2Array``, 138 | ``PoolVector3Array``, ``PoolColorArray``, ``PoolStringArray``. 139 | * `quats `_ Defines ``Quat`` (quaternion) describing object 140 | rotation in 3D space. 141 | * `rect2 `_ Defines ``Rect2`` - a 2D rectangle. 142 | * `aabb `_ Defines ``AABB`` - a 3D box. 143 | * `rids `_ Defines ``RID`` - a resource identifier. 144 | * `transform2d `_ Defines ``Transform2D``. 145 | * `transforms `_ Defines ``Transform``. 146 | * `vector2 `_ Defines ``Vector2``. 147 | * `vector3 `_ Defines ``Vector3``. 148 | * `godotbase `_ Defines ``Error`` type and few common math 149 | procedures missing in Nim's standard library. 150 | 151 | 152 | Godot API 153 | --------- 154 | 155 | This is an auto-generated list of Godot API modules. It's built from Godot 156 | changeset `$GODOTAPI_CHANGESET_HASH 157 | `_. 158 | 159 | $AUTO_GENERATED_GODOTAPI_LIST 160 | 161 | 162 | godotinternal Module 163 | -------------------- 164 | 165 | Contains low-level wrappers over Godot types that require manual memory 166 | management. This module is used within ``godot-nim`` implementation and you 167 | don't need to import it unless you know what you are doing. 168 | 169 | * `godotdictionaries `_ 170 | * `godotnodepaths `_ 171 | * `godotpoolarrays `_ 172 | * `godotstrings `_ 173 | * `godotvariants `_ 174 | -------------------------------------------------------------------------------- /godot/internal/godotvariants.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Xored Software, Inc. 2 | 3 | import core/godotcoretypes, godotinternaltypes, gdnativeapi 4 | 5 | proc getType*(p: GodotVariant): VariantType {.inline.} = 6 | getGDNativeAPI().variantGetType(p) 7 | 8 | proc initGodotVariant*(dest: var GodotVariant) {.inline.} = 9 | getGDNativeAPI().variantNewNil(dest) 10 | 11 | proc initGodotVariant*(dest: var GodotVariant, src: GodotVariant) {.inline.} = 12 | getGDNativeAPI().variantNewCopy(dest, src) 13 | 14 | proc initGodotVariant*(dest: var GodotVariant; b: bool) {.inline.} = 15 | getGDNativeAPI().variantNewBool(dest, b) 16 | 17 | proc initGodotVariant*(dest: var GodotVariant; i: uint64) {.inline.} = 18 | getGDNativeAPI().variantNewUInt(dest, i) 19 | 20 | proc initGodotVariant*(dest: var GodotVariant; i: int64) {.inline.} = 21 | getGDNativeAPI().variantNewInt(dest, i) 22 | 23 | proc initGodotVariant*(dest: var GodotVariant; r: cdouble) {.inline.} = 24 | getGDNativeAPI().variantNewReal(dest, r) 25 | 26 | proc initGodotVariant*(dest: var GodotVariant; s: GodotString) {.inline.} = 27 | getGDNativeAPI().variantNewString(dest, s) 28 | 29 | proc initGodotVariant*(dest: var GodotVariant; v2: Vector2) {.inline.} = 30 | getGDNativeAPI().variantNewVector2(dest, v2) 31 | 32 | proc initGodotVariant*(dest: var GodotVariant; rect2: Rect2) {.inline.} = 33 | getGDNativeAPI().variantNewRect2(dest, rect2) 34 | 35 | proc initGodotVariant*(dest: var GodotVariant; v3: Vector3) {.inline.} = 36 | getGDNativeAPI().variantNewVector3(dest, v3) 37 | 38 | proc initGodotVariant*(dest: var GodotVariant; t2d: Transform2D) {.inline.} = 39 | getGDNativeAPI().variantNewTransform2D(dest, t2d) 40 | 41 | proc initGodotVariant*(dest: var GodotVariant; plane: Plane) {.inline.} = 42 | getGDNativeAPI().variantNewPlane(dest, plane) 43 | 44 | proc initGodotVariant*(dest: var GodotVariant; quat: Quat) {.inline.} = 45 | getGDNativeAPI().variantNewQuat(dest, quat) 46 | 47 | proc initGodotVariant*(dest: var GodotVariant; aabb: AABB) {.inline.} = 48 | getGDNativeAPI().variantNewAABB(dest, aabb) 49 | 50 | proc initGodotVariant*(dest: var GodotVariant; basis: Basis) {.inline.} = 51 | getGDNativeAPI().variantNewBasis(dest, basis) 52 | 53 | proc initGodotVariant*(dest: var GodotVariant; trans: Transform) {.inline.} = 54 | getGDNativeAPI().variantNewTransform(dest, trans) 55 | 56 | proc initGodotVariant*(dest: var GodotVariant; color: Color) {.inline.} = 57 | getGDNativeAPI().variantNewColor(dest, color) 58 | 59 | proc initGodotVariant*(dest: var GodotVariant; 60 | nodePath: GodotNodePath) {.inline.} = 61 | getGDNativeAPI().variantNewNodePath(dest, nodePath) 62 | 63 | proc initGodotVariant*(dest: var GodotVariant; rid: RID) {.inline.} = 64 | getGDNativeAPI().variantNewRID(dest, rid) 65 | 66 | proc initGodotVariant*(dest: var GodotVariant; 67 | obj: ptr GodotObject) {.inline.} = 68 | getGDNativeAPI().variantNewObject(dest, obj) 69 | 70 | proc initGodotVariant*(dest: var GodotVariant; arr: GodotArray) {.inline.} = 71 | getGDNativeAPI().variantNewArray(dest, arr) 72 | 73 | proc initGodotVariant*(dest: var GodotVariant; 74 | pba: GodotPoolByteArray) {.inline.} = 75 | getGDNativeAPI().variantNewPoolByteArray(dest, pba) 76 | 77 | proc initGodotVariant*(dest: var GodotVariant; 78 | pia: GodotPoolIntArray) {.inline.} = 79 | getGDNativeAPI().variantNewPoolIntArray(dest, pia) 80 | 81 | proc initGodotVariant*(dest: var GodotVariant; 82 | pra: GodotPoolRealArray) {.inline.} = 83 | getGDNativeAPI().variantNewPoolRealArray(dest, pra) 84 | 85 | proc initGodotVariant*(dest: var GodotVariant; 86 | psa: GodotPoolStringArray) {.inline.} = 87 | getGDNativeAPI().variantNewPoolStringArray(dest, psa) 88 | 89 | proc initGodotVariant*(dest: var GodotVariant; 90 | pv2a: GodotPoolVector2Array) {.inline.} = 91 | getGDNativeAPI().variantNewPoolVector2Array(dest, pv2a) 92 | 93 | proc initGodotVariant*(dest: var GodotVariant; 94 | pv3a: GodotPoolVector3Array) {.inline.} = 95 | getGDNativeAPI().variantNewPoolVector3Array(dest, pv3a) 96 | 97 | proc initGodotVariant*(dest: var GodotVariant; 98 | pca: GodotPoolColorArray) {.inline.} = 99 | getGDNativeAPI().variantNewPoolColorArray(dest, pca) 100 | 101 | proc initGodotVariant*(dest: var GodotVariant; 102 | dict: GodotDictionary) {.inline.} = 103 | getGDNativeAPI().variantNewDictionary(dest, dict) 104 | 105 | proc deinit*(v: var GodotVariant) {.inline.} = 106 | getGDNativeAPI().variantDestroy(v) 107 | 108 | proc asBool*(self: GodotVariant): bool {.inline.} = 109 | getGDNativeAPI().variantAsBool(self) 110 | 111 | proc asUInt*(self: GodotVariant): uint64 {.inline.} = 112 | getGDNativeAPI().variantAsUInt(self) 113 | 114 | proc asInt*(self: GodotVariant): int64 {.inline.} = 115 | getGDNativeAPI().variantAsInt(self) 116 | 117 | proc asReal*(self: GodotVariant): cdouble {.inline.} = 118 | getGDNativeAPI().variantAsReal(self) 119 | 120 | proc asGodotString*(self: GodotVariant): GodotString {.inline.} = 121 | getGDNativeAPI().variantAsString(self) 122 | 123 | proc asVector2*(self: GodotVariant): Vector2 {.inline.} = 124 | getGDNativeAPI().variantAsVector2(self).toVector2() 125 | 126 | proc asRect2*(self: GodotVariant): Rect2 {.inline.} = 127 | getGDNativeAPI().variantAsRect2(self).toRect2() 128 | 129 | proc asVector3*(self: GodotVariant): Vector3 {.inline.} = 130 | getGDNativeAPI().variantAsVector3(self).toVector3() 131 | 132 | proc asTransform2D*(self: GodotVariant): Transform2D {.inline.} = 133 | getGDNativeAPI().variantAsTransform2D(self).toTransform2D() 134 | 135 | proc asPlane*(self: GodotVariant): Plane {.inline.} = 136 | getGDNativeAPI().variantAsPlane(self).toPlane() 137 | 138 | proc asQuat*(self: GodotVariant): Quat {.inline.} = 139 | getGDNativeAPI().variantAsQuat(self).toQuat() 140 | 141 | proc asAABB*(self: GodotVariant): AABB {.inline.} = 142 | getGDNativeAPI().variantAsAABB(self).toAABB() 143 | 144 | proc asBasis*(self: GodotVariant): Basis {.inline.} = 145 | getGDNativeAPI().variantAsBasis(self).toBasis() 146 | 147 | proc asTransform*(self: GodotVariant): Transform {.inline.} = 148 | getGDNativeAPI().variantAsTransform(self).toTransform() 149 | 150 | proc asColor*(self: GodotVariant): Color {.inline.} = 151 | getGDNativeAPI().variantAsColor(self).toColor() 152 | 153 | proc asNodePath*(self: GodotVariant): GodotNodePath {.inline.} = 154 | getGDNativeAPI().variantAsNodePath(self) 155 | 156 | proc asRID*(self: GodotVariant): RID {.inline.} = 157 | getGDNativeAPI().variantAsRID(self) 158 | 159 | proc asGodotObject*(self: GodotVariant): ptr GodotObject {.inline.} = 160 | getGDNativeAPI().variantAsObject(self) 161 | 162 | proc asGodotArray*(self: GodotVariant): GodotArray {.inline.} = 163 | getGDNativeAPI().variantAsArray(self) 164 | 165 | proc asGodotPoolByteArray*(self: GodotVariant): GodotPoolByteArray {.inline.} = 166 | getGDNativeAPI().variantAsPoolByteArray(self) 167 | 168 | proc asGodotPoolIntArray*(self: GodotVariant): GodotPoolIntArray {.inline.} = 169 | getGDNativeAPI().variantAsPoolIntArray(self) 170 | 171 | proc asGodotPoolRealArray*(self: GodotVariant): GodotPoolRealArray {.inline.} = 172 | getGDNativeAPI().variantAsPoolRealArray(self) 173 | 174 | proc asGodotPoolStringArray*(self: GodotVariant): GodotPoolStringArray 175 | {.inline.} = 176 | getGDNativeAPI().variantAsPoolStringArray(self) 177 | 178 | proc asGodotPoolVector2Array*(self: GodotVariant): GodotPoolVector2Array 179 | {.inline.} = 180 | getGDNativeAPI().variantAsPoolVector2Array(self) 181 | 182 | proc asGodotPoolVector3Array*(self: GodotVariant): GodotPoolVector3Array 183 | {.inline.} = 184 | getGDNativeAPI().variantAsPoolVector3Array(self) 185 | 186 | proc asGodotPoolColorArray*(self: GodotVariant): GodotPoolColorArray 187 | {.inline.} = 188 | getGDNativeAPI().variantAsPoolColorArray(self) 189 | 190 | proc asGodotDictionary*(self: GodotVariant): GodotDictionary {.inline.} = 191 | getGDNativeAPI().variantAsDictionary(self) 192 | 193 | proc call*(self: var GodotVariant; meth: GodotString; 194 | args: ptr array[256, ptr GodotVariant]; argCount: cint; 195 | error: var VariantCallError): GodotVariant {.inline.} = 196 | getGDNativeAPI().variantCall(self, meth, args, argCount, error) 197 | 198 | proc hasMethod*(self: GodotVariant; meth: GodotString): bool {.inline.} = 199 | getGDNativeAPI().variantHasMethod(self, meth) 200 | 201 | proc `==`*(self, other: GodotVariant): bool {.inline.} = 202 | getGDNativeAPI().variantOperatorEqual(self, other) 203 | 204 | proc `<`*(self, other: GodotVariant): bool {.inline.} = 205 | getGDNativeAPI().variantOperatorLess(self, other) 206 | 207 | proc hashCompare*(self, other: GodotVariant): bool {.inline.} = 208 | getGDNativeAPI().variantHashCompare(self, other) 209 | 210 | proc booleanize*(self: GodotVariant): bool {.inline.} = 211 | getGDNativeAPI().variantBooleanize(self) 212 | 213 | import godotstrings 214 | proc `$`*(self: GodotVariant): string = 215 | var s = self.asGodotString() 216 | result = $s 217 | s.deinit() 218 | -------------------------------------------------------------------------------- /godot/core/variants.nim: -------------------------------------------------------------------------------- 1 | import tables, hashes 2 | 3 | import godotcoretypes 4 | import internal/godotinternaltypes, internal/godotvariants, 5 | internal/godotstrings, internal/godotdictionaries, 6 | internal/godotarrays 7 | 8 | type 9 | Variant* = ref object 10 | godotVariant: GodotVariant 11 | noDeinit: bool # used to avoid copying when passing the variant to Godot 12 | 13 | export VariantType, VariantCallErrorType, VariantCallError 14 | 15 | proc markNoDeinit*(v: Variant) {.inline.} = 16 | ## Makes it so that internal GodotVariant object will not be destroyed 17 | ## when the reference is gone. Use only if you know what you are doing. 18 | v.noDeinit = true 19 | 20 | proc godotVariant*(v: Variant): ptr GodotVariant {.inline.} = 21 | ## WARNING: do not keep the returned value for longer than the lifetime of 22 | ## ``v`` 23 | addr v.godotVariant 24 | 25 | proc getType*(v: Variant): VariantType = 26 | v.godotVariant.getType() 27 | 28 | proc variantFinalizer*(v: Variant) = 29 | if not v.noDeinit: 30 | v.godotVariant.deinit() 31 | 32 | proc `$`*(self: Variant): string {.inline.} = 33 | $self.godotVariant 34 | 35 | proc newVariant*(): Variant {.inline.} = 36 | new(result, variantFinalizer) 37 | initGodotVariant(result.godotVariant) 38 | 39 | proc newVariant*(v: Variant): Variant {.inline.} = 40 | ## Makes a copy 41 | new(result, variantFinalizer) 42 | initGodotVariant(result.godotVariant, v.godotVariant) 43 | 44 | proc newVariant*(v: GodotVariant): Variant {.inline.} = 45 | new(result, variantFinalizer) 46 | result.godotVariant = v 47 | 48 | proc newVariant*(b: bool): Variant {.inline.} = 49 | new(result, variantFinalizer) 50 | initGodotVariant(result.godotVariant, b) 51 | 52 | # resolves Nim call ambiguities well 53 | template numConstructor(T, ConvT) = 54 | proc newVariant*(i: T): Variant {.inline.} = 55 | new(result, variantFinalizer) 56 | initGodotVariant(result.godotVariant, ConvT(i)) 57 | 58 | numConstructor(uint8, uint64) 59 | numConstructor(uint16, uint64) 60 | numConstructor(uint32, uint64) 61 | numConstructor(uint64, uint64) 62 | numConstructor(uint, uint64) 63 | 64 | numConstructor(int8, int64) 65 | numConstructor(int16, int64) 66 | numConstructor(int32, int64) 67 | numConstructor(int64, int64) 68 | numConstructor(int, int64) 69 | 70 | proc newVariant*(r: cdouble): Variant {.inline.} = 71 | new(result, variantFinalizer) 72 | initGodotVariant(result.godotVariant, r) 73 | 74 | proc newVariant*(s: string): Variant {.inline.} = 75 | new(result, variantFinalizer) 76 | when (NimMajor, NimMinor, NimPatch) < (0, 19, 0): 77 | if s.isNil: 78 | initGodotVariant(result.godotVariant) 79 | return 80 | var godotStr = s.toGodotString() 81 | initGodotVariant(result.godotVariant, godotStr) 82 | godotStr.deinit() 83 | 84 | import basis, nodepaths 85 | import planes, quats, rect2, aabb, rids 86 | import transforms, transform2d, vector2 87 | import vector3, colors 88 | 89 | proc newVariant*(v2: Vector2): Variant {.inline.} = 90 | new(result, variantFinalizer) 91 | initGodotVariant(result.godotVariant, v2) 92 | 93 | proc newVariant*(rect2: Rect2): Variant {.inline.} = 94 | new(result, variantFinalizer) 95 | initGodotVariant(result.godotVariant, rect2) 96 | 97 | proc newVariant*(v3: Vector3): Variant {.inline.} = 98 | new(result, variantFinalizer) 99 | initGodotVariant(result.godotVariant, v3) 100 | 101 | proc newVariant*(t2d: Transform2D): Variant {.inline.} = 102 | new(result, variantFinalizer) 103 | initGodotVariant(result.godotVariant, t2d) 104 | 105 | proc newVariant*(plane: Plane): Variant {.inline.} = 106 | new(result, variantFinalizer) 107 | initGodotVariant(result.godotVariant, plane) 108 | 109 | proc newVariant*(quat: Quat): Variant {.inline.} = 110 | new(result, variantFinalizer) 111 | initGodotVariant(result.godotVariant, quat) 112 | 113 | proc newVariant*(aabb: AABB): Variant {.inline.} = 114 | new(result, variantFinalizer) 115 | initGodotVariant(result.godotVariant, aabb) 116 | 117 | proc newVariant*(basis: Basis): Variant {.inline.} = 118 | new(result, variantFinalizer) 119 | initGodotVariant(result.godotVariant, basis) 120 | 121 | proc newVariant*(trans: Transform): Variant {.inline.} = 122 | new(result, variantFinalizer) 123 | initGodotVariant(result.godotVariant, trans) 124 | 125 | proc newVariant*(color: Color): Variant {.inline.} = 126 | new(result, variantFinalizer) 127 | initGodotVariant(result.godotVariant, color) 128 | 129 | proc newVariant*(nodePath: NodePath): Variant {.inline.} = 130 | new(result, variantFinalizer) 131 | initGodotVariant(result.godotVariant, nodePath.godotNodePath[]) 132 | 133 | proc newVariant*(godotNodePath: GodotNodePath): Variant {.inline.} = 134 | new(result, variantFinalizer) 135 | initGodotVariant(result.godotVariant, godotNodePath) 136 | 137 | proc newVariant*(rid: RID): Variant {.inline.} = 138 | new(result, variantFinalizer) 139 | initGodotVariant(result.godotVariant, rid) 140 | 141 | proc newVariant*(obj: ptr GodotObject): Variant {.inline.} = 142 | new(result, variantFinalizer) 143 | initGodotVariant(result.godotVariant, obj) 144 | 145 | import poolarrays 146 | 147 | proc newVariant*(pba: PoolByteArray): Variant {.inline.} = 148 | new(result, variantFinalizer) 149 | initGodotVariant(result.godotVariant, pba.godotPoolByteArray[]) 150 | 151 | proc newVariant*(pia: PoolIntArray): Variant {.inline.} = 152 | new(result, variantFinalizer) 153 | initGodotVariant(result.godotVariant, pia.godotPoolIntArray[]) 154 | 155 | proc newVariant*(pra: PoolRealArray): Variant {.inline.} = 156 | new(result, variantFinalizer) 157 | initGodotVariant(result.godotVariant, pra.godotPoolRealArray[]) 158 | 159 | proc newVariant*(psa: PoolStringArray): Variant {.inline.} = 160 | new(result, variantFinalizer) 161 | initGodotVariant(result.godotVariant, psa.godotPoolStringArray[]) 162 | 163 | proc newVariant*(pv2a: PoolVector2Array): Variant {.inline.} = 164 | new(result, variantFinalizer) 165 | initGodotVariant(result.godotVariant, pv2a.godotPoolVector2Array[]) 166 | 167 | proc newVariant*(pv3a: PoolVector3Array): Variant {.inline.} = 168 | new(result, variantFinalizer) 169 | initGodotVariant(result.godotVariant, pv3a.godotPoolVector3Array[]) 170 | 171 | proc newVariant*(pca: PoolColorArray): Variant {.inline.} = 172 | new(result, variantFinalizer) 173 | initGodotVariant(result.godotVariant, pca.godotPoolColorArray[]) 174 | 175 | proc asBool*(self: Variant): bool {.inline.} = 176 | self.godotVariant.asBool() 177 | 178 | proc asUInt*(self: Variant): uint64 {.inline.} = 179 | self.godotVariant.asUInt() 180 | 181 | proc asInt*(self: Variant): int64 {.inline.} = 182 | self.godotVariant.asInt() 183 | 184 | proc asReal*(self: Variant): cdouble {.inline.} = 185 | self.godotVariant.asReal() 186 | 187 | proc asString*(self: Variant): string {.inline.} = 188 | $self 189 | 190 | proc asVector2*(self: Variant): Vector2 {.inline.} = 191 | self.godotVariant.asVector2() 192 | 193 | proc asRect2*(self: Variant): Rect2 {.inline.} = 194 | self.godotVariant.asRect2() 195 | 196 | proc asVector3*(self: Variant): Vector3 {.inline.} = 197 | self.godotVariant.asVector3() 198 | 199 | proc asTransform2D*(self: Variant): Transform2D {.inline.} = 200 | self.godotVariant.asTransform2D() 201 | 202 | proc asPlane*(self: Variant): Plane {.inline.} = 203 | self.godotVariant.asPlane() 204 | 205 | proc asQuat*(self: Variant): Quat {.inline.} = 206 | self.godotVariant.asQuat() 207 | 208 | proc asAABB*(self: Variant): AABB {.inline.} = 209 | self.godotVariant.asAABB() 210 | 211 | proc asBasis*(self: Variant): Basis {.inline.} = 212 | self.godotVariant.asBasis() 213 | 214 | proc asTransform*(self: Variant): Transform {.inline.} = 215 | self.godotVariant.asTransform() 216 | 217 | proc asColor*(self: Variant): Color {.inline.} = 218 | self.godotVariant.asColor() 219 | 220 | proc asNodePath*(self: Variant): NodePath {.inline.} = 221 | result = newNodePath(self.godotVariant.asNodePath()) 222 | 223 | proc asRID*(self: Variant): RID {.inline.} = 224 | self.godotVariant.asRID() 225 | 226 | proc asGodotObject*(self: Variant): ptr GodotObject {.inline.} = 227 | self.godotVariant.asGodotObject() 228 | 229 | proc asPoolByteArray*(self: Variant): PoolByteArray {.inline.} = 230 | newPoolByteArray(self.godotVariant.asGodotPoolByteArray()) 231 | 232 | proc asPoolIntArray*(self: Variant): PoolIntArray {.inline.} = 233 | newPoolIntArray(self.godotVariant.asGodotPoolIntArray()) 234 | 235 | proc asPoolRealArray*(self: Variant): PoolRealArray {.inline.} = 236 | newPoolRealArray(self.godotVariant.asGodotPoolRealArray()) 237 | 238 | proc asPoolStringArray*(self: Variant): PoolStringArray {.inline.} = 239 | newPoolStringArray(self.godotVariant.asGodotPoolStringArray()) 240 | 241 | proc asPoolVector2Array*(self: Variant): PoolVector2Array {.inline.} = 242 | newPoolVector2Array(self.godotVariant.asGodotPoolVector2Array()) 243 | 244 | proc asPoolVector3Array*(self: Variant): PoolVector3Array {.inline.} = 245 | newPoolVector3Array(self.godotVariant.asGodotPoolVector3Array()) 246 | 247 | proc asPoolColorArray*(self: Variant): PoolColorArray {.inline.} = 248 | newPoolColorArray(self.godotVariant.asGodotPoolColorArray()) 249 | 250 | proc hash*(self: Variant): Hash = 251 | proc objectHash(obj: ptr GodotObject): Hash = 252 | if not obj.isNil: cast[int](obj).hash() else: 0.hash() 253 | result = case self.getType(): 254 | of VariantType.Nil: Hash(0) 255 | of VariantType.Bool: self.asBool().hash() 256 | of VariantType.Int: self.asInt().hash() 257 | of VariantType.Real: self.asReal().hash() 258 | of VariantType.String: self.asString().hash() 259 | of VariantType.Vector2: self.asVector2().hash() 260 | of VariantType.Rect2: self.asRect2().hash() 261 | of VariantType.Vector3: self.asVector3().hash() 262 | of VariantType.Transform2D: self.asTransform2D().hash() 263 | of VariantType.Plane: self.asPlane().hash() 264 | of VariantType.Quat: self.asQuat().hash() 265 | of VariantType.AABB: self.asAABB().hash() 266 | of VariantType.Basis: self.asBasis().hash() 267 | of VariantType.Transform: self.asTransform().hash() 268 | of VariantType.Color: self.asColor().hash() 269 | of VariantType.NodePath: self.asNodePath().hash() 270 | of VariantType.RID: self.asRID().hash() 271 | of VariantType.Object: self.asGodotObject().objectHash() 272 | of VariantType.Dictionary: hash(self.godotVariant.asGodotDictionary().godotHash()) 273 | of VariantType.Array: hash(self.godotVariant.asGodotArray().godotHash()) 274 | of VariantType.PoolByteArray: self.asPoolByteArray().hash() 275 | of VariantType.PoolIntArray: self.asPoolIntArray().hash() 276 | of VariantType.PoolRealArray: self.asPoolRealArray().hash() 277 | of VariantType.PoolStringArray: self.asPoolStringArray().hash() 278 | of VariantType.PoolVector2Array: self.asPoolVector2Array().hash() 279 | of VariantType.PoolVector3Array: self.asPoolVector3Array().hash() 280 | of VariantType.PoolColorArray: self.asPoolColorArray().hash() 281 | 282 | import arrays 283 | 284 | proc newVariant*(arr: Array): Variant {.inline.} = 285 | new(result, variantFinalizer) 286 | initGodotVariant(result.godotVariant, arr.godotArray[]) 287 | 288 | proc asArray*(self: Variant): Array {.inline.} = 289 | newArray(self.godotVariant.asGodotArray()) 290 | 291 | proc hasMethod*(self: Variant; meth: string): bool = 292 | var s = meth.toGodotString() 293 | result = self.godotVariant.hasMethod(s) 294 | s.deinit() 295 | 296 | proc `==`*(self, other: Variant): bool = 297 | if self.isNil and other.isNil: return true 298 | if self.isNil != other.isNil: return false 299 | result = self.godotVariant == other.godotVariant 300 | 301 | proc `<`*(self, other: Variant): bool = 302 | result = self.godotVariant < other.godotVariant 303 | 304 | proc hashCompare*(self, other: Variant): bool = 305 | self.godotVariant.hashCompare(other.godotVariant) 306 | 307 | proc booleanize*(self: Variant): bool = 308 | self.godotVariant.booleanize() 309 | -------------------------------------------------------------------------------- /godot/internal/godotpoolarrays.nim: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018 Xored Software, Inc. 2 | 3 | import godotinternaltypes, gdnativeapi 4 | import core/godotcoretypes 5 | 6 | template genPoolArrayAPI(ArrayT, initIdent, DataT, 7 | newProc, newCopyProc, newWithArrayProc, appendProc, 8 | appendArrayProc, insertProc, invertProc, pushBackProc, 9 | removeProc, resizeProc, setProc, getProc, sizeProc, 10 | destroyProc, readProc, writeProc, 11 | readAccessPtrProc, writeAccessPtrProc, 12 | readAccessDestroyProc, writeAccessDestroyProc) = 13 | proc initIdent*(dest: var ArrayT) {.inline.} = 14 | getGDNativeAPI().newProc(dest) 15 | 16 | proc initIdent*(dest: var ArrayT; src: ArrayT) {.inline.} = 17 | getGDNativeAPI().newCopyProc(dest, src) 18 | 19 | proc initIdent*(dest: var ArrayT; arr: GodotArray) {.inline.} = 20 | getGDNativeAPI().newWithArrayProc(dest, arr) 21 | 22 | proc deinit*(self: var ArrayT) {.inline.} = 23 | getGDNativeAPI().destroyProc(self) 24 | 25 | proc add*(self: var ArrayT; data: DataT) {.inline.} = 26 | getGDNativeAPI().pushBackProc(self, data) 27 | 28 | proc add*(self: var ArrayT; arr: ArrayT) {.inline.} = 29 | getGDNativeAPI().appendArrayProc(self, arr) 30 | 31 | proc insert*(self: var ArrayT; idx: cint; 32 | data: DataT): Error {.inline.} = 33 | getGDNativeAPI().insertProc(self, idx, data) 34 | 35 | proc delete*(self: var ArrayT; idx: cint) {.inline.} = 36 | getGDNativeAPI().removeProc(self, idx) 37 | 38 | proc reverse*(self: var ArrayT) {.inline.} = 39 | getGDNativeAPI().invertProc(self) 40 | 41 | proc setLen*(self: var ArrayT; size: cint) {.inline.} = 42 | getGDNativeAPI().resizeProc(self, size) 43 | 44 | proc `[]=`*(self: var ArrayT; idx: cint; data: DataT) {.inline.} = 45 | getGDNativeAPI().setProc(self, idx, data) 46 | 47 | proc `[]`*(self: ArrayT; idx: cint): DataT {.inline.} = 48 | let data = getGDNativeAPI().getProc(self, idx) 49 | when DataT is Color: 50 | data.toColor() 51 | elif DataT is Vector2: 52 | data.toVector2() 53 | elif DataT is Vector3: 54 | data.toVector3() 55 | else: 56 | data 57 | 58 | proc len*(self: ArrayT): cint {.inline.} = 59 | getGDNativeAPI().sizeProc(self) 60 | 61 | iterator items*(self: ArrayT): DataT = 62 | let readAccess = getGDNativeAPI().readProc(self) 63 | let readPtr = getGDNativeAPI().readAccessPtrProc(readAccess) 64 | for i in 0.cint..= ownLen: 99 | let instInfo = instantiationInfo() 100 | getGDNativeAPI().printError( 101 | cstring"Invalid subarray begin index", cstring"subarray", instInfo.filename, instInfo.line.cint) 102 | return 103 | if actualIdxTo < 0 or actualIdxTo >= ownLen: 104 | let instInfo = instantiationInfo() 105 | getGDNativeAPI().printError( 106 | cstring"Invalid subarray end index", cstring"subarray", instInfo.filename, instInfo.line.cint) 107 | return 108 | let span = actualIdxTo - actualIdxFrom + 1 109 | result.setLen(span) 110 | let readAccess = getGDNativeAPI().readProc(self) 111 | let writeAccess = getGDNativeAPI().writeProc(result) 112 | let readPtr = getGDNativeAPI().readAccessPtrProc(readAccess).offset(actualIdxFrom) 113 | copyMem(getGDNativeAPI().writeAccessPtrProc(writeAccess), readPtr, span) 114 | getGDNativeAPI().readAccessDestroyProc(readAccess) 115 | getGDNativeAPI().writeAccessDestroyProc(writeAccess) 116 | 117 | genPoolArrayAPI(GodotPoolByteArray, initGodotPoolByteArray, byte, 118 | poolByteArrayNew, 119 | poolByteArrayNewCopy, 120 | poolByteArrayNewWithArray, 121 | poolByteArrayAppend, 122 | poolByteArrayAppendArray, 123 | poolByteArrayInsert, 124 | poolByteArrayInvert, 125 | poolByteArrayPushBack, 126 | poolByteArrayRemove, 127 | poolByteArrayResize, 128 | poolByteArraySet, 129 | poolByteArrayGet, 130 | poolByteArraySize, 131 | poolByteArrayDestroy, 132 | poolByteArrayRead, 133 | poolByteArrayWrite, 134 | poolByteArrayReadAccessPtr, 135 | poolByteArrayWriteAccessPtr, 136 | poolByteArrayReadAccessDestroy, 137 | poolByteArrayWriteAccessDestroy) 138 | 139 | genPoolArrayAPI(GodotPoolIntArray, initGodotPoolIntArray, cint, 140 | poolIntArrayNew, 141 | poolIntArrayNewCopy, 142 | poolIntArrayNewWithArray, 143 | poolIntArrayAppend, 144 | poolIntArrayAppendArray, 145 | poolIntArrayInsert, 146 | poolIntArrayInvert, 147 | poolIntArrayPushBack, 148 | poolIntArrayRemove, 149 | poolIntArrayResize, 150 | poolIntArraySet, 151 | poolIntArrayGet, 152 | poolIntArraySize, 153 | poolIntArrayDestroy, 154 | poolIntArrayRead, 155 | poolIntArrayWrite, 156 | poolIntArrayReadAccessPtr, 157 | poolIntArrayWriteAccessPtr, 158 | poolIntArrayReadAccessDestroy, 159 | poolIntArrayWriteAccessDestroy) 160 | 161 | genPoolArrayAPI(GodotPoolRealArray, initGodotPoolRealArray, float32, 162 | poolRealArrayNew, 163 | poolRealArrayNewCopy, 164 | poolRealArrayNewWithArray, 165 | poolRealArrayAppend, 166 | poolRealArrayAppendArray, 167 | poolRealArrayInsert, 168 | poolRealArrayInvert, 169 | poolRealArrayPushBack, 170 | poolRealArrayRemove, 171 | poolRealArrayResize, 172 | poolRealArraySet, 173 | poolRealArrayGet, 174 | poolRealArraySize, 175 | poolRealArrayDestroy, 176 | poolRealArrayRead, 177 | poolRealArrayWrite, 178 | poolRealArrayReadAccessPtr, 179 | poolRealArrayWriteAccessPtr, 180 | poolRealArrayReadAccessDestroy, 181 | poolRealArrayWriteAccessDestroy) 182 | 183 | genPoolArrayAPI(GodotPoolStringArray, initGodotPoolStringArray, GodotString, 184 | poolStringArrayNew, 185 | poolStringArrayNewCopy, 186 | poolStringArrayNewWithArray, 187 | poolStringArrayAppend, 188 | poolStringArrayAppendArray, 189 | poolStringArrayInsert, 190 | poolStringArrayInvert, 191 | poolStringArrayPushBack, 192 | poolStringArrayRemove, 193 | poolStringArrayResize, 194 | poolStringArraySet, 195 | poolStringArrayGet, 196 | poolStringArraySize, 197 | poolStringArrayDestroy, 198 | poolStringArrayRead, 199 | poolStringArrayWrite, 200 | poolStringArrayReadAccessPtr, 201 | poolStringArrayWriteAccessPtr, 202 | poolStringArrayReadAccessDestroy, 203 | poolStringArrayWriteAccessDestroy) 204 | 205 | genPoolArrayAPI(GodotPoolVector2Array, initGodotPoolVector2Array, Vector2, 206 | poolVector2ArrayNew, 207 | poolVector2ArrayNewCopy, 208 | poolVector2ArrayNewWithArray, 209 | poolVector2ArrayAppend, 210 | poolVector2ArrayAppendArray, 211 | poolVector2ArrayInsert, 212 | poolVector2ArrayInvert, 213 | poolVector2ArrayPushBack, 214 | poolVector2ArrayRemove, 215 | poolVector2ArrayResize, 216 | poolVector2ArraySet, 217 | poolVector2ArrayGet, 218 | poolVector2ArraySize, 219 | poolVector2ArrayDestroy, 220 | poolVector2ArrayRead, 221 | poolVector2ArrayWrite, 222 | poolVector2ArrayReadAccessPtr, 223 | poolVector2ArrayWriteAccessPtr, 224 | poolVector2ArrayReadAccessDestroy, 225 | poolVector2ArrayWriteAccessDestroy) 226 | 227 | genPoolArrayAPI(GodotPoolVector3Array, initGodotPoolVector3Array, Vector3, 228 | poolVector3ArrayNew, 229 | poolVector3ArrayNewCopy, 230 | poolVector3ArrayNewWithArray, 231 | poolVector3ArrayAppend, 232 | poolVector3ArrayAppendArray, 233 | poolVector3ArrayInsert, 234 | poolVector3ArrayInvert, 235 | poolVector3ArrayPushBack, 236 | poolVector3ArrayRemove, 237 | poolVector3ArrayResize, 238 | poolVector3ArraySet, 239 | poolVector3ArrayGet, 240 | poolVector3ArraySize, 241 | poolVector3ArrayDestroy, 242 | poolVector3ArrayRead, 243 | poolVector3ArrayWrite, 244 | poolVector3ArrayReadAccessPtr, 245 | poolVector3ArrayWriteAccessPtr, 246 | poolVector3ArrayReadAccessDestroy, 247 | poolVector3ArrayWriteAccessDestroy) 248 | 249 | genPoolArrayAPI(GodotPoolColorArray, initGodotPoolColorArray, Color, 250 | poolColorArrayNew, 251 | poolColorArrayNewCopy, 252 | poolColorArrayNewWithArray, 253 | poolColorArrayAppend, 254 | poolColorArrayAppendArray, 255 | poolColorArrayInsert, 256 | poolColorArrayInvert, 257 | poolColorArrayPushBack, 258 | poolColorArrayRemove, 259 | poolColorArrayResize, 260 | poolColorArraySet, 261 | poolColorArrayGet, 262 | poolColorArraySize, 263 | poolColorArrayDestroy, 264 | poolColorArrayRead, 265 | poolColorArrayWrite, 266 | poolColorArrayReadAccessPtr, 267 | poolColorArrayWriteAccessPtr, 268 | poolColorArrayReadAccessDestroy, 269 | poolColorArrayWriteAccessDestroy) 270 | -------------------------------------------------------------------------------- /godot/internal/godotinternaltypes.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Xored Software, Inc. 2 | 3 | const MAX_ARG_COUNT* = 256 4 | 5 | type 6 | GodotArray* {.byref.} = object 7 | data: array[sizeof(int), byte] 8 | 9 | GodotDictionary* {.byref.} = object 10 | data: array[sizeof(int), byte] 11 | 12 | GodotNodePath* {.byref.} = object 13 | data: array[sizeof(int), byte] 14 | 15 | GodotObject* = object 16 | 17 | GodotPoolByteArray* {.byref.} = object 18 | data: array[sizeof(int), byte] 19 | GodotPoolByteArrayReadAccess* {.byref.} = object 20 | data: array[1, byte] 21 | GodotPoolByteArrayWriteAccess* {.byref.} = object 22 | data: array[1, byte] 23 | 24 | GodotPoolIntArray* {.byref.} = object 25 | data: array[sizeof(int), byte] 26 | GodotPoolIntArrayReadAccess* {.byref.} = object 27 | data: array[1, byte] 28 | GodotPoolIntArrayWriteAccess* {.byref.} = object 29 | data: array[1, byte] 30 | 31 | GodotPoolRealArray* {.byref.} = object 32 | data: array[sizeof(int), byte] 33 | GodotPoolRealArrayReadAccess* {.byref.} = object 34 | data: array[1, byte] 35 | GodotPoolRealArrayWriteAccess* {.byref.} = object 36 | data: array[1, byte] 37 | 38 | GodotPoolStringArray* {.byref.} = object 39 | data: array[sizeof(int), byte] 40 | GodotPoolStringArrayReadAccess* {.byref.} = object 41 | data: array[1, byte] 42 | GodotPoolStringArrayWriteAccess* {.byref.} = object 43 | data: array[1, byte] 44 | 45 | GodotPoolVector2Array* {.byref.} = object 46 | data: array[sizeof(int), byte] 47 | GodotPoolVector2ArrayReadAccess* {.byref.} = object 48 | data: array[1, byte] 49 | GodotPoolVector2ArrayWriteAccess* {.byref.} = object 50 | data: array[1, byte] 51 | 52 | GodotPoolVector3Array* {.byref.} = object 53 | data: array[sizeof(int), byte] 54 | GodotPoolVector3ArrayReadAccess* {.byref.} = object 55 | data: array[1, byte] 56 | GodotPoolVector3ArrayWriteAccess* {.byref.} = object 57 | data: array[1, byte] 58 | 59 | GodotPoolColorArray* {.byref.} = object 60 | data: array[sizeof(int), byte] 61 | GodotPoolColorArrayReadAccess* {.byref.} = object 62 | data: array[1, byte] 63 | GodotPoolColorArrayWriteAccess* {.byref.} = object 64 | data: array[1, byte] 65 | 66 | GodotString* {.byref.} = object 67 | data: array[sizeof(int), byte] 68 | 69 | cwchar_t* {.importc: "wchar_t", nodecl.} = object 70 | 71 | GodotCharString* {.byref.} = object 72 | data: array[sizeof(int), byte] 73 | 74 | VariantType* {.size: sizeof(cint), pure.} = enum 75 | Nil, ## atomic types 76 | Bool, 77 | Int, 78 | Real, 79 | String, 80 | # math types 81 | Vector2, ## 5 82 | Rect2, 83 | Vector3, 84 | Transform2D, 85 | Plane, 86 | Quat, ## 10 87 | AABB, 88 | Basis, 89 | Transform, ## misc types 90 | Color, 91 | NodePath, ## 15 92 | RID, 93 | Object, 94 | Dictionary, 95 | Array, ## 20 96 | # arrays 97 | PoolByteArray, 98 | PoolIntArray, 99 | PoolRealArray, 100 | PoolStringArray, 101 | PoolVector2Array, ## 25 102 | PoolVector3Array, 103 | PoolColorArray 104 | 105 | VariantCallErrorType* {.size: sizeof(cint), pure.} = enum 106 | OK, 107 | InvalidMethod, 108 | InvalidArgument, 109 | TooManyArguments, 110 | TooFewArguments, 111 | InstanceIsNull 112 | 113 | VariantCallError* = object 114 | error*: VariantCallErrorType 115 | argument*: cint 116 | expected*: VariantType 117 | 118 | GodotVariant* {.byref.} = object 119 | data: array[2, int64] 120 | data2: int 121 | 122 | type GodotMethodBind* = object 123 | 124 | type 125 | GDNativeAPIVersion* = object 126 | major*: cuint 127 | minor*: cuint 128 | 129 | GDNativeInitOptions* = object 130 | inEditor*: bool 131 | coreApiHash*: uint64 132 | editorApiHash*: uint64 133 | noApiHash*: uint64 134 | reportVersionMismatch*: proc (library: ptr GodotObject, extension: cstring, 135 | want: GDNativeAPIVersion, have: GDNativeAPIVersion) {.noconv.} 136 | reportLoadingError*: proc (library: ptr GodotObject, what: cstring) {.noconv.} 137 | gdNativeLibrary*: ptr GodotObject 138 | gdNativeAPIStruct*: pointer 139 | activeLibraryPath*: ptr GodotString 140 | 141 | GDNativeTerminateOptions* = object 142 | inEditor*: bool 143 | 144 | GodotMethodRPCMode* {.size: sizeof(cint), pure.} = enum 145 | Disabled, 146 | Remote, 147 | Sync, 148 | Master, 149 | Slave 150 | 151 | GodotMethodAttributes* = object 152 | rpcMode*: GodotMethodRPCMode 153 | 154 | GodotPropertyHint* {.size: sizeof(cint), pure.} = enum 155 | None, ## no hint provided. 156 | Range, ## hint_text = "min,max,step,slider; // slider is optional" 157 | ExpRange, ## hint_text = "min,max,step", exponential edit 158 | Enum, ## hint_text= "val1,val2,val3,etc" 159 | ExpEasing, ## exponential easing funciton (Math::ease) 160 | Length, ## hint_text= "length" (as integer) 161 | SpriteFrame, 162 | KeyAccel, ## hint_text= "length" (as integer) 163 | Flags, ## hint_text= "flag1,flag2,etc" (as bit flags) 164 | Layers2DRender, 165 | Layers2DPhysics, 166 | Layers3DRender, 167 | Layers3DPhysics, 168 | File, ## a file path must be passed, hint_text (optionally) 169 | ## is a filter "*.png,*.wav,*.doc," 170 | Dir, ## a directort path must be passed 171 | GlobalFile, ## a file path must be passed, hint_text (optionally) is a 172 | ## filter "*.png,*.wav,*.doc," 173 | GlobalDir, ## a directort path must be passed 174 | ResourceType, ## a resource object type 175 | MultilineText, ## used for string properties that can contain multiple lines 176 | ColorNoAlpha, ## used for ignoring alpha component when editing a color 177 | ImageCompressLossy, 178 | ImageCompressLossless, 179 | ObjectId, 180 | TypeString, ## a type string, the hint is the base type to choose 181 | NodePathToEditedNode, ## so something else can provide this 182 | ## (used in scripts) 183 | MethodOfVariantType, ## a method of a type 184 | MethodOfBaseType, ## a method of a base type 185 | MethodOfInstance, ## a method of an instance 186 | MethodOfScript, ## a method of a script & base 187 | PropertyOfVariantType, ## a property of a type 188 | PropertyOfBaseType, ## a property of a base type 189 | PropertyOfInstance, ## a property of an instance 190 | PropertyOfScript, ## a property of a script & base 191 | PropertyHintMax 192 | 193 | const 194 | GODOT_PROPERTY_USAGE_STORAGE_VALUE = 1.cint 195 | GODOT_PROPERTY_USAGE_EDITOR_VALUE = 2.cint 196 | GODOT_PROPERTY_USAGE_NETWORK_VALUE = 4.cint 197 | GODOT_PROPERTY_USAGE_EDITOR_HELPER_VALUE = 8.cint 198 | GODOT_PROPERTY_USAGE_CHECKABLE_VALUE = 16.cint 199 | GODOT_PROPERTY_USAGE_CHECKED_VALUE = 32.cint 200 | GODOT_PROPERTY_USAGE_INTERNATIONALIZED_VALUE = 64.cint 201 | GODOT_PROPERTY_USAGE_GROUP_VALUE = 128.cint 202 | GODOT_PROPERTY_USAGE_CATEGORY_VALUE = 256.cint 203 | GODOT_PROPERTY_USAGE_STORE_IF_NONZERO_VALUE = 512.cint 204 | GODOT_PROPERTY_USAGE_STORE_IF_NONONE_VALUE = 1024.cint 205 | GODOT_PROPERTY_USAGE_NO_INSTANCE_STATE_VALUE = 2048.cint 206 | GODOT_PROPERTY_USAGE_RESTART_IF_CHANGED_VALUE = 4096.cint 207 | GODOT_PROPERTY_USAGE_SCRIPT_VARIABLE_VALUE = 8192.cint 208 | GODOT_PROPERTY_USAGE_STORE_IF_NULL_VALUE = 16384.cint 209 | GODOT_PROPERTY_USAGE_ANIMATE_AS_TRIGGER_VALUE = 32768.cint 210 | GODOT_PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED_VALUE = 65536.cint 211 | 212 | GODOT_PROPERTY_USAGE_DEFAULT_VALUE: cint = 213 | GODOT_PROPERTY_USAGE_STORAGE_VALUE or GODOT_PROPERTY_USAGE_EDITOR_VALUE or 214 | GODOT_PROPERTY_USAGE_NETWORK_VALUE 215 | GODOT_PROPERTY_USAGE_DEFAULT_INTL_VALUE: cint = 216 | GODOT_PROPERTY_USAGE_STORAGE_VALUE or 217 | GODOT_PROPERTY_USAGE_EDITOR_VALUE or GODOT_PROPERTY_USAGE_NETWORK_VALUE or 218 | GODOT_PROPERTY_USAGE_INTERNATIONALIZED_VALUE 219 | GODOT_PROPERTY_USAGE_NOEDITOR_VALUE: cint = 220 | GODOT_PROPERTY_USAGE_STORAGE_VALUE or GODOT_PROPERTY_USAGE_NETWORK_VALUE 221 | 222 | type 223 | GodotPropertyUsage* {.size: sizeof(cint), pure.} = enum 224 | Storage = GODOT_PROPERTY_USAGE_STORAGE_VALUE 225 | Editor = GODOT_PROPERTY_USAGE_EDITOR_VALUE 226 | Network = GODOT_PROPERTY_USAGE_NETWORK_VALUE 227 | NoEditor = GODOT_PROPERTY_USAGE_NOEDITOR_VALUE 228 | Default = GODOT_PROPERTY_USAGE_DEFAULT_VALUE 229 | EditorHelper = GODOT_PROPERTY_USAGE_EDITOR_HELPER_VALUE 230 | Checkable = GODOT_PROPERTY_USAGE_CHECKABLE_VALUE 231 | ## used for editing global variables 232 | Checked = GODOT_PROPERTY_USAGE_CHECKED_VALUE 233 | ## used for editing global variables 234 | Internationalized = GODOT_PROPERTY_USAGE_INTERNATIONALIZED_VALUE 235 | ## hint for internationalized strings 236 | DefaultIntl = GODOT_PROPERTY_USAGE_DEFAULT_INTL_VALUE 237 | Group = GODOT_PROPERTY_USAGE_GROUP_VALUE 238 | ## used for grouping props in the editor 239 | Category = GODOT_PROPERTY_USAGE_CATEGORY_VALUE 240 | NonZero = GODOT_PROPERTY_USAGE_STORE_IF_NONZERO_VALUE 241 | ## only store if nonzero 242 | NonOne = GODOT_PROPERTY_USAGE_STORE_IF_NONONE_VALUE 243 | ## only store if false 244 | NoInstanceState = GODOT_PROPERTY_USAGE_NO_INSTANCE_STATE_VALUE 245 | RestartIfChanged = GODOT_PROPERTY_USAGE_RESTART_IF_CHANGED_VALUE 246 | ScriptVariable = GODOT_PROPERTY_USAGE_SCRIPT_VARIABLE_VALUE 247 | StoreIfNull = GODOT_PROPERTY_USAGE_STORE_IF_NULL_VALUE 248 | AnimateAsTrigger = GODOT_PROPERTY_USAGE_ANIMATE_AS_TRIGGER_VALUE 249 | UpdateAllIfModified = GODOT_PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED_VALUE 250 | 251 | GodotPropertyAttributes* {.bycopy.} = object 252 | rsetType*: GodotMethodRPCMode 253 | typ*: cint 254 | hint*: GodotPropertyHint 255 | hintString*: GodotString 256 | usage*: cint 257 | defaultValue*: GodotVariant 258 | 259 | GodotInstanceCreateFunc* {.bycopy.} = object 260 | createFunc*: 261 | proc (obj: ptr GodotObject; methodData: pointer): pointer {.noconv.} 262 | ## returns user data 263 | methodData*: pointer 264 | freeFunc*: proc (a2: pointer) {.noconv.} 265 | 266 | GodotInstanceDestroyFunc* {.bycopy.} = object 267 | destroyFunc*: 268 | proc (obj: ptr GodotObject; methodData: pointer; 269 | userData: pointer) {.noconv.} 270 | methodData*: pointer 271 | freeFunc*: proc (a2: pointer) {.noconv.} 272 | 273 | GodotInstanceMethod* {.bycopy.} = object 274 | meth*: 275 | proc (obj: ptr GodotObject; methodData: pointer; 276 | userData: pointer; numArgs: cint; 277 | args: var array[MAX_ARG_COUNT, ptr GodotVariant]): 278 | GodotVariant {.noconv.} 279 | methodData*: pointer 280 | freeFunc*: proc (a2: pointer) {.noconv.} 281 | 282 | GodotPropertySetFunc* {.bycopy.} = object 283 | setFunc*: proc (obj: ptr GodotObject; methodData: pointer; 284 | userData: pointer; value: GodotVariant) {.noconv.} 285 | methodData*: pointer 286 | freeFunc*: proc (a2: pointer) {.noconv.} 287 | 288 | GodotPropertyGetFunc* {.bycopy.} = object 289 | getFunc*: proc (obj: ptr GodotObject; methodData: pointer; 290 | userData: pointer): GodotVariant {.noconv.} 291 | methodData*: pointer 292 | freeFunc*: proc (a2: pointer) {.noconv.} 293 | 294 | GodotSignalArgument* {.bycopy.} = object 295 | name*: GodotString 296 | typ*: cint 297 | hint*: GodotPropertyHint 298 | hintString*: GodotString 299 | usage*: cint 300 | defaultValue*: GodotVariant 301 | 302 | GodotSignal* = object 303 | name*: GodotString 304 | numArgs*: cint 305 | args*: ptr GodotSignalArgument 306 | numDefaultArgs*: cint 307 | defaultArgs*: ptr GodotVariant 308 | 309 | GodotClassConstructor* = proc (): ptr GodotObject {. 310 | noconv, gcsafe, locks: 0, raises: [], tags: [].} 311 | 312 | template offset*[T](p: ptr T, offset: int): ptr T = 313 | cast[ptr T](cast[ByteAddress](p) +% (offset * sizeof(T))) -------------------------------------------------------------------------------- /godot/core/basis.nim: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018 Xored Software, Inc. 2 | 3 | import math, hashes 4 | 5 | import godotbase, vector3, quats 6 | import godotcoretypes 7 | 8 | {.push stackTrace: off.} 9 | 10 | proc setCells*(basis: var Basis, xx, xy, xz, yx, yy, yz, zx, zy, zz: float32) = 11 | basis.elements[0].x = xx 12 | basis.elements[0].y = xy 13 | basis.elements[0].z = xz 14 | basis.elements[1].x = yx 15 | basis.elements[1].y = yy 16 | basis.elements[1].z = yz 17 | basis.elements[2].x = zx 18 | basis.elements[2].y = zy 19 | basis.elements[2].z = zz 20 | 21 | proc `[]`*(self: Basis; row: range[0..2]): Vector3 {.inline.} = 22 | self.elements[row] 23 | 24 | proc `[]`*(self: var Basis; row: range[0..2]): var Vector3 {.inline.} = 25 | self.elements[row] 26 | 27 | proc `[]=`*(self: var Basis; row: range[0..2]; 28 | value: Vector3) {.inline.} = 29 | self.elements[row] = value 30 | 31 | proc `==`*(self, other: Basis): bool = 32 | for i in 0..2: 33 | for j in 0..2: 34 | if self[i][j] != other[i][j]: 35 | return false 36 | result = true 37 | 38 | proc isEqualApprox*(self, other: Basis): bool = 39 | for i in 0..2: 40 | for j in 0..2: 41 | if not self[i][j].isEqualApprox(other[i][j]): 42 | return false 43 | result = true 44 | 45 | # column accessors 46 | proc x*(self: Basis): Vector3 {.inline.} = 47 | vec3(self.elements[0].x, self.elements[1].x, self.elements[2].x) 48 | 49 | proc y*(self: Basis): Vector3 {.inline.} = 50 | vec3(self.elements[0].y, self.elements[1].y, self.elements[2].y) 51 | 52 | proc z*(self: Basis): Vector3 {.inline.} = 53 | vec3(self.elements[0].z, self.elements[1].z, self.elements[2].z) 54 | 55 | proc tdotx*(self: Basis; v: Vector3): float32 {.inline.} = 56 | self.elements[0].x * v.x + self.elements[1].x * v.y + self.elements[2].x * v.z 57 | 58 | proc tdoty*(self: Basis; v: Vector3): float32 {.inline.} = 59 | self.elements[0].y * v.x + self.elements[1].y * v.y + self.elements[2].y * v.z 60 | 61 | proc tdotz*(self: Basis; v: Vector3): float32 {.inline.} = 62 | self.elements[0].z * v.x + self.elements[1].z * v.y + self.elements[2].z * v.z 63 | 64 | proc `+`*(self, other: Basis): Basis {.inline.} = 65 | result[0] = self[0] + other[0] 66 | result[1] = self[1] + other[1] 67 | result[2] = self[2] + other[2] 68 | 69 | proc `+=`*(self: var Basis, other: Basis) {.inline.} = 70 | self[0] += other[0] 71 | self[1] += other[1] 72 | self[2] += other[2] 73 | 74 | proc `-`*(self, other: Basis): Basis {.inline.} = 75 | result[0] = self[0] - other[0] 76 | result[1] = self[1] - other[1] 77 | result[2] = self[2] - other[2] 78 | 79 | proc `-=`*(self: var Basis, other: Basis) {.inline.} = 80 | self[0] -= other[0] 81 | self[1] -= other[1] 82 | self[2] -= other[2] 83 | 84 | proc `*`*(self, other: Basis): Basis {.inline.} = 85 | result.setCells( 86 | other.tdotx(self[0]), other.tdoty(self[0]), other.tdotz(self[0]), 87 | other.tdotx(self[1]), other.tdoty(self[1]), other.tdotz(self[1]), 88 | other.tdotx(self[2]), other.tdoty(self[2]), other.tdotz(self[2]) 89 | ) 90 | 91 | proc `*=`*(self: var Basis, other: Basis) {.inline.} = 92 | self.setCells( 93 | other.tdotx(self[0]), other.tdoty(self[0]), other.tdotz(self[0]), 94 | other.tdotx(self[1]), other.tdoty(self[1]), other.tdotz(self[1]), 95 | other.tdotx(self[2]), other.tdoty(self[2]), other.tdotz(self[2]) 96 | ) 97 | 98 | proc `*=`*(self: var Basis; b: float32) {.inline.} = 99 | self[0] *= b 100 | self[1] *= b 101 | self[2] *= b 102 | 103 | proc `*`*(self: Basis; b: float32): Basis {.inline.} = 104 | result = self 105 | result *= b 106 | 107 | proc initBasis*(): Basis {.inline.} = 108 | result.setCells( 109 | 1, 0, 0, 110 | 0, 1, 0, 111 | 0, 0, 1 112 | ) 113 | 114 | proc initBasis*(row0, row1, row2: Vector3): Basis {.inline.} = 115 | Basis(elements: [row0, row1, row2]) 116 | 117 | proc initBasis*(xx, xy, xz, yx, yy, yz, zx, zy, zz: float32): Basis = 118 | result.setCells(xx, xy, xz, yx, yy, yz, zx, zy, zz) 119 | 120 | proc initBasis*(euler: Quat): Basis {.inline.} = 121 | let d = euler.lengthSquared() 122 | let s = 2.0 / d 123 | let xs = euler.x * s 124 | let ys = euler.y * s 125 | let zs = euler.z * s 126 | let wx = euler.w * xs 127 | let wy = euler.w * ys 128 | let wz = euler.w * zs 129 | let xx = euler.x * xs 130 | let xy = euler.x * ys 131 | let xz = euler.x * zs 132 | let yy = euler.y * ys 133 | let yz = euler.y * zs 134 | let zz = euler.z * zs 135 | result.setCells( 136 | 1.0 - (yy + zz), xy - wz, xz + wy, 137 | xy + wz, 1.0 - (xx + zz), yz - wx, 138 | xz - wy, yz + wx, 1.0 - (xx + yy)) 139 | 140 | proc setAxisAngle(self: var Basis, axis: Vector3, phi: float32) = 141 | assert(axis.isNormalized()) 142 | let axisSq = vec3(axis.x * axis.x, axis.y * axis.y, axis.z * axis.z) 143 | 144 | let cosine = cos(phi); 145 | let sine = sin(phi); 146 | 147 | self.elements[0].x = axisSq.x + cosine * (1.0 - axisSq.x) 148 | self.elements[0].y = axis.x * axis.y * (1.0 - cosine) - axis.z * sine 149 | self.elements[0].z = axis.z * axis.x * (1.0 - cosine) + axis.y * sine 150 | 151 | self.elements[1].x = axis.x * axis.y * (1.0 - cosine) + axis.z * sine 152 | self.elements[1].y = axisSq.y + cosine * (1.0 - axisSq.y) 153 | self.elements[1].z = axis.y * axis.z * (1.0 - cosine) - axis.x * sine 154 | 155 | self.elements[2].x = axis.z * axis.x * (1.0 - cosine) - axis.y * sine 156 | self.elements[2].y = axis.y * axis.z * (1.0 - cosine) + axis.x * sine 157 | self.elements[2].z = axisSq.z + cosine * (1.0 - axisSq.z) 158 | 159 | proc initBasis*(axis: Vector3, phi: float32): Basis {.inline.} = 160 | result.setAxisAngle(axis, phi) 161 | 162 | proc setEuler*(self: var Basis, euler: Vector3) = 163 | var c = cos(euler.x) 164 | var s = sin(euler.x) 165 | 166 | let xmat = initBasis(1.0, 0.0, 0.0, 0.0, c, -s, 0.0, s, c) 167 | 168 | c = cos(euler.y) 169 | s = sin(euler.y) 170 | let ymat = initBasis(c, 0.0, s, 0.0, 1.0, 0.0, -s, 0.0, c) 171 | 172 | c = cos(euler.z) 173 | s = sin(euler.z) 174 | let zmat = initBasis(c, -s, 0.0, s, c, 0.0, 0.0, 0.0, 1.0) 175 | 176 | self = xmat * (ymat * zmat) 177 | 178 | proc getEuler*(self: Basis): Vector3 = 179 | result.y = arcsin(self.elements[0].z) 180 | if result.y < PI * 0.5: 181 | if result.y > -PI * 0.5: 182 | result.x = arctan2(-self.elements[1].z, self.elements[2].z) 183 | result.z = arctan2(-self.elements[0].y, self.elements[0].x) 184 | else: 185 | let r = arctan2(self.elements[1].x, self.elements[1].y) 186 | result.x = -r 187 | else: 188 | let r = arctan2(self.elements[0].y, self.elements[1].y) 189 | result.x = r 190 | 191 | proc initBasis*(euler: Vector3): Basis {.inline.} = 192 | result.setEuler(euler) 193 | 194 | proc outer*(self, other: Vector3): Basis {.inline.} = 195 | let row0 = vec3(self.x * other.x, self.x * other.y, self.x * other.z) 196 | let row1 = vec3(self.y * other.x, self.y * other.y, self.y * other.z) 197 | let row2 = vec3(self.z * other.x, self.z * other.y, self.z * other.z) 198 | initBasis(row0, row1, row2) 199 | 200 | proc toDiagonalMatrix*(self: Vector3): Basis {.inline.} = 201 | initBasis( 202 | self.x, 0, 0, 203 | 0, self.y, 0, 204 | 0, 0, self.z 205 | ) 206 | 207 | proc `$`*(self: Basis): string {.inline.} = 208 | result = newStringOfCap(128) 209 | for i in 0..2: 210 | for j in 0..2: 211 | if i != 0 or j != 0: 212 | result.add(", ") 213 | result.add($self[i][j]) 214 | 215 | proc hash*(self: Basis): Hash {.inline.} = 216 | !$(self.elements[0].hash() !& self.elements[1].hash() !& self.elements[2].hash()) 217 | 218 | template cofac(row1, col1, row2, col2: int): float32 = 219 | self.elements[row1][col1] * self.elements[row2][col2] - 220 | self.elements[row1][col2] * self.elements[row2][col1] 221 | 222 | proc determinant(self: Basis): float32 {.inline.} = 223 | self[0][0] * cofac(1, 1, 2, 2) - 224 | self[1][0] * cofac(0, 1, 2, 2) + 225 | self[2][0] * cofac(0, 1, 1, 2) 226 | 227 | proc invert*(self: var Basis) = 228 | let co = [cofac(1, 1, 2, 2), cofac(1, 2, 2, 0), cofac(1, 0, 2, 1)] 229 | let det = self.elements[0][0] * co[0] + 230 | self.elements[0][1] * co[1] + 231 | self.elements[0][2] * co[2] 232 | assert(det != 0) 233 | let s = 1.0'f32 / det 234 | self.setCells( 235 | co[0] * s, cofac(0, 2, 2, 1) * s, cofac(0, 1, 1, 2) * s, 236 | co[1] * s, cofac(0, 0, 2, 2) * s, cofac(0, 2, 1, 0) * s, 237 | co[2] * s, cofac(0, 1, 2, 0) * s, cofac(0, 0, 1, 1) * s 238 | ) 239 | 240 | proc inverse*(self: Basis): Basis {.inline.} = 241 | result = self 242 | result.invert() 243 | 244 | proc axis*(self: Basis; idx: range[0..2]): Vector3 {.inline.} = 245 | vec3(self[0][idx], self[1][idx], self[2][idx]) 246 | 247 | proc setAxis*(self: var Basis; idx: range[0..2]; value: Vector3) {.inline.} = 248 | self.elements[0][idx] = value.x 249 | self.elements[1][idx] = value.y 250 | self.elements[2][idx] = value.z 251 | 252 | proc row*(self: Basis; row: range[0..2]): Vector3 {.inline.} = 253 | self.elements[row] 254 | 255 | proc setRow*(self: var Basis; row: range[0..2]; value: Vector3) {.inline.} = 256 | self.elements[row] = value 257 | 258 | proc getMainDiagonal*(self: Basis): Vector3 {.inline.} = 259 | vec3(self.elements[0][0], self.elements[1][1], self.elements[2][2]) 260 | 261 | proc zero*(self: var Basis) {.inline.} = 262 | self.elements[0].zero() 263 | self.elements[1].zero() 264 | self.elements[2].zero() 265 | 266 | proc orthonormalize(self: var Basis) = 267 | var x = self.axis(0) 268 | var y = self.axis(1) 269 | var z = self.axis(2) 270 | 271 | x.normalize() 272 | y = y - x * x.dot(y) 273 | y.normalize() 274 | z = z - x * x.dot(z) - y * y.dot(z) 275 | z.normalize() 276 | 277 | self.setAxis(0, x) 278 | self.setAxis(1, y) 279 | self.setAxis(2, z) 280 | 281 | proc orthonormalized*(self: Basis): Basis {.inline.} = 282 | result = self 283 | result.orthonormalize() 284 | 285 | proc transpose*(self: var Basis) {.inline.} = 286 | swap(self.elements[0].y, self.elements[1].x) 287 | swap(self.elements[0].z, self.elements[2].x) 288 | swap(self.elements[1].z, self.elements[2].y) 289 | 290 | proc transposed*(self: Basis): Basis {.inline.} = 291 | result = self 292 | result.transpose() 293 | 294 | proc isOrthogonal*(self: Basis): bool {.inline.} = 295 | let id = initBasis() 296 | let m = self * self.transposed() 297 | result = id.isEqualApprox(m) 298 | 299 | proc isRotation*(self: Basis): bool {.inline.} = 300 | self.determinant().isEqualApprox(1.0) and self.isOrthogonal() 301 | 302 | proc isSymmetric*(self: Basis): bool {.inline.} = 303 | if not self.elements[0][1].isEqualApprox(self.elements[1][0]): 304 | return false 305 | if not self.elements[0][2].isEqualApprox(self.elements[2][0]): 306 | return false 307 | if not self.elements[1][2].isEqualApprox(self.elements[2][1]): 308 | return false 309 | result = true 310 | 311 | proc scale*(self: var Basis, scale: Vector3) = 312 | self[0].x *= scale.x 313 | self[0].y *= scale.x 314 | self[0].z *= scale.x 315 | self[1].x *= scale.y 316 | self[1].y *= scale.y 317 | self[1].z *= scale.y 318 | self[2].x *= scale.z 319 | self[2].y *= scale.z 320 | self[2].z *= scale.z 321 | 322 | proc scaled*(self: Basis, scale: Vector3): Basis = 323 | result = self 324 | result.scale(scale) 325 | 326 | proc rotated*(self: Basis; axis: Vector3; phi: float32): Basis {.inline.} = 327 | initBasis(axis, phi) * self 328 | 329 | proc rotate*(self: var Basis; axis: Vector3; phi: float32) {.inline.} = 330 | self = self.rotated(axis, phi) 331 | 332 | proc rotated*(self: Basis; euler: Vector3): Basis {.inline.} = 333 | initBasis(euler) * self 334 | 335 | proc rotate*(self: var Basis; euler: Vector3) {.inline.} = 336 | self = self.rotated(euler) 337 | 338 | proc getScale*(self: Basis): Vector3 = 339 | let detSign = if self.determinant() > 0: 1'f32 else: -1'f32 340 | result = detSign * vec3( 341 | vec3(self.elements[0].x, self.elements[1].x, self.elements[2].x).length(), 342 | vec3(self.elements[0].y, self.elements[1].y, self.elements[2].y).length(), 343 | vec3(self.elements[0].z, self.elements[1].z, self.elements[2].z).length(), 344 | ) 345 | 346 | proc getRotation*(self: Basis): Vector3 {.inline.} = 347 | var m = self.orthonormalized() 348 | let det = m.determinant() 349 | if det < 0: 350 | m.scale(vec3(-1, -1, -1)) 351 | result = m.getEuler() 352 | 353 | proc setScale*(self: var Basis; scale: Vector3) = 354 | let e = self.getEuler() 355 | self = initBasis() # reset to identity 356 | self.scale(scale) 357 | self.rotate(e) 358 | 359 | proc setRotationEuler*(self: var Basis; euler: Vector3) = 360 | let s = self.getScale() 361 | self = initBasis() 362 | self.scale(s) 363 | self.rotate(euler) 364 | 365 | proc setRotationAxisAngle*(self: var Basis; axis: Vector3; angle: float32) = 366 | let s = self.getScale() 367 | self = initBasis() 368 | self.scale(s) 369 | self.rotate(axis, angle) 370 | 371 | proc asQuat*(self: Basis): Quat = 372 | let trace = self.elements[0].x + self.elements[1].y + self.elements[2].z 373 | var temp: array[4, float32] 374 | if trace > 0'f32: 375 | var s = sqrt(trace + 1.0) 376 | temp[3] = s * 0.5 377 | s = 0.5 / s 378 | 379 | temp[0] = (self.elements[2].y - self.elements[1].z) * s 380 | temp[1] = (self.elements[0].z - self.elements[2].x) * s 381 | temp[2] = (self.elements[1].x - self.elements[0].y) * s 382 | else: 383 | let i = if self.elements[0].x < self.elements[1].y: 384 | if self.elements[1].y < self.elements[2].z: 2 else: 1 385 | else: 386 | if self.elements[0].x < self.elements[2].z: 2 else: 0 387 | let j = (i + 1) mod 3 388 | let k = (i + 2) mod 3 389 | 390 | var s = sqrt(self.elements[i][i] - self.elements[j][j] - 391 | self.elements[k][k] + 1.0) 392 | temp[i] = s * 0.5 393 | s = 0.5 / s 394 | 395 | temp[3] = (self.elements[k][j] - self.elements[j][k]) * s 396 | temp[j] = (self.elements[j][i] + self.elements[i][j]) * s 397 | temp[k] = (self.elements[k][i] + self.elements[i][k]) * s 398 | 399 | result = initQuat(temp[0], temp[1], temp[2], temp[3]) 400 | 401 | proc xform*(self: Basis; v: Vector3): Vector3 {.inline.} = 402 | vec3( 403 | self.elements[0].dot(v), 404 | self.elements[1].dot(v), 405 | self.elements[2].dot(v) 406 | ) 407 | 408 | proc xformInv*(self: Basis; v: Vector3): Vector3 {.inline.} = 409 | vec3( 410 | self.elements[0].x * v.x + self.elements[1].x * v.y + self.elements[2].x * v.z, 411 | self.elements[0].y * v.x + self.elements[1].y * v.y + self.elements[2].y * v.z, 412 | self.elements[0].z * v.x + self.elements[1].z * v.y + self.elements[2].z * v.z, 413 | ) 414 | 415 | const orthoBases = [ 416 | initBasis(1, 0, 0, 0, 1, 0, 0, 0, 1), 417 | initBasis(0, -1, 0, 1, 0, 0, 0, 0, 1), 418 | initBasis(-1, 0, 0, 0, -1, 0, 0, 0, 1), 419 | initBasis(0, 1, 0, -1, 0, 0, 0, 0, 1), 420 | initBasis(1, 0, 0, 0, 0, -1, 0, 1, 0), 421 | initBasis(0, 0, 1, 1, 0, 0, 0, 1, 0), 422 | initBasis(-1, 0, 0, 0, 0, 1, 0, 1, 0), 423 | initBasis(0, 0, -1, -1, 0, 0, 0, 1, 0), 424 | initBasis(1, 0, 0, 0, -1, 0, 0, 0, -1), 425 | initBasis(0, 1, 0, 1, 0, 0, 0, 0, -1), 426 | initBasis(-1, 0, 0, 0, 1, 0, 0, 0, -1), 427 | initBasis(0, -1, 0, -1, 0, 0, 0, 0, -1), 428 | initBasis(1, 0, 0, 0, 0, 1, 0, -1, 0), 429 | initBasis(0, 0, -1, 1, 0, 0, 0, -1, 0), 430 | initBasis(-1, 0, 0, 0, 0, -1, 0, -1, 0), 431 | initBasis(0, 0, 1, -1, 0, 0, 0, -1, 0), 432 | initBasis(0, 0, 1, 0, 1, 0, -1, 0, 0), 433 | initBasis(0, -1, 0, 0, 0, 1, -1, 0, 0), 434 | initBasis(0, 0, -1, 0, -1, 0, -1, 0, 0), 435 | initBasis(0, 1, 0, 0, 0, -1, -1, 0, 0), 436 | initBasis(0, 0, 1, 0, -1, 0, 1, 0, 0), 437 | initBasis(0, 1, 0, 0, 0, 1, 1, 0, 0), 438 | initBasis(0, 0, -1, 0, 1, 0, 1, 0, 0), 439 | initBasis(0, -1, 0, 0, 0, -1, 1, 0, 0) 440 | ] 441 | 442 | proc orthogonalIndex*(self: Basis): int = 443 | var orth = self 444 | for i in 0..2: 445 | for j in 0..2: 446 | var v = orth[i][j] 447 | if v > 0.5: 448 | v = 1.0'f32 449 | elif v < -0.5: 450 | v = -1.0'f32 451 | else: 452 | v = 0'f32 453 | orth[i][j] = v 454 | 455 | for idx, base in orthoBases: 456 | if base == orth: 457 | return idx 458 | 459 | proc setOrthogonalIndex*(self: var Basis, idx: range[0..23]) = 460 | self = orthoBases[idx] 461 | 462 | proc rotate*(self: var Vector3; axis: Vector3; phi: float32) = 463 | self = initBasis(axis, phi).xform(self) 464 | 465 | proc rotated*(self: Vector3; axis: Vector3; phi: float32): Vector3 = 466 | result = self 467 | result.rotate(axis, phi) 468 | 469 | {.pop.} # stackTrace: off 470 | -------------------------------------------------------------------------------- /godot/nim/godotmacros.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Xored Software, Inc. 2 | 3 | import macros, tables, typetraits, strutils, sets, sequtils, options, algorithm 4 | import godotinternal, internal/godotvariants 5 | import godotnim, core/variants 6 | 7 | type 8 | VarDecl = ref object 9 | name: NimNode 10 | typ: NimNode 11 | defaultValue: NimNode 12 | isNoGodot: bool 13 | hint: Option[string] 14 | hintStr: Option[string] 15 | usage: NimNode 16 | isExported: bool 17 | 18 | MethodDecl = ref object 19 | name: string 20 | args: seq[VarDecl] 21 | isVirtual: bool 22 | returnType: NimNode 23 | nimNode: NimNode 24 | isNoGodot: bool 25 | 26 | ObjectDecl = ref object 27 | name: string 28 | parentName: string 29 | fields: seq[VarDecl] 30 | methods: seq[MethodDecl] 31 | isTool: bool 32 | 33 | include "internal/backwardcompat.inc.nim" 34 | 35 | proc godotToNim[T](val: Variant): (T, ConversionResult) = 36 | mixin fromVariant 37 | result[1] = fromVariant(result[0], val) 38 | 39 | proc nimToGodot[T](val: T): Variant = 40 | mixin toVariant 41 | when compiles(toVariant(val)): 42 | result = toVariant(val) 43 | else: 44 | const err = "Cannot convert Nim value of type " & T.name & 45 | " into Variant" 46 | {.error: err.} 47 | 48 | proc extractNames(definition: NimNode): 49 | tuple[name, parentName: string] = 50 | if definition.kind == nnkIdent: 51 | result.name = definition.strVal 52 | else: 53 | if not (definition.kind == nnkInfix and 54 | definition[0].strVal == "of"): 55 | error("invalid type definition", definition) 56 | result.name = definition[1].strVal 57 | case definition[2].kind: 58 | of nnkIdent: 59 | result.parentName = definition[2].strVal 60 | else: 61 | error("parent type expected", definition[2]) 62 | 63 | when not declared(newRStrLit): 64 | proc newRStrLit(s: string): NimNode {.compileTime.} = 65 | result = newNimNode(nnkRStrLit) 66 | result.strVal = s 67 | 68 | proc newCStringLit(s: string): NimNode {.compileTime.} = 69 | newNimNode(nnkCallStrLit).add(ident("cstring"), newRStrLit(s)) 70 | 71 | iterator pragmas(node: NimNode): 72 | tuple[key: string, value: NimNode, index: int] = 73 | assert node.kind in {nnkPragma, nnkEmpty} 74 | for index in countdown(node.len - 1, 0): 75 | if node[index].kind == nnkExprColonExpr: 76 | yield (node[index][0].strVal, node[index][1], index) 77 | elif node[index].kind == nnkIdent: 78 | yield (node[index].strVal, nil, index) 79 | 80 | proc removePragmaNode(statement: NimNode, 81 | pname: string): NimNode {.compileTime.} = 82 | ## Removes the pragma from the node and returns value of the pragma 83 | ## Works for routine nodes or nnkPragmaExpr 84 | if not (RoutineNodes.contains(statement.kind) or 85 | statement.kind == nnkPragmaExpr): 86 | return nil 87 | 88 | result = nil 89 | var pragmas = if RoutineNodes.contains(statement.kind): statement.pragma() 90 | else: statement[1] 91 | for ident, val, i in pragmas(pragmas): 92 | if ident.eqIdent(pname): 93 | pragmas.del(i) 94 | return val 95 | 96 | proc removePragma(statement: NimNode, pname: string): bool = 97 | ## Removes the pragma from the node and returns whether pragma was removed 98 | if not (RoutineNodes.contains(statement.kind) or 99 | statement.kind == nnkPragmaExpr): 100 | return false 101 | var pragmas = if RoutineNodes.contains(statement.kind): statement.pragma() 102 | else: statement[1] 103 | for ident, val, i in pragmas(pragmas): 104 | if ident.eqIdent(pname): 105 | pragmas.del(i) 106 | return true 107 | 108 | proc removeStrPragma(statement: NimNode, 109 | pname: string): Option[string] {.compileTime.} = 110 | ## Removes the pragma from the node and returns value of the pragma 111 | ## Works for routine nodes or nnkPragmaExpr 112 | let node = removePragmaNode(statement, pname) 113 | result = if node.isNil: none(string) 114 | else: some($node) 115 | 116 | proc isExported(node: NimNode): bool {.compileTime.} = 117 | if node.kind == nnkPragmaExpr: 118 | result = isExported(node[0]) 119 | elif node.kind == nnkPostfix: 120 | result = ($node[0] == "*") 121 | 122 | proc identDefsToVarDecls(identDefs: NimNode): seq[VarDecl] = 123 | assert(identDefs.kind == nnkIdentDefs) 124 | result = newSeqOfCap[VarDecl](identDefs.len - 2) 125 | 126 | var typ = identDefs[identDefs.len - 2] 127 | if typ.kind == nnkEmpty: 128 | let defaultValue = identDefs[identDefs.len - 1] 129 | if defaultValue.kind != nnkEmpty: 130 | typ = newCall("type", defaultValue) 131 | 132 | for i in 0..<(identDefs.len - 2): 133 | let nameNode = identDefs[i].copyNimTree() 134 | let hint = removeStrPragma(nameNode, "hint") 135 | let hintStr = removeStrPragma(nameNode, "hintStr") 136 | let usage = removePragmaNode(nameNode, "usage") 137 | let isGdExport = removePragma(nameNode, "gdExport") 138 | 139 | result.add(VarDecl( 140 | name: if nameNode.kind == nnkPragmaExpr: nameNode[0].basename() 141 | else: nameNode.basename(), 142 | typ: typ, 143 | defaultValue: identDefs[identDefs.len - 1], 144 | hint: hint, 145 | hintStr: hintStr, 146 | isNoGodot: not isGdExport, 147 | usage: usage, 148 | isExported: nameNode.isExported() 149 | )) 150 | 151 | proc parseMethod(meth: NimNode): MethodDecl = 152 | assert(meth.kind in {nnkProcDef, nnkMethodDef}) 153 | let isGdExport = removePragma(meth, "gdExport") 154 | let isNoGodot = (meth.kind != nnkMethodDef and not isGdExport) or 155 | removePragma(meth, "noGdExport") 156 | result = MethodDecl( 157 | name: $meth[0].basename, 158 | args: newSeq[VarDecl](), 159 | returnType: meth[3][0], 160 | isVirtual: meth.kind == nnkMethodDef, 161 | isNoGodot: isNoGodot, 162 | nimNode: meth 163 | ) 164 | for i in 1..`_: 675 | ## 676 | ## .. code-block:: nim 677 | ## import godot, editor_plugin 678 | ## 679 | ## gdobj(MyTool of EditorPlugin, tool): 680 | ## method enterTree*() = 681 | ## print("MyTool initialized!") 682 | ## 683 | ## Objects can be instantiated by invoking 684 | ## `gdnew `_ or by using 685 | ## `load `_ or any other way 686 | ## that you can find in `Godot API `_. 687 | let typeDef = parseType(ast) 688 | result = genType(typeDef) 689 | -------------------------------------------------------------------------------- /godot/nim/godotnim.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Xored Software, Inc. 2 | 3 | import tables, typetraits, macros, unicode, strutils, sets, options 4 | import gdnativeapi 5 | import core/godotcoretypes, core/godotbase 6 | import core/vector2, core/rect2, 7 | core/vector3, core/transform2d, 8 | core/planes, core/quats, core/aabb, 9 | core/basis, core/transforms, core/colors, 10 | core/nodepaths, core/rids, core/dictionaries, 11 | core/arrays, core/poolarrays, core/variants 12 | import godotinternal 13 | 14 | ## This module defines ``NimGodotObject`` and ``toVariant``/``fromVariant`` 15 | ## converters for Nim types. The converters are used by 16 | ## `gdobj `_ macro to import/export 17 | ## values from/to Godot (editor, GDScript). 18 | ## 19 | ## You can also allow conversion of any custom type ``MyType`` by implementing: 20 | ## 21 | ## .. code-block:: nim 22 | ## proc godotTypeInfo*(T: typedesc[MyType]): GodotTypeInfo 23 | ## proc toVariant*(self: MyType): Variant 24 | ## proc fromVariant*(self: var MyType, val: Variant): ConversionResult 25 | ## 26 | ## Implementing ``godotTypeInfo`` is optional and is necessary only if you want 27 | ## the type to be editable from the editor. 28 | 29 | type 30 | NimGodotObject* = ref object of RootObj 31 | ## The base type all Godot types inherit from. 32 | ## Manages lifecycle of the wrapped ``GodotObject``. 33 | godotObject: ptr GodotObject 34 | linkedObjectPtr: pointer 35 | ## Wrapper around native object that is the container of the Nim "script" 36 | ## This is needed for `of` checks and `as` conversions to work as 37 | ## expected. For example, Nim type may inherit from ``Spatial``, but the 38 | ## script is attached to ``Particles``. In this case conversion to 39 | ## ``Particles`` is valid, but Nim type system is not aware of that. 40 | ## This works in both directions - for linked native object this 41 | ## reference points to Nim object. 42 | ## This is stored as a raw pointer to avoid reference cycles and therefore 43 | ## improve GC performance. 44 | isRef*: bool 45 | isFinalized: bool 46 | isNative: bool 47 | 48 | ConversionResult* {.pure.} = enum 49 | ## Conversion result to return from ``fromVariant`` procedure. 50 | OK, 51 | TypeError, 52 | ## Type mismatch 53 | RangeError 54 | ## Types match, but the value is out of range. 55 | ## Mainly used for numeric (ordinal) types. 56 | 57 | SomeUnsignedInt = uint8 or uint16 or uint32 or uint64 or uint or cuint 58 | SomeSignedInt = int8 or int16 or int32 or int64 or int or cint 59 | SomeFloat = float32 or float64 or cfloat 60 | 61 | SomeGodot = bool or Vector2 or Rect2 or Vector3 or 62 | Transform2D or Plane or Quat or AABB or 63 | Basis or Transform or Color or NodePath or 64 | RID or GodotObject or Dictionary or Array or 65 | PoolByteArray or PoolIntArray or PoolRealArray or 66 | PoolStringArray or PoolVector2Array or PoolVector3Array or 67 | PoolColorArray or GodotString 68 | 69 | SomeGodotOrNum = SomeGodot or SomeSignedInt or SomeUnsignedInt or SomeFloat 70 | 71 | CallError* = object of Exception 72 | ## Raised by wrappers in case of an incorrect dynamic invocation. 73 | ## For example, if incorrect number of arguments were passed or they had 74 | ## unexpected types. 75 | err*: VariantCallError 76 | ## The error as returned by Godot 77 | 78 | ObjectInfo = object 79 | constructor: proc(): NimGodotObject {.gcsafe, nimcall.} 80 | baseNativeClass: cstring 81 | isNative: bool 82 | isRef: bool 83 | 84 | GodotTypeInfo* = object 85 | ## Type information provided to Godot editor 86 | variantType*: VariantType 87 | hint*: GodotPropertyHint 88 | hintStr*: string 89 | ## Format depends on the type and the hint. 90 | ## For example, for Enum ``hint`` this is a comma separated list of 91 | ## values. 92 | ## See documentation of ``GodotPropertyHint`` for description of formats. 93 | 94 | FNV1Hash = uint32 95 | 96 | include "internal/backwardcompat.inc.nim" 97 | 98 | proc isFinalized*(obj: NimGodotObject): bool {.inline.} = 99 | obj.isFinalized 100 | 101 | var classRegistry {.threadvar.}: TableRef[FNV1Hash, ObjectInfo] 102 | var classRegistryStatic* {.compileTime.}: TableRef[FNV1Hash, ObjectInfo] 103 | ## Compile-time variable used for implementation of several procedures 104 | ## and macros 105 | static: 106 | classRegistryStatic = newTable[FNV1Hash, ObjectInfo]() 107 | 108 | var nativeClasses {.compileTime.} = newSeq[string]() 109 | var refClasses* {.compileTime.} = newSeq[string]() 110 | 111 | template initFNV1Hash(hash: var FNV1Hash) = 112 | hash = 0x811c9dc5'u32 113 | 114 | template appendFNV1Hash(hash: var FNV1Hash, val: uint8) = 115 | block: 116 | let u64hash = hash.uint64 117 | hash = (( 118 | u64hash + 119 | (u64hash shl 1'u64) + 120 | (u64hash shl 4'u64) + 121 | (u64hash shl 7'u64) + 122 | (u64hash shl 8'u64) + 123 | (u64hash shl 24'u64)) and 0xFFFFFFFF'u32).uint32 xor val 124 | 125 | {.push stackTrace:off.} 126 | proc lsb(c: ptr cwchar_t): char {.noinit, inline.} = 127 | {.emit: [result, " = (char)(", c[]," & 0xFF);"]} 128 | {.pop.} 129 | 130 | proc fnv1Hash(godotClassName: GodotString): FNV1Hash = 131 | var charsCount = godotClassName.len 132 | let charsPtr = godotClassName.dataPtr 133 | if charsCount > 2 and 134 | charsPtr.offset(charsCount - 2).lsb == 'S' and 135 | charsPtr.offset(charsCount - 1).lsb == 'W': 136 | charsCount -= 2 137 | 138 | initFNV1Hash(result) 139 | for i in 0..= charsCount: 152 | break 153 | let firstByte = uint8(rune.uint64 and 0xFF'u64) 154 | appendFNV1Hash(result, firstByte) 155 | # We don't really need to calculate hash of other bytes, 156 | # since we only use hashes of ASCII strings 157 | inc i 158 | 159 | proc getClassName*(o: NimGodotObject): string = 160 | o.godotObject.getClassName() 161 | 162 | var unreferenceMethodBind {.threadvar.}: ptr GodotMethodBind 163 | proc unreference(o: ptr GodotObject): bool = 164 | if isNil(unreferenceMethodBind): 165 | unreferenceMethodBind = getMethod(cstring"Reference", 166 | cstring"unreference") 167 | unreferenceMethodBind.ptrCall(o, nil, addr(result)) 168 | 169 | var referenceMethodBind {.threadvar.}: ptr GodotMethodBind 170 | proc reference(o: ptr GodotObject): bool {.discardable.} = 171 | if isNil(referenceMethodBind): 172 | referenceMethodBind = getMethod(cstring"Reference", 173 | cstring"reference") 174 | referenceMethodBind.ptrCall(o, nil, addr result) 175 | 176 | var initRefMethodBind {.threadvar.}: ptr GodotMethodBind 177 | proc initRef(o: ptr GodotObject): bool {.discardable.} = 178 | if isNil(initRefMethodBind): 179 | initRefMethodBind = getMethod(cstring"Reference", 180 | cstring"init_ref") 181 | initRefMethodBind.ptrCall(o, nil, addr result) 182 | 183 | proc deinit*(obj: NimGodotObject) = 184 | ## Destroy the object. You only need to call this for objects not inherited 185 | ## from Reference, where manual lifecycle control is necessary. 186 | assert(not obj.godotObject.isNil) 187 | obj.godotObject.deinit() 188 | obj.godotObject = nil 189 | 190 | proc linkedObject(obj: NimGodotObject): NimGodotObject {.inline.} = 191 | cast[NimGodotObject](obj.linkedObjectPtr) 192 | 193 | proc nimGodotObjectFinalizer*[T: NimGodotObject](obj: T) = 194 | if obj.godotObject.isNil or obj.isNative: return 195 | # important to set it before so that ``unreference`` is aware 196 | obj.isFinalized = true 197 | if (obj.isRef or not obj.linkedObject.isNil and obj.linkedObject.isRef) and 198 | obj.godotObject.unreference(): 199 | if not obj.linkedObject.isNil: 200 | GC_unref(obj.linkedObject) 201 | obj.deinit() 202 | 203 | macro baseNativeType(T: typedesc): cstring = 204 | var t = getType(getType(T)[1][1]) 205 | var baseT: string 206 | while true: 207 | let typeName = ($t[1][1]).split(':')[0] 208 | if typeName in nativeClasses: 209 | baseT = typeName 210 | break 211 | if typeName == "NimGodotObject": 212 | break 213 | t = getType(t[1][1]) 214 | if baseT.len == 0: 215 | result = newNilLit() 216 | else: 217 | let rStr = newNimNode(nnkRStrLit) 218 | rStr.strVal = baseT 219 | result = newNimNode(nnkCallStrLit).add(ident("cstring"), rStr) 220 | 221 | proc inherits(t: NimNode, parent: string): bool {.compileTime.} = 222 | var curT = t 223 | while true: 224 | let typeName = ($curT[1][1]).split(':')[0] 225 | if typeName == parent: 226 | return true 227 | if typeName == "NimGodotObject": 228 | break 229 | curT = getType(curT[1][1]) 230 | 231 | macro isReference(T: typedesc): bool = 232 | result = if inherits(getType(T), "Reference"): ident("true") 233 | else: ident("false") 234 | 235 | macro isResource(T: typedesc): bool = 236 | result = if inherits(getType(T), "Resource"): ident("true") 237 | else: ident("false") 238 | 239 | template registerClass*(T: typedesc; godotClassName: string or cstring, 240 | native: bool) = 241 | ## Registers the specified Godot type. 242 | ## Used by ``gdobj`` macro and `godotapigen `_. 243 | if classRegistry.isNil: 244 | classRegistry = newTable[FNV1Hash, ObjectInfo]() 245 | let constructor = proc(): NimGodotObject = 246 | var t: T 247 | new(t, nimGodotObjectFinalizer[T]) 248 | result = t 249 | 250 | const base = baseNativeType(T) 251 | const isRef: bool = isReference(T) 252 | let objInfo = ObjectInfo( 253 | constructor: constructor, 254 | baseNativeClass: base, 255 | isNative: native, 256 | isRef: isRef 257 | ) 258 | classRegistry[fnv1Hash($godotClassName)] = objInfo 259 | static: 260 | let objInfoStatic = ObjectInfo( 261 | baseNativeClass: base, 262 | isNative: native, 263 | isRef: isRef, 264 | ) 265 | let nameHash = fnv1Hash($godotClassName) 266 | if not classRegistryStatic.contains(nameHash): 267 | classRegistryStatic[nameHash] = objInfoStatic 268 | elif not endsWith($godotClassName, "SW"): 269 | # For simplicity we assume that all class names must have 270 | # different hashes 271 | # If this exception is ever raised, I guess, we should 272 | # implement a proper collision resolving 273 | raise newException(Exception, "Hash collision " & $godotClassName) 274 | when isRef: 275 | static: 276 | refClasses.add(T.name) 277 | when native: 278 | static: 279 | nativeClasses.add(T.name) 280 | 281 | proc newNimGodotObject[T: NimGodotObject]( 282 | godotObject: ptr GodotObject, godotClassName: GodotString, noRef: bool): T = 283 | assert(not classRegistry.isNil) 284 | assert(not godotObject.isNil) 285 | let objInfo = classRegistry.getOrDefault(fnv1Hash(godotClassName)) 286 | if objInfo.constructor.isNil: 287 | printError("Nim constructor not found for class " & $godotClassName) 288 | else: 289 | result = T(objInfo.constructor()) 290 | result.godotObject = godotObject 291 | result.isRef = objInfo.isRef 292 | if not noRef and objInfo.isRef: 293 | result.godotObject.reference() 294 | 295 | proc asNimGodotObject*[T: NimGodotObject]( 296 | godotObject: ptr GodotObject, forceNativeObject, noRef: bool = false): T = 297 | ## Wraps ``godotObject`` into Nim type ``T``. 298 | ## This is used by `godotapigen `_ and should rarely be 299 | ## used by anything else. 300 | if godotObject.isNil: return nil 301 | let userDataPtr = godotObject.getUserData() 302 | if not userDataPtr.isNil and not forceNativeObject: 303 | result = cast[T](userDataPtr) 304 | if result.godotObject != godotObject: 305 | # Could be data from other bindings 306 | result = nil 307 | if result.isNil: 308 | var classNameStr = godotObject.getClassNameRaw() 309 | result = newNimGodotObject[T]( 310 | godotObject, classNameStr, 311 | forceNativeObject or noRef) 312 | deinit(classNameStr) 313 | 314 | proc newVariant*(obj: NimGodotObject): Variant {.inline.} = 315 | newVariant(obj.godotObject) 316 | 317 | proc asObject*[T: NimGodotObject](v: Variant): T {.inline.} = 318 | ## Converts ``v`` to object of type ``T``. 319 | ## Returns ``nil`` if the conversion cannot be performed 320 | ## (``v``'s type is not an Object or it's an object of an incompatible type) 321 | asNimGodotObject[T](v.asGodotObject()) 322 | 323 | proc asObject*(v: Variant, T: typedesc[NimGodotObject]): T {.inline.} = 324 | ## Converts ``v`` to object of type ``T``. 325 | ## Returns ``nil`` if the conversion cannot be performed 326 | ## (``v``'s type is not an Object or it's an object of an incompatible type) 327 | asNimGodotObject[T](v.asGodotObject()) 328 | 329 | proc `as`*[T: NimGodotObject](obj: NimGodotObject, t: typedesc[T]): T = 330 | ## Converts the ``obj`` into the specified type. 331 | ## Returns ``nil`` if the conversion cannot be performed 332 | ## (the ``obj`` is not of the type ``T``) 333 | ## 334 | ## This can be used either in dot notation (``node.as(Button)``) or 335 | ## infix notation (``node as Button``). 336 | if obj.isNil: return nil 337 | if system.`of`(obj, T): 338 | result = T(obj) 339 | elif not obj.linkedObject.isNil and system.`of`(obj.linkedObject, T): 340 | result = T(obj.linkedObject) 341 | else: 342 | result = nil 343 | 344 | proc `of`*[T1, T2: NimGodotObject](obj: T1, t: typedesc[T2]): bool {.inline.} = 345 | ## Godot-specific inheritance check. 346 | not obj.isNil and (system.`of`(obj, T2) or system.`of`(obj.linkedObject, T2)) 347 | 348 | proc newRStrLit(s: string): NimNode {.compileTime.} = 349 | result = newNimNode(nnkRStrLit) 350 | result.strVal = s 351 | 352 | macro toGodotName(T: typedesc): untyped = 353 | if T is GodotString or T is string: 354 | newStrLitNode"String" 355 | elif T is SomeFloat: 356 | newStrLitNode"float" 357 | elif T is SomeUnsignedInt or T is SomeSignedInt: 358 | newStrLitNode"int" 359 | else: 360 | let nameStr = ((T.getType()[1][1].strVal).split(':')[0]) 361 | case nameStr: 362 | of "File", "Directory", "Thread", "Mutex", "Semaphore": 363 | newStrLitNode("_" & nameStr) 364 | else: 365 | newStrLitNode(nameStr) 366 | 367 | macro asCString(s: static[string]): cstring = 368 | result = newNimNode(nnkCallStrLit).add( 369 | ident("cstring"), newRStrLit(s)) 370 | 371 | proc getSingleton*[T: NimGodotObject](): T = 372 | ## Returns singleton of type ``T``. Normally, this should not be used, 373 | ## because `godotapigen `_ wraps singleton methods so that 374 | ## singleton objects don't have to be provided as parameters. 375 | const godotName = asCString(toGodotName(T)) 376 | let singleton = getGodotSingleton(godotName) 377 | if singleton.isNil: 378 | printError("Tried to get non-existing singleton of type " & $godotName) 379 | else: 380 | result = asNimGodotObject[T](singleton) 381 | 382 | var gdNativeLibraryObj: ptr GodotObject 383 | 384 | var setClassNameMethod: ptr GodotMethodBind 385 | var setLibraryMethod: ptr GodotMethodBind 386 | var newMethod: ptr GodotMethodBind 387 | type 388 | PtrCallArgType = ptr array[MAX_ARG_COUNT, pointer] 389 | proc newOwnObj[T: NimGodotObject](name: cstring): T = 390 | let newNativeScript = getClassConstructor(cstring"NativeScript")() 391 | if setClassNameMethod.isNil: 392 | setClassNameMethod = 393 | getMethod(cstring"NativeScript", cstring"set_class_name") 394 | if setLibraryMethod.isNil: 395 | setLibraryMethod = 396 | getMethod(cstring"NativeScript", cstring"set_library") 397 | if newMethod.isNil: 398 | newMethod = getMethod(cstring"NativeScript", cstring"new") 399 | var godotStrName = name.toGodotString() 400 | var argPtr: pointer = addr godotStrName 401 | setClassNameMethod.ptrCall( 402 | newNativeScript, cast[PtrCallArgType](addr argPtr), nil) 403 | deinit(godotStrName) 404 | setLibraryMethod.ptrCall( 405 | newNativeScript, cast[PtrCallArgType](addr gdNativeLibraryObj), nil) 406 | 407 | var err: VariantCallError 408 | var ret = newMethod.call(newNativeScript, nil, 0, err) 409 | if err.error != VariantCallErrorType.OK: 410 | printError("Failed to invoke 'new' on NativeScript for " & $name) 411 | elif ret.getType() != VariantType.Object: 412 | printError("Expected that NativeScript::new returns Object, " & 413 | "but it returned: " & $ret.getType()) 414 | else: 415 | result = asNimGodotObject[T](ret.asGodotObject()) 416 | if result.isRef: 417 | result.isFinalized = true 418 | result.godotObject.reference() 419 | result.isFinalized = false 420 | ret.deinit() 421 | 422 | proc gdnew*[T: NimGodotObject](): T = 423 | ## Instantiates new object of type ``T``. 424 | const godotName = toGodotName(T) 425 | const cGodotName = asCString(godotName) 426 | const objInfo = classRegistryStatic[fnv1Hash(godotName)] 427 | when objInfo.isNative: 428 | let godotObject = getClassConstructor(cGodotName)() 429 | new(result, nimGodotObjectFinalizer[T]) 430 | result.godotObject = godotObject 431 | when objInfo.isRef: 432 | godotObject.initRef() 433 | result.isRef = true 434 | else: 435 | result = newOwnObj[T](cGodotName) 436 | 437 | proc newCallError*(err: VariantCallError): ref CallError = 438 | ## Instantiates ``CallError`` from Godot ``err``. 439 | let msg = case err.error: 440 | of VariantCallErrorType.OK, 441 | VariantCallErrorType.InvalidMethod, 442 | VariantCallErrorType.TooManyArguments, 443 | VariantCallErrorType.TooFewArguments, 444 | VariantCallErrorType.InstanceIsNull: 445 | $err.error 446 | of VariantCallErrorType.InvalidArgument: 447 | "invalid argument at position " & $err.argument & ": expected " & 448 | $err.expected 449 | 450 | result = newException(CallError, msg) 451 | result.err = err 452 | 453 | proc newConversionError*(err: ConversionResult): ref ValueError = 454 | ## Instantiates error raised by `godotapigen `_ 455 | ## generated code in case of a conversion error. 456 | let msg = case err: 457 | of ConversionResult.TypeError: 458 | "Failed to convert the return value into Nim type" 459 | of ConversionResult.RangeError: 460 | "The returned value was out of bounds" 461 | of ConversionResult.OK: 462 | "OK" 463 | 464 | result = newException(ValueError, msg) 465 | 466 | proc setGodotObject*(nimObj: NimGodotObject, obj: ptr GodotObject) {.inline.} = 467 | ## Used from Godot constructor produced by ``gdobj`` macro. Do not call. 468 | assert(not obj.isNil) 469 | assert(nimObj.godotObject.isNil) # reassignment is not allowed 470 | nimObj.godotObject = obj 471 | 472 | proc setNativeObject*(nimObj: NimGodotObject, 473 | nativeObj: NimGodotObject) {.inline.} = 474 | ## Used from Godot constructor produced by ``gdobj`` macro. Do not call. 475 | GC_ref(nativeObj) 476 | nimObj.linkedObjectPtr = cast[pointer](nativeObj) 477 | nativeObj.linkedObjectPtr = cast[pointer](nimObj) 478 | nativeObj.isNative = true 479 | 480 | proc removeGodotObject*(nimObj: NimGodotObject) {.inline.} = 481 | ## Used from Godot destructor produced by ``gdobj`` macro. Do not call. 482 | GC_unref(nimObj.linkedObject) 483 | nimObj.godotObject = nil 484 | nimObj.linkedObject.godotObject = nil 485 | nimObj.linkedObjectPtr = nil 486 | 487 | proc `==`*(self, other: NimGodotObject): bool {.inline.} = 488 | ## Compares objects by referential equality. 489 | if self.isNil and other.isNil: return true 490 | if self.isNil != other.isNil: return false 491 | result = (self.godotObject == other.godotObject) 492 | 493 | proc godotObject*(nimObj: NimGodotObject): ptr GodotObject {.inline.} = 494 | ## Returns raw poitner to ``GodotObject``. Use only if you know what 495 | ## you are doing. 496 | nimObj.godotObject 497 | 498 | proc godotTypeInfo*(T: typedesc[NimGodotObject]): GodotTypeInfo {.inline.} = 499 | GodotTypeInfo( 500 | variantType: VariantType.Object, 501 | hint: when isResource(T): GodotPropertyHint.ResourceType 502 | else: GodotPropertyHint.None, 503 | hintStr: toGodotName(T) 504 | ) 505 | 506 | proc toVariant*(self: NimGodotObject): Variant {.inline.} = 507 | if self.isNil: 508 | newVariant() 509 | else: 510 | newVariant(self.godotObject) 511 | 512 | proc fromVariant*[T: NimGodotObject](self: var T, 513 | val: Variant): ConversionResult = 514 | if val.getType() == VariantType.Object: 515 | let objPtr = val.asGodotObject() 516 | self = asNimGodotObject[T](objPtr) 517 | if self.isNil: 518 | result = ConversionResult.TypeError 519 | elif val.getType() == VariantType.Nil: 520 | self = nil 521 | else: 522 | result = ConversionResult.TypeError 523 | 524 | proc toVariant*(self: Variant): Variant {.inline.} = 525 | if self.isNil: 526 | newVariant() 527 | else: 528 | newVariant(self) 529 | 530 | proc fromVariant*(self: var Variant, 531 | val: Variant): ConversionResult {.inline.} = 532 | self = newVariant(val) 533 | 534 | proc godotTypeInfo*(T: typedesc[SomeGodotOrNum]): GodotTypeInfo {.inline.} = 535 | result.variantType = 536 | when T is SomeSignedInt or T is SomeUnsignedInt: 537 | VariantType.Int 538 | elif T is bool: 539 | VariantType.Bool 540 | elif T is SomeFloat: 541 | VariantType.Real 542 | elif T is string or T is GodotString: 543 | VariantType.String 544 | elif T is Vector2: 545 | VariantType.Vector2 546 | elif T is Rect2: 547 | VariantType.Rect2 548 | elif T is Vector3: 549 | VariantType.Vector3 550 | elif T is Transform2D: 551 | VariantType.Transform2D 552 | elif T is Plane: 553 | VariantType.Plane 554 | elif T is Quat: 555 | VariantType.Quat 556 | elif T is AABB: 557 | VariantType.AABB 558 | elif T is Basis: 559 | VariantType.Basis 560 | elif T is Transform: 561 | VariantType.Transform 562 | elif T is Color: 563 | VariantType.Color 564 | elif T is RID: 565 | VariantType.RID 566 | elif T is ptr GodotObject: 567 | VariantType.Object 568 | elif T is NodePath: 569 | VariantType.NodePath 570 | elif T is Dictionary: 571 | VariantType.Dictionary 572 | elif T is Array: 573 | VariantType.Array 574 | elif T is PoolByteArray: 575 | VariantType.PoolByteArray 576 | elif T is PoolIntArray: 577 | VariantType.PoolIntArray 578 | elif T is PoolRealArray: 579 | VariantType.PoolRealArray 580 | elif T is PoolStringArray: 581 | VariantType.PoolStringArray 582 | elif T is PoolVector2Array: 583 | VariantType.PoolVector2Array 584 | elif T is PoolVector3Array: 585 | VariantType.PoolVector3Array 586 | elif T is PoolColorArray: 587 | VariantType.PoolColorArray 588 | else: 589 | VariantType.Nil 590 | 591 | proc godotTypeInfo*(T: typedesc[range]): VariantType {.inline.} = 592 | GodotTypeInfo( 593 | variantType: VariantType.Int, 594 | hint: GodotPropertyHint.Range, 595 | hintStr: $low(T) & "," & $high(T) & ",1" 596 | ) 597 | 598 | proc toVariant*[T: SomeGodotOrNum](val: T): Variant {.inline.} = 599 | when val is ref: 600 | if val.isNil: 601 | newVariant() 602 | else: 603 | newVariant(val) 604 | else: 605 | newVariant(val) 606 | 607 | proc fromVariant*[T: SomeSignedInt or SomeUnsignedInt]( 608 | self: var T, val: Variant): ConversionResult = 609 | if val.getType() == VariantType.Nil: 610 | self = 0 611 | elif val.getType() == VariantType.Int or val.getType() == VariantType.Real: 612 | # Real is allowed, because that's what the editor sets for Int values 613 | var intVal: (when T is SomeSignedInt: int64 614 | else: uint64) 615 | intVal = when T is SomeSignedInt: val.asInt() 616 | else: val.asUint() 617 | const highT = when T is SomeSignedInt: high(T).int64 618 | elif T is uint64: 0xFFFFFFFFFFFFFFFF'u64 619 | else: high(T).uint64 620 | const lowT = when T is SomeSignedInt: low(T).int64 621 | elif T is uint64: 0'u64 622 | else: low(T).uint64 623 | if intVal > highT or intVal < lowT: 624 | result = ConversionResult.RangeError 625 | else: 626 | self = T(intVal) 627 | else: 628 | result = ConversionResult.TypeError 629 | 630 | proc godotTypeInfo*(T: typedesc[enum]): GodotTypeInfo = 631 | result = GodotTypeInfo( 632 | variantType: VariantType.Int, 633 | hint: GodotPropertyHint.Enum, 634 | hintStr: "" 635 | ) 636 | for val in T: 637 | if result.hintStr.len > 0: 638 | result.hintStr.add(',') 639 | result.hintStr.add($val) 640 | 641 | proc toVariant*[T: enum](self: T): Variant {.inline.} = 642 | newVariant(int64(ord(self))) 643 | 644 | proc fromVariant*[T: enum](self: var T, 645 | val: Variant): ConversionResult {.inline.} = 646 | var intConv: int64 647 | result = fromVariant(intConv, val) 648 | if result == ConversionResult.OK: 649 | self = T(intConv) 650 | 651 | proc fromVariant*[T: SomeFloat](self: var T, val: Variant): ConversionResult = 652 | if val.getType() == VariantType.Nil: 653 | self = 0 654 | elif val.getType() == VariantType.Real or val.getType() == VariantType.Int: 655 | self = T(val.asReal()) 656 | else: 657 | result = ConversionResult.TypeError 658 | 659 | proc fromVariant*[T: SomeGodot](self: var T, val: Variant): ConversionResult = 660 | if val.getType() == VariantType.Nil: 661 | return 662 | const typeInfo = godotTypeInfo(T) 663 | if typeInfo.variantType != val.getType(): 664 | return ConversionResult.TypeError 665 | when self is bool: 666 | self = val.asBool() 667 | elif self is Vector2: 668 | self = val.asVector2() 669 | elif self is Rect2: 670 | self = val.asRect2() 671 | elif self is Vector3: 672 | self = val.asVector3() 673 | elif self is Transform2D: 674 | self = val.asTransform2D() 675 | elif self is Plane: 676 | self = val.asPlane() 677 | elif self is Quat: 678 | self = val.asQuat() 679 | elif self is AABB: 680 | self = val.asAABB() 681 | elif self is Basis: 682 | self = val.asBasis() 683 | elif self is Transform: 684 | self = val.asTransform() 685 | elif self is Color: 686 | self = val.asColor() 687 | elif self is NodePath: 688 | self = val.asNodePath() 689 | elif self is RID: 690 | self = val.asRID() 691 | elif self is ptr GodotObject: 692 | self = val.asObject() 693 | elif self is Dictionary: 694 | self = val.asDictionary() 695 | elif self is Array: 696 | self = val.asArray() 697 | elif self is PoolByteArray: 698 | self = val.asPoolByteArray() 699 | elif self is PoolIntArray: 700 | self = val.asPoolIntArray() 701 | elif self is PoolRealArray: 702 | self = val.asPoolRealArray() 703 | elif self is PoolStringArray: 704 | self = val.asPoolStringArray() 705 | elif self is PoolVector2Array: 706 | self = val.asPoolVector2Array() 707 | elif self is PoolVector3Array: 708 | self = val.asPoolVector3Array() 709 | elif self is PoolColorArray: 710 | self = val.asPoolColorArray() 711 | elif self is GodotString: 712 | self = val.asGodotString() 713 | else: 714 | # mustn't reach this 715 | result = ConversionError.TypeError 716 | 717 | proc godotTypeInfo*(T: typedesc[string]): GodotTypeInfo {.inline.} = 718 | result.variantType = VariantType.String 719 | 720 | proc toVariant*(s: string): Variant {.inline.} = 721 | newVariant(s) 722 | 723 | proc fromVariant*(s: var string, val: Variant): ConversionResult = 724 | if val.getType() == VariantType.String: 725 | s = val.asString() 726 | elif val.getType() == VariantType.Nil: 727 | when (NimMajor, NimMinor, NimPatch) < (0, 19, 0): 728 | s = nil 729 | else: 730 | s = "" 731 | else: 732 | result = ConversionResult.TypeError 733 | 734 | template arrTypeInfo(T) = 735 | result.variantType = VariantType.Array 736 | mixin godotTypeInfo 737 | type ItemT = type(( 738 | block: 739 | var s: T; 740 | when T is seq: s[0] else: s[low(s)])) 741 | when compiles(godotTypeInfo(ItemT)): 742 | let itemTypeInfo = godotTypeInfo(ItemT) 743 | result.hintStr = $ord(itemTypeInfo.variantType) 744 | result.hintStr.add('/') 745 | result.hintStr.add($ord(itemTypeInfo.hint)) 746 | result.hintStr.add(':') 747 | if not itemTypeInfo.hintStr.isNil: 748 | result.hintStr.add(itemTypeInfo.hintStr) 749 | 750 | proc godotTypeInfo*(T: typedesc[seq]): GodotTypeInfo = 751 | arrTypeInfo(T) 752 | 753 | proc godotTypeInfo*(T: typedesc[array]): GodotTypeInfo = 754 | arrTypeInfo(T) 755 | 756 | template arrayToVariant(s: untyped): Variant = 757 | var arr = newArray() 758 | mixin toVariant 759 | for item in s: 760 | arr.add(toVariant(item)) 761 | newVariant(arr) 762 | 763 | proc toVariant*[T](s: seq[T]): Variant = 764 | when (NimMajor, NimMinor, NimPatch) < (0, 20, 0): 765 | if s.isNil: 766 | return newVariant() 767 | result = arrayToVariant(s) 768 | 769 | proc toVariant*[I, T](s: array[I, T]): Variant = 770 | result = arrayToVariant(s) 771 | 772 | proc fromVariant*[T](s: var seq[T], val: Variant): ConversionResult = 773 | if val.getType() == VariantType.Nil: 774 | when (NimMajor, NimMinor, NimPatch) < (0, 20, 0): 775 | s = nil 776 | else: 777 | result = ConversionResult.TypeError 778 | elif val.getType() == VariantType.Array: 779 | let arr = val.asArray() 780 | var newS = newSeq[T](arr.len) 781 | for idx, item in arr: 782 | mixin fromVariant 783 | let convResult = fromVariant(newS[idx], item) 784 | if convResult != ConversionResult.OK: 785 | return convResult 786 | shallowCopy(s, newS) 787 | else: 788 | result = ConversionResult.TypeError 789 | 790 | proc fromVariant*[T: array](s: var T, val: Variant): ConversionResult = 791 | if val.getType() == VariantType.Nil: 792 | discard 793 | elif val.getType() == VariantType.Array: 794 | let arr = val.asArray() 795 | if s.len != arr.len: 796 | return ConversionResult.TypeError 797 | var nimIdx = low(s) # may not start from 0 and may even be an enum 798 | for item in arr: 799 | mixin fromVariant 800 | let convResult = fromVariant(s[nimIdx], item) 801 | if convResult != ConversionResult.OK: 802 | return convResult 803 | if nimIdx != high(s): 804 | inc nimIdx 805 | else: 806 | result = ConversionResult.TypeError 807 | 808 | proc godotTypeInfo*[T](OptT: typedesc[Option[T]]): GodotTypeInfo = 809 | when compiles(godotTypeInfo(T)): 810 | result.variantType = godotTypeInfo(T) 811 | else: 812 | result.variantType = VariantType.Nil 813 | 814 | proc toVariant*[T](option: Option[T]): Variant = 815 | if option.isSome(): 816 | result = toVariant(option.unsafeGet()) 817 | else: 818 | result = newVariant() 819 | 820 | proc fromVariant*[T](option: var Option[T], val: Variant): ConversionResult = 821 | if val.getType() == VariantType.Nil: 822 | option = none(T) 823 | else: 824 | var v: T 825 | result = fromVariant(v, val) 826 | if result == ConversionResult.OK: 827 | option = some(v) 828 | 829 | proc godotTypeInfo*(T: typedesc[Table|TableRef|OrderedTable|OrderedTableRef]): GodotTypeInfo {.inline.} = 830 | result.variantType = VariantType.Dictionary 831 | 832 | proc toVariant*[T: Table or TableRef or OrderedTable or OrderedTableRef](t: T): Variant = 833 | when t is ref: 834 | if t.isNil: 835 | return newVariant() 836 | var dict = newDictionary() 837 | mixin toVariant 838 | for k, v in t.pairs(): 839 | dict[toVariant(k)] = toVariant(v) 840 | result = newVariant(dict) 841 | 842 | proc fromVariant*[T: Table or TableRef or OrderedTable or OrderedTableRef](t: var T, 843 | val: Variant): ConversionResult = 844 | if val.getType() == VariantType.Nil: 845 | when t is ref: 846 | t = nil 847 | elif val.getType() == VariantType.Dictionary: 848 | let dict = val.asDictionary() 849 | mixin fromVariant 850 | when t is Table: 851 | t = initTable[type(t.keys()), type(t.values())]() 852 | elif t is TableRef: 853 | t = newTable[type(t.keys()), type(t.values())]() 854 | elif t is OrderedTable: 855 | t = initOrderedTable[type(t.keys()), type(t.values())]() 856 | else: 857 | t = newOrderedTable[type(t.keys()), type(t.values())]() 858 | for k, v in dict: 859 | var nimKey: type(t.keys()) 860 | var nimVal: type(t.values()) 861 | let keyResult = fromVariant(nimKey, k) 862 | if keyResult != ConversionResult.OK: 863 | when t is ref: 864 | t = nil 865 | return keyResult 866 | let valResult = fromVariant(nimVal, v) 867 | if valResult != ConversionResult.OK: 868 | when t is ref: 869 | t = nil 870 | return valResult 871 | t[nimKey] = nimVal 872 | else: 873 | result = ConversionResult.TypeError 874 | 875 | when (NimMajor, NimMinor, NimPatch) < (0, 19, 0): 876 | {.emit: """/*TYPESECTION*/ 877 | N_LIB_EXPORT N_CDECL(void, NimMain)(void); 878 | N_NOINLINE(void, setStackBottom)(void* thestackbottom); 879 | """.} 880 | 881 | var nativeLibHandle: pointer 882 | proc getNativeLibHandle*(): pointer = 883 | ## Returns NativeScript library handle used to register type information 884 | ## in Godot. 885 | return nativeLibHandle 886 | 887 | proc godot_nativescript_init(handle: pointer) {. 888 | cdecl, exportc, dynlib.} = 889 | nativeLibHandle = handle 890 | 891 | var stackBottom {.volatile.}: pointer 892 | stackBottom = addr(stackBottom) 893 | {.emit: """ 894 | NimMain(); 895 | """.} 896 | when (NimMajor, NimMinor, NimPatch) < (0, 19, 0): 897 | {.emit: """ 898 | setStackBottom((void*)(&`stackBottom`)); 899 | """.} 900 | else: 901 | nimGC_setStackBottom(stackBottom) 902 | GC_fullCollect() 903 | GC_disable() 904 | 905 | proc godot_gdnative_init(options: ptr GDNativeInitOptions) {. 906 | cdecl, exportc, dynlib.} = 907 | gdNativeLibraryObj = options.gdNativeLibrary 908 | setGDNativeAPI(options.gdNativeAPIStruct, options) 909 | 910 | proc godot_gdnative_terminate(options: ptr GDNativeTerminateOptions) {. 911 | cdecl, exportc, dynlib.} = 912 | if not options[].inEditor or not compileOption("threads"): 913 | deallocHeap(runFinalizers = not options[].inEditor, allowGcAfterwards = false) 914 | 915 | const nimGcStepLengthUs {.intdefine.} = 2000 916 | 917 | var idleCallbacks {.threadvar.}: seq[proc () {.closure.}] 918 | idleCallbacks = newSeq[proc () {.closure.}]() 919 | 920 | var isMainThread {.threadvar.}: bool 921 | isMainThread = true 922 | 923 | proc registerFrameCallback*(cb: proc () {.closure.}) = 924 | # Registers a callback to be called on the main thread at the end 925 | # of each frame. 926 | if not isMainThread: 927 | const err = cstring"registerFrameIdleCallback is called from non-main thread. Ignoring." 928 | godotPrintError(err, cstring"registerFrameCallback", 929 | cstring"godotnim.nim", 0) 930 | else: 931 | idleCallbacks.add(cb) 932 | 933 | {.push stackTrace: off.} 934 | 935 | proc godot_nativescript_frame() {.cdecl, exportc, dynlib.} = 936 | var stackBottom {.volatile.}: pointer 937 | stackBottom = addr(stackBottom) 938 | when (NimMajor, NimMinor, NimPatch) < (0, 19, 0): 939 | {.emit: """ 940 | setStackBottom((void*)(&`stackBottom`)); 941 | """.} 942 | else: 943 | nimGC_setStackBottom(stackBottom) 944 | for cb in idleCallbacks: 945 | cb() 946 | GC_step(nimGcStepLengthUs, true, 0) 947 | 948 | when not defined(release): 949 | onUnhandledException = proc(errorMsg: string) = 950 | printError("Unhandled Nim exception: " & errorMsg) 951 | 952 | proc godot_nativescript_thread_enter() {.cdecl, exportc, dynlib.} = 953 | when compileOption("threads"): 954 | setupForeignThreadGc() 955 | else: 956 | 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." 957 | var s = err.toGodotString() 958 | godotPrint(s) 959 | s.deinit() 960 | 961 | proc godot_nativescript_thread_exit() {.cdecl, exportc, dynlib.} = 962 | when compileOption("threads"): 963 | teardownForeignThreadGc() 964 | 965 | {.pop.} # stackTrace: off 966 | --------------------------------------------------------------------------------