Compare commits
166 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4175dbb3e5 | ||
| 7eadb07820 | |||
|
|
00d8ac2691 | ||
|
|
388bea9205 | ||
|
|
f25c3c7a5d | ||
|
|
d3e5f91b40 | ||
|
|
3f46e3c648 | ||
|
|
87707a86b4 | ||
|
|
031774f54f | ||
|
|
ed9ede5cb3 | ||
|
|
a49fcbdac7 | ||
|
|
157a90e4a0 |
||
|
|
d1b82d351c | ||
|
|
78d3626fa3 | ||
|
|
1b8e7ccd98 | ||
|
|
c2db807da4 | ||
|
|
7dd1b1ed5f | ||
|
|
2f3f4034cf | ||
|
|
19b0c23d62 | ||
|
|
0fecfdb3b8 | ||
|
|
34fda99def | ||
|
|
3a935b9308 | ||
|
|
f45281f5a0 | ||
|
|
db4bb91765 | ||
|
|
e9d73d8ec4 | ||
|
|
859f9f04fb | ||
|
|
ceaf66a34c | ||
|
|
fd5f77e7c2 | ||
|
|
8d68051f23 | ||
|
|
13f5aba3fe | ||
|
|
b3ad6134d9 | ||
|
|
1e8ccfea2b | ||
|
|
9e61030817 | ||
|
|
66c939b9e6 | ||
|
|
76de026b4f | ||
|
|
4eb771e9be | ||
|
|
2dd0130c78 | ||
|
|
651c2d823c | ||
|
|
8b1ac6d835 | ||
|
|
21ca9a088b | ||
|
|
96dfc7de90 | ||
|
|
a1d1481967 | ||
|
|
6e014bbc01 | ||
|
|
dc6ebaf575 | ||
|
|
be6f01e3b7 | ||
|
|
d11856377e | ||
|
|
0aab6e17ef | ||
|
|
5ccf351b5a | ||
|
|
f05eb090f7 | ||
|
|
e3216f09d0 | ||
|
|
ae3171cb98 | ||
|
|
d4ab8a5524 | ||
|
|
09326f5104 | ||
|
|
d89073bac8 | ||
|
|
e2feb06468 | ||
|
|
4d19140d7c | ||
|
|
72dd992e66 | ||
|
|
50835baca8 | ||
|
|
c06792df8d | ||
|
|
8d6972f729 | ||
|
|
0d21c361d0 | ||
|
|
3e1e8f1073 | ||
|
|
e2049ff1a7 | ||
|
|
4e24244c48 | ||
|
|
a1c378301a | ||
|
|
bf5bd54356 | ||
|
|
cc6bfa0045 | ||
|
|
a93dcd1d4d | ||
|
|
e494dc914a | ||
|
|
26570707aa | ||
|
|
d2b86a2b94 | ||
|
|
1b47dac4e9 | ||
|
|
7f73a89878 | ||
|
|
c5d7680e53 | ||
|
|
f5abff05e6 | ||
|
|
54d962afd4 | ||
|
|
b62db02d8f | ||
|
|
cf75723fa1 | ||
|
|
178192651f | ||
|
|
77a8cf7815 | ||
|
|
99934854d0 | ||
|
|
ee53768c13 | ||
|
|
b5fd4295e6 | ||
|
|
e3c014a359 | ||
|
|
2db2e413a9 | ||
|
|
7e23048048 | ||
|
|
2c226b90e2 | ||
|
|
fda800fd26 | ||
|
|
3349fe2321 | ||
|
|
7a96e33f74 | ||
|
|
f54de5cd46 | ||
|
|
3d9839ceed | ||
|
|
8d49c0b910 | ||
|
|
c5f6d47f3e | ||
|
|
6da07cada0 | ||
|
|
72e6e774a7 | ||
|
|
d43b10bc76 | ||
|
|
53f0f230da | ||
|
|
e8ea5fbe27 | ||
|
|
34753b7a27 | ||
|
|
fcc10071fb | ||
|
|
a7d9aaef95 | ||
|
|
4b6c76e776 | ||
|
|
daa56270e5 | ||
|
|
4cc9711d2f | ||
|
|
8ef554501f | ||
|
|
327cd0e18f | ||
|
|
643c445f87 | ||
|
|
6549d90c3b | ||
|
|
6aaeed4dca | ||
|
|
72b706d7fe | ||
|
|
f91a0d0364 | ||
|
|
fd40716b58 | ||
|
|
64a8aefeb8 | ||
|
|
3b89eeb9a7 | ||
|
|
c1c1852203 | ||
|
|
afa48455f6 | ||
|
|
fedd04229a | ||
|
|
0062568dbc | ||
|
|
e587fdf382 | ||
|
|
c34a2174fa | ||
|
|
4d14f624b4 | ||
|
|
988b9e1f11 | ||
|
|
ec707ea776 | ||
|
|
294c057ff9 | ||
|
|
0af5eb3b7f | ||
|
|
7131cd0748 | ||
|
|
a91fe1f713 | ||
|
|
692fbe892b | ||
|
|
0fd0101432 | ||
|
|
31bd5ff4c6 | ||
|
|
be02bdfd9c | ||
|
|
728e3012c6 | ||
|
|
fb8c42a2cc | ||
|
|
3b8b12833a | ||
|
|
7185682025 | ||
|
|
25a21072be | ||
|
|
360be5759e | ||
|
|
f30df6d81b | ||
|
|
0fe948c4a1 | ||
|
|
04c97656d8 | ||
|
|
5884cb766a | ||
|
|
712be9ca5a | ||
|
|
05c858ee44 | ||
|
|
7d91c2b5cb | ||
|
|
bc7d12d780 | ||
|
|
f5769045fc | ||
|
|
2fd1efcc4e | ||
|
|
69cb828750 | ||
|
|
4a5e0fe95f | ||
|
|
3e2d0708e2 | ||
|
|
0c5e2e463c | ||
|
|
94f6f7c8a7 | ||
|
|
de89df71ad | ||
|
|
863df0ae45 | ||
|
|
b023775f79 | ||
|
|
15a527d8b4 | ||
|
|
3a6acbbe92 | ||
|
|
291e14a32a | ||
|
|
dc00986f29 | ||
|
|
e716926207 | ||
|
|
b41a37681f | ||
|
|
1e6646713f | ||
|
|
daf972d722 | ||
|
|
0ff9c8f580 | ||
|
|
1e039ff39d |
3496 changed files with 10771 additions and 4905240 deletions
13
.gitignore
vendored
13
.gitignore
vendored
|
|
@ -1 +1,14 @@
|
||||||
|
nimcache/
|
||||||
|
|
||||||
|
/godot/apigen/apigen
|
||||||
|
/godot/apigen/apigen.exe
|
||||||
|
/godot/godotapigen
|
||||||
|
/godot/godotapigen.exe
|
||||||
|
|
||||||
|
/docgen
|
||||||
|
/docs/docbuild
|
||||||
|
/docs/docbuild.exe
|
||||||
|
/docs/docpublish
|
||||||
|
/docs/docpublish.exe
|
||||||
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
53
.travis.yml
Normal file
53
.travis.yml
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
sudo: false
|
||||||
|
language: c
|
||||||
|
os:
|
||||||
|
- osx
|
||||||
|
compiler: clang
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- secure: o+IZkRS6J7bGYkiilm10KDeCTDIVHszZ9dPvb93cdUKX/9hFVRiUjDOvNXqBdyOv43JIAsRTppym4B2pfcp9cwLoVBJNW70GKhp6ChLZm3wFdabScWKemuG2YtAUyGiSmxbVmUZ4baltnADyGFHuYWgHLjx6AKO26SqrXRLJ0I1IzGNKKNIfoyZzm7qdFDGJRnSC7L+y1pOITK7dpy60D1vat4FhOLaz2K7L8T8tZYZFK7yyxKduFUlY3cy4z3TpjxMa9/ksCiPiuPDN5xOrVIw0AtgZ2gYodZJUEnfaRzFkgcZ4OJuTAMNMalu52mVAVAoDt4yc7BnbtfsYJzfIjTeLjjWKWz8mqqp/HpxcfVnmPKxV5zeN8UhbosT8vNjwretWbQcFndzt0ohK7E8uMsnDGER7sGPEhCZCttkId96gi7Ro1awPIKCqLaMqB43Bwo48nnW0oQgrfWe1ZKtREXWI4F1F2GMbU8Jsvv0N5GnPGd4RDieBH5KIkJXcttAwRk8AUQ4U5PVkQ/OK9xm9BH2tB0vrjZ4FZWnFPapKVcPUYw9deyyXOXwSMmDpuwkJIjqi3tRyBWJG9+tUlAJw8zyFkCPeN9kzyVH/PhbacwBMdSxew24VLAWWCUhQHCP+fcjpKio8uDUFQN3javIRV4N3mHJ9v0VAF7Ixzh8AviQ=
|
||||||
|
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- ubuntu-toolchain-r-test
|
||||||
|
- llvm-toolchain-trusty-3.9
|
||||||
|
packages:
|
||||||
|
- build-essential
|
||||||
|
- scons
|
||||||
|
- pkg-config
|
||||||
|
- libx11-dev
|
||||||
|
- libxcursor-dev
|
||||||
|
- libasound2-dev
|
||||||
|
- libfreetype6-dev
|
||||||
|
- libgl1-mesa-dev
|
||||||
|
- libglu1-mesa-dev
|
||||||
|
- libssl-dev
|
||||||
|
- libxinerama-dev
|
||||||
|
- libxrandr-dev
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then rvm --default use 2.3; brew update; brew install scons ; fi
|
||||||
|
|
||||||
|
install:
|
||||||
|
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export GODOT_PLATFORM=osx; else export GODOT_PLATFORM=x11; fi
|
||||||
|
- git clone --depth=1 https://github.com/nim-lang/Nim.git
|
||||||
|
- cd Nim
|
||||||
|
- git checkout devel
|
||||||
|
- sh ci/build.sh
|
||||||
|
- export PATH=$PATH:"`pwd`/bin"
|
||||||
|
- ./koch tools -d:release
|
||||||
|
- nimble install -y
|
||||||
|
- cd ..
|
||||||
|
- git clone --depth=1 https://github.com/godotengine/godot.git godotengine
|
||||||
|
- cd godotengine
|
||||||
|
- scons -j 3 platform=$GODOT_PLATFORM
|
||||||
|
- export GODOT_BIN="`pwd`/bin/godot.$GODOT_PLATFORM.tools.64"
|
||||||
|
- cd ..
|
||||||
|
|
||||||
|
script:
|
||||||
|
- set -e
|
||||||
|
- mkdir godotapi
|
||||||
|
- nim c -d:release -r godot/godotapigen.nim "$GODOT_BIN" godotapi
|
||||||
|
- nim c -d:useRealtimeGc --path:godot -c godotapi/godotall.nim
|
||||||
|
- nim c -d:release -r docs/docpublish.nim
|
||||||
16
.vscode/settings.json
vendored
Normal file
16
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"editor.tabSize": 2,
|
||||||
|
"editor.rulers": [80],
|
||||||
|
"editor.insertSpaces": true,
|
||||||
|
"editor.detectIndentation": false,
|
||||||
|
"files.eol": "\n",
|
||||||
|
"files.trimTrailingWhitespace": true,
|
||||||
|
"nim.project": ["godot/godot.nim",
|
||||||
|
"godot/godotapigen.nim"],
|
||||||
|
"nim.buildOnSave": false,
|
||||||
|
"nim.lintOnSave": true,
|
||||||
|
"nim.licenseString": "# Copyright 2018 Xored Software, Inc.\n\n",
|
||||||
|
"files.exclude": {
|
||||||
|
"**/nimcache/**": true
|
||||||
|
}
|
||||||
|
}
|
||||||
20
LICENSE
Normal file
20
LICENSE
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
godot-nim - Nim bindings for Godot Engine
|
||||||
|
|
||||||
|
The MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2018 Xored Software Inc.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||||
|
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||||
|
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial
|
||||||
|
portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||||
|
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||||
|
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
16
README.md
Normal file
16
README.md
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
# Nim bindings for Godot Engine
|
||||||
|
|
||||||
|
Nim bindings for Godot 3 based on [GDNative](https://godotengine.org/article/dlscript-here).
|
||||||
|
|
||||||
|
Documentation: https://pragmagic.github.io/godot-nim/
|
||||||
|
|
||||||
|
## Links
|
||||||
|
|
||||||
|
- [Godot Engine](http://www.godotengine.org/)
|
||||||
|
- [Nim](http://nim-lang.org/)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is licensed under the MIT license. Read [LICENSE](LICENSE) file for details.
|
||||||
|
|
||||||
|
Copyright (c) 2018 Xored Software, Inc.
|
||||||
161
docs/docbuild.nim
Normal file
161
docs/docbuild.nim
Normal file
|
|
@ -0,0 +1,161 @@
|
||||||
|
# Copyright 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
import threadpool, os, osproc, strutils, sequtils, pegs
|
||||||
|
|
||||||
|
import "../godot/godotapigen.nim"
|
||||||
|
|
||||||
|
const dirs = ["godot"/"core", "godot"/"internal", "godot"/"nim"]
|
||||||
|
const files = ["godot"/"godotapigen.nim", "godot"/"godotinternal.nim",
|
||||||
|
"godot"/"godot.nim"]
|
||||||
|
const indexFile = "docs"/"index.rst"
|
||||||
|
const gitHubUrl = "https://github.com/pragmagic/godot-nim"
|
||||||
|
|
||||||
|
proc outName(outDir, file: string): string =
|
||||||
|
outDir / file.extractFilename().changeFileExt("html")
|
||||||
|
|
||||||
|
template quoted(s: string): string =
|
||||||
|
('"' & s & '"')
|
||||||
|
|
||||||
|
proc execOrFail(cmd: string) =
|
||||||
|
echo "[exec] " & cmd
|
||||||
|
let ret = execShellCmd(cmd)
|
||||||
|
if ret != 0:
|
||||||
|
raise newException(
|
||||||
|
Exception, "Command quit with exit code " & $ret & ": " & cmd)
|
||||||
|
|
||||||
|
template withDir(dir: string, body: typed) =
|
||||||
|
let curDir = getCurrentDir()
|
||||||
|
setCurrentDir(dir)
|
||||||
|
try:
|
||||||
|
body
|
||||||
|
finally:
|
||||||
|
setCurrentDir(curDir)
|
||||||
|
|
||||||
|
iterator walkDirRec(dir: string, filter: set[PathComponent],
|
||||||
|
extensions: openarray[string]): string =
|
||||||
|
for file in walkDirRec(dir, filter):
|
||||||
|
if not extensions.anyIt(file.endsWith(it)): continue
|
||||||
|
yield file
|
||||||
|
|
||||||
|
proc genApiFiles(targetDir, godotBin: string) =
|
||||||
|
let jsonFile = targetDir / "api.json"
|
||||||
|
try:
|
||||||
|
execOrFail(quoted(godotBin) &
|
||||||
|
" --gdnative-generate-json-api " & quoted(jsonFile))
|
||||||
|
except:
|
||||||
|
# this fails unstably even if api.json is created successfully
|
||||||
|
discard
|
||||||
|
if not fileExists(jsonFile):
|
||||||
|
raise newException(Exception, "Failed to generate Godot API wrappers")
|
||||||
|
|
||||||
|
genApi(targetDir, jsonFile)
|
||||||
|
|
||||||
|
writeFile(targetDir / "nim.cfg", "path=\"$projectdir/../../godot\"")
|
||||||
|
|
||||||
|
proc extractVersion(nimbleFile: string): string =
|
||||||
|
let contents = readFile(nimbleFile)
|
||||||
|
var matches: array[1, string]
|
||||||
|
doAssert match(contents, peg"""'version' \s* '=' \s* '"' {@} '"' """, matches)
|
||||||
|
result = matches[0]
|
||||||
|
|
||||||
|
proc fixupHrefs(file: string) =
|
||||||
|
var contents = readFile(file)
|
||||||
|
contents = contents.replacef(
|
||||||
|
peg"""'href="' ('internal'/'core'/'nim') '/' {@} '"' """,
|
||||||
|
"href=\"$#\"")
|
||||||
|
if file.contains("godotapi"):
|
||||||
|
contents = contents.replacef(
|
||||||
|
peg"""'href="' {('godotinternal' / 'godot') '.html"'} """,
|
||||||
|
"href=\"../$#")
|
||||||
|
writeFile(file, contents)
|
||||||
|
|
||||||
|
proc getGitHash(): string =
|
||||||
|
result = execProcess("git rev-parse HEAD")
|
||||||
|
if result.len > 0:
|
||||||
|
result = result.replace("\L", "").replace("\r", "")
|
||||||
|
|
||||||
|
proc buildDocs*(outDir, godotNimDir, godotBin: string) =
|
||||||
|
removeDir(outDir)
|
||||||
|
createDir(outDir)
|
||||||
|
let outDirAbs = expandFilename(outDir)
|
||||||
|
let godotBinAbs = expandFilename(godotBin)
|
||||||
|
|
||||||
|
setCurrentDir(godotNimDir)
|
||||||
|
|
||||||
|
let godotNimVersion = extractVersion("godot.nimble")
|
||||||
|
putEnv("godotnimversion", godotNimVersion)
|
||||||
|
putEnv("godotnimgithub", gitHubUrl)
|
||||||
|
let gitCommit = getGitHash()
|
||||||
|
|
||||||
|
var allNimFiles = newSeq[string]()
|
||||||
|
allNimFiles.add(files)
|
||||||
|
for dir in dirs:
|
||||||
|
for file in walkDirRec(dir, {pcFile, pcDir}, [".nim"]):
|
||||||
|
allNimFiles.add(file)
|
||||||
|
for file in allNimFiles:
|
||||||
|
spawn execOrFail(
|
||||||
|
"nim doc -d:useRealtimeGc --path:godot -o:" &
|
||||||
|
quoted(outName(outDirAbs, file)) &
|
||||||
|
" --git.url:" & quoted(gitHubUrl) &
|
||||||
|
" --git.commit:" & quoted(gitCommit) &
|
||||||
|
' ' & quoted(file))
|
||||||
|
|
||||||
|
let godotApiFolder = outDirAbs / "godotapi"
|
||||||
|
createDir(godotApiFolder)
|
||||||
|
genApiFiles(godotApiFolder, godotBinAbs)
|
||||||
|
for file in walkDirRec(godotApiFolder, {pcFile, pcDir}, [".nim"]):
|
||||||
|
spawn execOrFail("nim doc -d:useRealtimeGc --path:godot -o:" &
|
||||||
|
quoted(outName(godotApiFolder, file)) & ' ' & quoted(file))
|
||||||
|
|
||||||
|
sync()
|
||||||
|
|
||||||
|
var gitHash: string
|
||||||
|
withDir(godotBinAbs.parentDir()):
|
||||||
|
gitHash = getGitHash()
|
||||||
|
if gitHash.len == 0:
|
||||||
|
raise newException(Exception,
|
||||||
|
"Godot executable is not under Git repository")
|
||||||
|
|
||||||
|
var indexContent = readFile(indexFile)
|
||||||
|
var apiList = newStringOfCap(4096)
|
||||||
|
for file in walkDirRec(godotApiFolder, {pcFile, pcDir}):
|
||||||
|
if not file.endsWith(".html"):
|
||||||
|
removeFile(file)
|
||||||
|
else:
|
||||||
|
let moduleHtml = file.extractFileName()
|
||||||
|
let moduleName = moduleHtml.changeFileExt("")
|
||||||
|
apiList.add("* `" & moduleName & " <godotapi/" & moduleHtml & ">`_\L")
|
||||||
|
indexContent = indexContent.replace("$GODOTAPI_CHANGESET_HASH", gitHash).
|
||||||
|
replace("$AUTO_GENERATED_GODOTAPI_LIST", apiList).
|
||||||
|
replace("$GODOTNIM_GITHUB_URL", gitHubUrl)
|
||||||
|
|
||||||
|
let tmpRst = outDirAbs/"index.rst"
|
||||||
|
writeFile(tmpRst, indexContent)
|
||||||
|
try:
|
||||||
|
execOrFail("nim rst2html -o:" & quoted(outName(outDirAbs, tmpRst)) &
|
||||||
|
' ' & quoted(tmpRst))
|
||||||
|
finally:
|
||||||
|
removeFile(tmpRst)
|
||||||
|
|
||||||
|
for file in walkDirRec(outDir, {pcFile, pcDir}, [".html"]):
|
||||||
|
spawn fixupHrefs(file)
|
||||||
|
|
||||||
|
sync()
|
||||||
|
|
||||||
|
when isMainModule:
|
||||||
|
const outDir = "docgen"
|
||||||
|
|
||||||
|
if not fileExists("godot.nimble"):
|
||||||
|
echo "Must be executed from godot-nim root dir"
|
||||||
|
quit(-1)
|
||||||
|
|
||||||
|
let godotBin = getEnv("GODOT_BIN")
|
||||||
|
if godotBin.len == 0:
|
||||||
|
echo "GODOT_BIN environment variable must point to Godot executable"
|
||||||
|
quit(-1)
|
||||||
|
|
||||||
|
try:
|
||||||
|
buildDocs(outDir, getCurrentDir(), godotBin)
|
||||||
|
except:
|
||||||
|
echo getCurrentExceptionMsg()
|
||||||
|
quit(-1)
|
||||||
97
docs/docpublish.nim
Normal file
97
docs/docpublish.nim
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
# Copyright 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
import os, pegs, strutils
|
||||||
|
import docbuild
|
||||||
|
|
||||||
|
const indexTemplate = """<html>
|
||||||
|
<head><title>godot-nim docs index</title></head>
|
||||||
|
<body>
|
||||||
|
<h1>Documentation of Nim bindings for Godot Engine (<a href="https://github.com/$REPO_SLUG">GitHub</a>)</h1><br/>
|
||||||
|
$VERSION_LIST
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"""
|
||||||
|
|
||||||
|
proc execOrQuit(cmd: string) =
|
||||||
|
let ret = execShellCmd(cmd)
|
||||||
|
if ret != 0:
|
||||||
|
quit(ret)
|
||||||
|
|
||||||
|
proc walkDirRecRelative(dir: string, cb: proc (file: string), start = "") =
|
||||||
|
for kind, path in walkDir(dir, relative = true):
|
||||||
|
if kind in {pcFile, pcLinkToFile}:
|
||||||
|
cb(if start.len > 0: start / path else: path)
|
||||||
|
elif kind in {pcDir, pcLinkToDir}:
|
||||||
|
let fullPath = if start.len > 0: start / path else: path
|
||||||
|
walkDirRecRelative(dir / fullPath, cb, fullPath)
|
||||||
|
|
||||||
|
proc publish(docDir, gitHubToken, repoSlug, branch, tag, changeset: string) =
|
||||||
|
let release = if branch == "master": branch else: tag
|
||||||
|
let commitComment = if release == "master":
|
||||||
|
"Update master documentation for changeset " & changeset
|
||||||
|
else:
|
||||||
|
"Update documentation for " & tag
|
||||||
|
|
||||||
|
const repoDir = "gh-pages"
|
||||||
|
execOrQuit(
|
||||||
|
"git clone --depth=1 --branch=gh-pages https://github.com/$#.git $#" %
|
||||||
|
[repoSlug, repoDir])
|
||||||
|
try:
|
||||||
|
removeDir(repoDir/release)
|
||||||
|
createDir(repoDir/release)
|
||||||
|
var versionList = newStringOfCap(4096)
|
||||||
|
for kind, path in walkDir(repoDir, relative = true):
|
||||||
|
if kind == pcDir and not path.startsWith("."):
|
||||||
|
versionList.add("<a href='$1/index.html'>$1</a><br/>" % path)
|
||||||
|
let index = indexTemplate.replace("$REPO_SLUG", repoSlug).
|
||||||
|
replace("$VERSION_LIST", versionList)
|
||||||
|
writeFile(repoDir/"index.html", index)
|
||||||
|
|
||||||
|
walkDirRecRelative(docDir) do (file: string):
|
||||||
|
createDir(parentDir(repoDir/release/file))
|
||||||
|
copyFile(docDir/file, repoDir/release/file)
|
||||||
|
|
||||||
|
setCurrentDir(repoDir)
|
||||||
|
try:
|
||||||
|
execOrQuit("git add --all")
|
||||||
|
execOrQuit("git commit -m \"$#\"" % commitComment)
|
||||||
|
execOrQuit("git push -fq \"https://$#@github.com/$#.git\" gh-pages" %
|
||||||
|
[gitHubToken, repoSlug])
|
||||||
|
finally:
|
||||||
|
setCurrentDir("..")
|
||||||
|
finally:
|
||||||
|
removeDir(repoDir)
|
||||||
|
|
||||||
|
when isMainModule:
|
||||||
|
proc getEnvOrQuit(key: string): string =
|
||||||
|
result = getEnv(key)
|
||||||
|
if result.len == 0:
|
||||||
|
echo "Expected environment variable: " & key
|
||||||
|
quit(1)
|
||||||
|
|
||||||
|
let pr = getEnv("TRAVIS_PULL_REQUEST")
|
||||||
|
if pr.len > 0 and pr != "false":
|
||||||
|
echo "This is a PR build. Skipping."
|
||||||
|
quit(0)
|
||||||
|
|
||||||
|
let repoSlug = getEnvOrQuit("TRAVIS_REPO_SLUG")
|
||||||
|
let branch = getEnvOrQuit("TRAVIS_BRANCH")
|
||||||
|
let changeset = getEnvOrQuit("TRAVIS_COMMIT")
|
||||||
|
let tag = getEnv("TRAVIS_TAG")
|
||||||
|
|
||||||
|
# let repoSlug = "pragmagic/godot-nim"
|
||||||
|
# let branch = "master"
|
||||||
|
# let changeset = "0fd0101432c1fed1004f50b035fcf74f75f004a8"
|
||||||
|
# let tag = ""
|
||||||
|
|
||||||
|
let gitHubToken = getEnvOrQuit("GITHUB_TOKEN")
|
||||||
|
|
||||||
|
if branch != "master" and not (tag =~ peg"^ 'v' \d+ '.' \d+ '.' \d+ $"):
|
||||||
|
echo "This is not master or tagged changeset. Skipping."
|
||||||
|
quit(0)
|
||||||
|
|
||||||
|
let godotBin = getEnvOrQuit("GODOT_BIN")
|
||||||
|
|
||||||
|
const docDir = "docgen"
|
||||||
|
buildDocs(docDir, getCurrentDir(), godotBin)
|
||||||
|
publish(docDir, gitHubToken, repoSlug, branch, tag, changeset)
|
||||||
12
docs/godotapi.rst
Normal file
12
docs/godotapi.rst
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
===============
|
||||||
|
Godot API (Nim)
|
||||||
|
===============
|
||||||
|
|
||||||
|
:Godot Git Hash: |godothash|
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
|
||||||
|
This is an auto-generated index of Godot API. It's built from Git changeset
|
||||||
|
$GODOTAPI_CHANGESET_HASH.
|
||||||
|
|
||||||
|
$AUTO_GENERATED_GODOTAPI_LIST
|
||||||
173
docs/index.rst
Normal file
173
docs/index.rst
Normal file
|
|
@ -0,0 +1,173 @@
|
||||||
|
=============================
|
||||||
|
Nim bindings for Godot Engine
|
||||||
|
=============================
|
||||||
|
|
||||||
|
:Author: Ruslan Mustakov
|
||||||
|
:Version: |godotnimversion|
|
||||||
|
:GitHub: `$GODOTNIM_GITHUB_URL <$GODOTNIM_GITHUB_URL>`_
|
||||||
|
:License: MIT
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
|
||||||
|
``godot-nim`` library allows to create games on
|
||||||
|
`Godot Engine <https://godotengine.org/>`_ with
|
||||||
|
`Nim programming language <https://nim-lang.org/>`_. Nim is a statically typed
|
||||||
|
language with an elegant Python-like syntax that compiles to native code.
|
||||||
|
It is garbage-collected, but its GC supports real-time mode which this library
|
||||||
|
makes use of. It means the GC will never run during game frames and will use
|
||||||
|
fixed amount of frame idle time to collect garbage. This leads to no stalls
|
||||||
|
and close to zero compromise on performance comparing to native languages with
|
||||||
|
manual memory management.
|
||||||
|
|
||||||
|
If you are not familiar with Nim yet, it is recommended to go through the
|
||||||
|
`official tutorial <https://nim-lang.org/docs/tut1.html>`_.
|
||||||
|
|
||||||
|
`VSCode <https://code.visualstudio.com/>`_ is the recommended editor for
|
||||||
|
working with Nim code. It is cross-platform and has the excellent
|
||||||
|
`nim plugin <https://marketplace.visualstudio.com/items?itemName=kosz78.nim>`_
|
||||||
|
that supports most of the features you would expect from an IDE.
|
||||||
|
It also has `godot-tools plugin <https://marketplace.visualstudio.com/items?itemName=geequlim.godot-tools>`_
|
||||||
|
which adds features for editing GDScript and Godot resource files.
|
||||||
|
|
||||||
|
|
||||||
|
Getting Started
|
||||||
|
===============
|
||||||
|
|
||||||
|
Getting Godot
|
||||||
|
--------------
|
||||||
|
|
||||||
|
The library requires Godot version 3.0, which you can get here:
|
||||||
|
https://godotengine.org/download
|
||||||
|
|
||||||
|
Installing Nim
|
||||||
|
-------------
|
||||||
|
|
||||||
|
The library requires Nim version 0.18.0 or newer, which you can get here:
|
||||||
|
https://nim-lang.org/install.html
|
||||||
|
|
||||||
|
Make sure you also have ``nimble`` (Nim's package manager) installed.
|
||||||
|
|
||||||
|
Creating Project
|
||||||
|
----------------
|
||||||
|
|
||||||
|
The fastest way to set up a Godot-Nim project is to use the existing stub:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
git clone --depth=1 https://github.com/pragmagic/godot-nim-stub.git myproject
|
||||||
|
|
||||||
|
(you can then delete the .git directory within to untie the project from the
|
||||||
|
stub repository)
|
||||||
|
|
||||||
|
The stub contains the necessary build configuration to compile your code for
|
||||||
|
desktop and mobile platforms, as well as a couple of very simple scenes to
|
||||||
|
help you get started. Consult the stub's `README
|
||||||
|
<https://github.com/pragmagic/godot-nim-stub>`_ for information about
|
||||||
|
compiling the project.
|
||||||
|
|
||||||
|
|
||||||
|
Adding Nim to Existing Project
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
If you would like to use Nim in an existing project:
|
||||||
|
|
||||||
|
1. Copy ``nakefile.nim`` file and ``src`` directory from the stub described
|
||||||
|
in the previous section above your Godot project folder. Adjust paths in
|
||||||
|
build scripts (``nakefile.nim``, ``src/stub.nimble``) according to your
|
||||||
|
own project structure.
|
||||||
|
|
||||||
|
2. Copy ``nimlib.gdnlib`` to your Godot project folder. It is a
|
||||||
|
GDNative library resource that contains paths to dynamic libraries
|
||||||
|
compiled by Nim.
|
||||||
|
|
||||||
|
Next Steps
|
||||||
|
----------
|
||||||
|
|
||||||
|
Once you are familiarized with the build process (it's as simple as running
|
||||||
|
``nake build`` after you are set up), it is recommended to go through
|
||||||
|
`godotmacros <godotmacros.html>`_ and `godotnim <godotnim.html>`_ module
|
||||||
|
documentations. They describe special macros and procedures needed to define
|
||||||
|
or instantiate Godot objects. After you learned that, the rest is similar to
|
||||||
|
using any Nim library. These bindings do not limit any of Nim's capabilities,
|
||||||
|
and you can use any Nim types as fields or parameters of Godot objects and
|
||||||
|
their procedures (but, obviously, you may not be able to export some of them
|
||||||
|
to Godot editor or GDScript, unless you define your own converters).
|
||||||
|
|
||||||
|
|
||||||
|
Modules
|
||||||
|
=======
|
||||||
|
|
||||||
|
The binding library consists of three major modules:
|
||||||
|
|
||||||
|
* `godot <#modules-godot-module>`_ - Contains core types and macro definitions.
|
||||||
|
You need to import this in any module that defines or makes use of Godot
|
||||||
|
types.
|
||||||
|
|
||||||
|
* `godotinternal <#modules-godotinternal-module>`_ - Contains raw wrappers over
|
||||||
|
few core types, such as ``GodotVariant``, ``GodotString``, ``GodotNodePath``,
|
||||||
|
``GodotDictionary``, pool arrays. These are used by ``godotapigen`` and macro
|
||||||
|
implementations, and you don't have to use them at all in your code, unless
|
||||||
|
you want to go into low-level details for some reason. Each of those types
|
||||||
|
needs to be destructed manually with ``deinit`` procedure.
|
||||||
|
|
||||||
|
* `godotapigen <godotapigen.html>`_ - Wrapper generator based on data from
|
||||||
|
Godot's ``ClassDB``. You only need to use it as a part of the build process.
|
||||||
|
|
||||||
|
|
||||||
|
godot Module
|
||||||
|
------------
|
||||||
|
|
||||||
|
Contains core types and macro definitions. You need to import this in any
|
||||||
|
module that defines or makes use of Godot types. The sumbodules below are
|
||||||
|
exported and you don't have to import any of them directly.
|
||||||
|
|
||||||
|
* `godotnim <godotnim.html>`_ Defines ``NimGodotObject`` and Varaint converters
|
||||||
|
for standard Nim types.
|
||||||
|
* `godotmacros <godotmacros.html>`_ Defines ``gdobj`` macro for defining
|
||||||
|
Godot objects.
|
||||||
|
* `variants <variants.html>`_ ``Variant`` type represents a "dynamic object"
|
||||||
|
that many Godot procedures make use of.
|
||||||
|
* `arrays <arrays.html>`_ Defines ``Array`` of Variants.
|
||||||
|
* `basis <basis.html>`_ Defines 3D ``Basis``.
|
||||||
|
* `colors <colors.html>`_ Defines ARGB ``Color``.
|
||||||
|
* `dictionaries <dictionaries.html>`_ Defines ``Variant`` -> ``Variant``
|
||||||
|
``Dictionary``.
|
||||||
|
* `nodepaths <nodepaths.html>`_ Defines ``NodePath`` - a path to a ``Node``.
|
||||||
|
* `planes <planes.html>`_ Defines 3D ``Plane``.
|
||||||
|
* `poolarrays <poolarrays.html>`_ Defines pooled arrays: ``PoolByteArray``,
|
||||||
|
``PoolIntArray``, ``PoolRealArray``, ``PoolVector2Array``,
|
||||||
|
``PoolVector3Array``, ``PoolColorArray``, ``PoolStringArray``.
|
||||||
|
* `quats <quats.html>`_ Defines ``Quat`` (quaternion) describing object
|
||||||
|
rotation in 3D space.
|
||||||
|
* `rect2 <rect2.html>`_ Defines ``Rect2`` - a 2D rectangle.
|
||||||
|
* `aabb <aabb.html>`_ Defines ``AABB`` - a 3D box.
|
||||||
|
* `rids <rids.html>`_ Defines ``RID`` - a resource identifier.
|
||||||
|
* `transform2d <transform2d.html>`_ Defines ``Transform2D``.
|
||||||
|
* `transforms <transforms.html>`_ Defines ``Transform``.
|
||||||
|
* `vector2 <vector2.html>`_ Defines ``Vector2``.
|
||||||
|
* `vector3 <vector3.html>`_ Defines ``Vector3``.
|
||||||
|
* `godotbase <godotbase.html>`_ Defines ``Error`` type and few common math
|
||||||
|
procedures missing in Nim's standard library.
|
||||||
|
|
||||||
|
|
||||||
|
Godot API
|
||||||
|
---------
|
||||||
|
|
||||||
|
This is an auto-generated list of Godot API modules. It's built from Godot
|
||||||
|
changeset `$GODOTAPI_CHANGESET_HASH
|
||||||
|
<https://github.com/godotengine/godot/commit/$GODOTAPI_CHANGESET_HASH>`_.
|
||||||
|
|
||||||
|
$AUTO_GENERATED_GODOTAPI_LIST
|
||||||
|
|
||||||
|
|
||||||
|
godotinternal Module
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
Contains low-level wrappers over Godot types that require manual memory
|
||||||
|
management. This module is used within ``godot-nim`` implementation and you
|
||||||
|
don't need to import it unless you know what you are doing.
|
||||||
|
|
||||||
|
* `godotdictionaries <godotdictionaries.html>`_
|
||||||
|
* `godotnodepaths <godotnodepaths.html>`_
|
||||||
|
* `godotpoolarrays <godotpoolarrays.html>`_
|
||||||
|
* `godotstrings <godotstrings.html>`_
|
||||||
|
* `godotvariants <godotvariants.html>`_
|
||||||
1
docs/nim.cfg
Normal file
1
docs/nim.cfg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
--threads:on
|
||||||
7
godot.nimble
Normal file
7
godot.nimble
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
version = "0.8.2"
|
||||||
|
author = "Xored Software, Inc."
|
||||||
|
description = "Godot Engine bindings"
|
||||||
|
license = "MIT"
|
||||||
|
srcDir = "godot"
|
||||||
|
|
||||||
|
requires "nim >= 0.17.3", "compiler >= 0.17.3"
|
||||||
79
godot/core/aabb.nim
Normal file
79
godot/core/aabb.nim
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
# Copyright (c) 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
import hashes
|
||||||
|
|
||||||
|
import vector3
|
||||||
|
import internal/godotinternaltypes, internal/godotstrings
|
||||||
|
import godotcoretypes, gdnativeapi
|
||||||
|
|
||||||
|
proc initAABB*(pos, size: Vector3): AABB {.inline.} =
|
||||||
|
AABB(position: pos, size: size)
|
||||||
|
|
||||||
|
proc `$`*(self: AABB): string {.inline.} =
|
||||||
|
$getGDNativeAPI().aabbAsString(self)
|
||||||
|
|
||||||
|
proc hash*(self: AABB): Hash {.inline.} =
|
||||||
|
!$(self.position.hash() !& self.size.hash())
|
||||||
|
|
||||||
|
proc area*(self: AABB): float32 {.inline.} =
|
||||||
|
getGDNativeAPI().aabbGetArea(self)
|
||||||
|
|
||||||
|
proc hasNoArea*(self: AABB): bool {.inline.} =
|
||||||
|
getGDNativeAPI().aabbHasNoArea(self)
|
||||||
|
|
||||||
|
proc hasNoSurface*(self: AABB): bool {.inline.} =
|
||||||
|
getGDNativeAPI().aabbHasNoSurface(self)
|
||||||
|
|
||||||
|
proc intersects*(self, other: AABB): bool {.inline.} =
|
||||||
|
getGDNativeAPI().aabbIntersects(self, other)
|
||||||
|
|
||||||
|
proc encloses*(self, other: AABB): bool {.inline.} =
|
||||||
|
getGDNativeAPI().aabbEncloses(self, other)
|
||||||
|
|
||||||
|
proc merge*(self, other: AABB): AABB {.inline.} =
|
||||||
|
getGDNativeAPI().aabbMerge(self, other).toAABB()
|
||||||
|
|
||||||
|
proc intersection*(self, other: AABB): AABB {.inline.} =
|
||||||
|
getGDNativeAPI().aabbIntersection(self, other).toAABB()
|
||||||
|
|
||||||
|
proc intersectsPlane*(self: AABB; plane: Plane): bool {.inline.} =
|
||||||
|
getGDNativeAPI().aabbIntersectsPlane(self, plane)
|
||||||
|
|
||||||
|
proc intersectsSegment*(self: AABB; start, to: Vector3): bool {.inline.} =
|
||||||
|
getGDNativeAPI().aabbIntersectsSegment(self, start, to)
|
||||||
|
|
||||||
|
proc contains*(self: AABB; point: Vector3): bool {.inline.} =
|
||||||
|
getGDNativeAPI().aabbHasPoint(self, point)
|
||||||
|
|
||||||
|
proc getSupport*(self: AABB; dir: Vector3): Vector3 {.inline.} =
|
||||||
|
getGDNativeAPI().aabbGetSupport(self, dir).toVector3()
|
||||||
|
|
||||||
|
proc getLongestAxis*(self: AABB): Vector3 {.inline.} =
|
||||||
|
getGDNativeAPI().aabbGetLongestAxis(self).toVector3()
|
||||||
|
|
||||||
|
proc getLongestAxisIndex*(self: AABB): cint {.inline.} =
|
||||||
|
getGDNativeAPI().aabbGetLongestAxisIndex(self)
|
||||||
|
|
||||||
|
proc getLongestAxisSize*(self: AABB): float32 {.inline.} =
|
||||||
|
getGDNativeAPI().aabbGetLongestAxisSize(self)
|
||||||
|
|
||||||
|
proc getShortestAxis*(self: AABB): Vector3 {.inline.} =
|
||||||
|
getGDNativeAPI().aabbGetShortestAxis(self).toVector3()
|
||||||
|
|
||||||
|
proc getShortestAxisIndex*(self: AABB): cint {.inline.} =
|
||||||
|
getGDNativeAPI().aabbGetShortestAxisIndex(self)
|
||||||
|
|
||||||
|
proc getShortestAxisSize*(self: AABB): float32 {.inline.} =
|
||||||
|
getGDNativeAPI().aabbGetShortestAxisSize(self)
|
||||||
|
|
||||||
|
proc expand*(self: AABB; toPoint: Vector3): AABB {.inline.} =
|
||||||
|
getGDNativeAPI().aabbExpand(self, toPoint).toAABB()
|
||||||
|
|
||||||
|
proc grow*(self: AABB; by: float32): AABB {.inline.} =
|
||||||
|
getGDNativeAPI().aabbGrow(self, by).toAABB()
|
||||||
|
|
||||||
|
proc getEndpoint*(self: AABB; idx: cint): Vector3 {.inline.} =
|
||||||
|
getGDNativeAPI().aabbGetEndpoint(self, idx).toVector3()
|
||||||
|
|
||||||
|
proc `==`*(a, b: AABB): bool {.inline.} =
|
||||||
|
getGDNativeAPI().aabbOperatorEqual(a, b)
|
||||||
146
godot/core/arrays.nim
Normal file
146
godot/core/arrays.nim
Normal file
|
|
@ -0,0 +1,146 @@
|
||||||
|
# Copyright 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
import hashes
|
||||||
|
import internal/godotinternaltypes, internal/godotarrays
|
||||||
|
|
||||||
|
type
|
||||||
|
Array* = ref object
|
||||||
|
godotArray: GodotArray
|
||||||
|
|
||||||
|
proc godotArray*(arr: Array): ptr GodotArray {.inline.} =
|
||||||
|
## WARNING: do not keep the returned value for longer than the lifetime of
|
||||||
|
## ``arr``
|
||||||
|
addr arr.godotArray
|
||||||
|
|
||||||
|
proc arrayFinalizer(arr: Array) =
|
||||||
|
arr.godotArray.deinit()
|
||||||
|
|
||||||
|
proc newArray*(arr: GodotArray): Array {.inline.} =
|
||||||
|
new(result, arrayFinalizer)
|
||||||
|
result.godotArray = arr
|
||||||
|
|
||||||
|
import variants
|
||||||
|
|
||||||
|
proc newArray*(s: varargs[Variant]): Array =
|
||||||
|
new(result, arrayFinalizer)
|
||||||
|
initGodotArray(result.godotArray)
|
||||||
|
for v in s:
|
||||||
|
result.godotArray.add(v.godotVariant[])
|
||||||
|
|
||||||
|
proc newArray*(s: openarray[Variant]): Array =
|
||||||
|
result = newArray()
|
||||||
|
for v in s:
|
||||||
|
result.godotArray.add(v.godotVariant[])
|
||||||
|
|
||||||
|
import poolarrays
|
||||||
|
|
||||||
|
proc newArray*(pca: PoolColorArray): Array {.inline.} =
|
||||||
|
new(result, arrayFinalizer)
|
||||||
|
initGodotArray(result.godotArray, pca.godotPoolColorArray[])
|
||||||
|
|
||||||
|
proc newArray*(pv3a: PoolVector3Array): Array {.inline.} =
|
||||||
|
new(result, arrayFinalizer)
|
||||||
|
initGodotArray(result.godotArray, pv3a.godotPoolVector3Array[])
|
||||||
|
|
||||||
|
proc newArray*(pv2a: PoolVector2Array): Array {.inline.} =
|
||||||
|
new(result, arrayFinalizer)
|
||||||
|
initGodotArray(result.godotArray, pv2a.godotPoolVector2Array[])
|
||||||
|
|
||||||
|
proc newArray*(psa: PoolStringArray): Array {.inline.} =
|
||||||
|
new(result, arrayFinalizer)
|
||||||
|
initGodotArray(result.godotArray, psa.godotPoolStringArray[])
|
||||||
|
|
||||||
|
proc newArray*(pra: PoolRealArray): Array {.inline.} =
|
||||||
|
new(result, arrayFinalizer)
|
||||||
|
initGodotArray(result.godotArray, pra.godotPoolRealArray[])
|
||||||
|
|
||||||
|
proc newArray*(pia: PoolIntArray): Array {.inline.} =
|
||||||
|
new(result, arrayFinalizer)
|
||||||
|
initGodotArray(result.godotArray, pia.godotPoolIntArray[])
|
||||||
|
|
||||||
|
proc newArray*(pba: PoolByteArray): Array {.inline.} =
|
||||||
|
new(result, arrayFinalizer)
|
||||||
|
initGodotArray(result.godotArray, pba.godotPoolByteArray[])
|
||||||
|
|
||||||
|
proc `[]=`*(self: Array; idx: int; value: Variant) {.inline.} =
|
||||||
|
self.godotArray[idx.cint] = value.godotVariant[]
|
||||||
|
|
||||||
|
proc `[]`*(self: Array; idx: int): Variant {.inline.} =
|
||||||
|
newVariant(self.godotArray[idx.cint])
|
||||||
|
|
||||||
|
proc add*(self: Array; value: Variant) {.inline.} =
|
||||||
|
self.godotArray.add(value.godotVariant[])
|
||||||
|
|
||||||
|
proc clear*(self: Array) {.inline.} =
|
||||||
|
self.godotArray.clear()
|
||||||
|
|
||||||
|
proc count*(self: Array; value: Variant): int {.inline.} =
|
||||||
|
self.godotArray.count(value.godotVariant[]).int
|
||||||
|
|
||||||
|
proc isEmpty*(self: Array): bool {.inline.} =
|
||||||
|
self.godotArray.isEmpty()
|
||||||
|
|
||||||
|
proc erase*(self: Array; value: Variant) {.inline.} =
|
||||||
|
self.godotArray.erase(value.godotVariant[])
|
||||||
|
|
||||||
|
proc first*(self: Array): Variant {.inline.} =
|
||||||
|
newVariant(self.godotArray.first())
|
||||||
|
|
||||||
|
proc last*(self: Array): Variant {.inline.} =
|
||||||
|
newVariant(self.godotArray.last())
|
||||||
|
|
||||||
|
proc find*(self: Array; what: Variant; f: int): int {.inline.} =
|
||||||
|
self.godotArray.find(what.godotVariant[], f.cint).int
|
||||||
|
|
||||||
|
proc findLast*(self: Array; what: Variant): int {.inline.} =
|
||||||
|
self.godotArray.findLast(what.godotVariant[]).int
|
||||||
|
|
||||||
|
proc contains*(self: Array; value: Variant): bool {.inline.} =
|
||||||
|
self.godotArray.contains(value.godotVariant[])
|
||||||
|
|
||||||
|
proc hash*(self: Array): Hash {.inline.} =
|
||||||
|
hash(self.godotArray.godotHash())
|
||||||
|
|
||||||
|
proc insert*(self: Array; pos: int; value: Variant) {.inline.} =
|
||||||
|
self.godotArray.insert(pos.cint, value.godotVariant[])
|
||||||
|
|
||||||
|
proc reverse*(self: Array) {.inline.} =
|
||||||
|
self.godotArray.reverse()
|
||||||
|
|
||||||
|
proc popLast*(self: Array): Variant {.inline.} =
|
||||||
|
newVariant(self.godotArray.popLast())
|
||||||
|
|
||||||
|
proc popFirst*(self: Array): Variant {.inline.} =
|
||||||
|
newVariant(self.godotArray.popFirst())
|
||||||
|
|
||||||
|
proc addLast*(self: Array; value: Variant) {.inline.} =
|
||||||
|
self.godotArray.addLast(value.godotVariant[])
|
||||||
|
|
||||||
|
proc addFirst*(self: Array; value: Variant) {.inline.} =
|
||||||
|
self.godotArray.addFirst(value.godotVariant[])
|
||||||
|
|
||||||
|
proc delete*(self: Array; idx: int) {.inline.} =
|
||||||
|
self.godotArray.delete(idx.cint)
|
||||||
|
|
||||||
|
proc setLen*(self: Array; size: int) {.inline.} =
|
||||||
|
self.godotArray.setLen(size.cint)
|
||||||
|
|
||||||
|
proc rfind*(self: Array; what: Variant; fromIdx: int): int {.inline.} =
|
||||||
|
self.godotArray.rfind(what.godotVariant[], fromIdx.cint).int
|
||||||
|
|
||||||
|
proc len*(self: Array): int {.inline.} =
|
||||||
|
self.godotArray.len.int
|
||||||
|
|
||||||
|
proc sort*(self: Array) {.inline.} =
|
||||||
|
self.godotArray.sort()
|
||||||
|
|
||||||
|
iterator items*(self: Array): Variant =
|
||||||
|
for i in 0..<self.len:
|
||||||
|
yield self[i]
|
||||||
|
|
||||||
|
iterator pairs*(self: Array): tuple[key: int, val: Variant] =
|
||||||
|
for i in 0..<self.len:
|
||||||
|
yield (i, self[i])
|
||||||
|
|
||||||
|
proc `$`*(self: Array): string =
|
||||||
|
$self.godotArray
|
||||||
459
godot/core/basis.nim
Normal file
459
godot/core/basis.nim
Normal file
|
|
@ -0,0 +1,459 @@
|
||||||
|
# Copyright (c) 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
import math, hashes
|
||||||
|
|
||||||
|
import godotbase, vector3, quats
|
||||||
|
import godotcoretypes
|
||||||
|
|
||||||
|
{.push stackTrace: off.}
|
||||||
|
|
||||||
|
proc setCells*(basis: var Basis, xx, xy, xz, yx, yy, yz, zx, zy, zz: float32) =
|
||||||
|
basis.elements[0].x = xx
|
||||||
|
basis.elements[0].y = xy
|
||||||
|
basis.elements[0].z = xz
|
||||||
|
basis.elements[1].x = yx
|
||||||
|
basis.elements[1].y = yy
|
||||||
|
basis.elements[1].z = yz
|
||||||
|
basis.elements[2].x = zx
|
||||||
|
basis.elements[2].y = zy
|
||||||
|
basis.elements[2].z = zz
|
||||||
|
|
||||||
|
proc `[]`*(self: Basis; row: range[0..2]): Vector3 {.inline.} =
|
||||||
|
self.elements[row]
|
||||||
|
|
||||||
|
proc `[]`*(self: var Basis; row: range[0..2]): var Vector3 {.inline.} =
|
||||||
|
self.elements[row]
|
||||||
|
|
||||||
|
proc `[]=`*(self: var Basis; row: range[0..2];
|
||||||
|
value: Vector3) {.inline.} =
|
||||||
|
self.elements[row] = value
|
||||||
|
|
||||||
|
proc `==`*(self, other: Basis): bool =
|
||||||
|
for i in 0..2:
|
||||||
|
for j in 0..2:
|
||||||
|
if self[i][j] != other[i][j]:
|
||||||
|
return false
|
||||||
|
result = true
|
||||||
|
|
||||||
|
proc isEqualApprox*(self, other: Basis): bool =
|
||||||
|
for i in 0..2:
|
||||||
|
for j in 0..2:
|
||||||
|
if not self[i][j].isEqualApprox(other[i][j]):
|
||||||
|
return false
|
||||||
|
result = true
|
||||||
|
|
||||||
|
proc tdotx*(self: Basis; v: Vector3): float32 {.inline.} =
|
||||||
|
self.elements[0].x * v.x + self.elements[1].x * v.y + self.elements[2].x * v.z
|
||||||
|
|
||||||
|
proc tdoty*(self: Basis; v: Vector3): float32 {.inline.} =
|
||||||
|
self.elements[0].y * v.x + self.elements[1].y * v.y + self.elements[2].y * v.z
|
||||||
|
|
||||||
|
proc tdotz*(self: Basis; v: Vector3): float32 {.inline.} =
|
||||||
|
self.elements[0].z * v.x + self.elements[1].z * v.y + self.elements[2].z * v.z
|
||||||
|
|
||||||
|
proc `+`*(self, other: Basis): Basis {.inline.} =
|
||||||
|
result[0] = self[0] + other[0]
|
||||||
|
result[1] = self[1] + other[1]
|
||||||
|
result[2] = self[2] + other[2]
|
||||||
|
|
||||||
|
proc `+=`*(self: var Basis, other: Basis) {.inline.} =
|
||||||
|
self[0] += other[0]
|
||||||
|
self[1] += other[1]
|
||||||
|
self[2] += other[2]
|
||||||
|
|
||||||
|
proc `-`*(self, other: Basis): Basis {.inline.} =
|
||||||
|
result[0] = self[0] - other[0]
|
||||||
|
result[1] = self[1] - other[1]
|
||||||
|
result[2] = self[2] - other[2]
|
||||||
|
|
||||||
|
proc `-=`*(self: var Basis, other: Basis) {.inline.} =
|
||||||
|
self[0] -= other[0]
|
||||||
|
self[1] -= other[1]
|
||||||
|
self[2] -= other[2]
|
||||||
|
|
||||||
|
proc `*`*(self, other: Basis): Basis {.inline.} =
|
||||||
|
result.setCells(
|
||||||
|
other.tdotx(self[0]), other.tdoty(self[0]), other.tdotz(self[0]),
|
||||||
|
other.tdotx(self[1]), other.tdoty(self[1]), other.tdotz(self[1]),
|
||||||
|
other.tdotx(self[2]), other.tdoty(self[2]), other.tdotz(self[2])
|
||||||
|
)
|
||||||
|
|
||||||
|
proc `*=`*(self: var Basis, other: Basis) {.inline.} =
|
||||||
|
self.setCells(
|
||||||
|
other.tdotx(self[0]), other.tdoty(self[0]), other.tdotz(self[0]),
|
||||||
|
other.tdotx(self[1]), other.tdoty(self[1]), other.tdotz(self[1]),
|
||||||
|
other.tdotx(self[2]), other.tdoty(self[2]), other.tdotz(self[2])
|
||||||
|
)
|
||||||
|
|
||||||
|
proc `*=`*(self: var Basis; b: float32) {.inline.} =
|
||||||
|
self[0] *= b
|
||||||
|
self[1] *= b
|
||||||
|
self[2] *= b
|
||||||
|
|
||||||
|
proc `*`*(self: Basis; b: float32): Basis {.inline.} =
|
||||||
|
result = self
|
||||||
|
result *= b
|
||||||
|
|
||||||
|
proc initBasis*(): Basis {.inline.} =
|
||||||
|
result.setCells(
|
||||||
|
1, 0, 0,
|
||||||
|
0, 1, 0,
|
||||||
|
0, 0, 1
|
||||||
|
)
|
||||||
|
|
||||||
|
proc initBasis*(row0, row1, row2: Vector3): Basis {.inline.} =
|
||||||
|
Basis(elements: [row0, row1, row2])
|
||||||
|
|
||||||
|
proc initBasis*(xx, xy, xz, yx, yy, yz, zx, zy, zz: float32): Basis =
|
||||||
|
result.setCells(xx, xy, xz, yx, yy, yz, zx, zy, zz)
|
||||||
|
|
||||||
|
proc initBasis*(euler: Quat): Basis {.inline.} =
|
||||||
|
let d = euler.lengthSquared()
|
||||||
|
let s = 2.0 / d
|
||||||
|
let xs = euler.x * s
|
||||||
|
let ys = euler.y * s
|
||||||
|
let zs = euler.z * s
|
||||||
|
let wx = euler.w * xs
|
||||||
|
let wy = euler.w * ys
|
||||||
|
let wz = euler.w * zs
|
||||||
|
let xx = euler.x * xs
|
||||||
|
let xy = euler.x * ys
|
||||||
|
let xz = euler.x * zs
|
||||||
|
let yy = euler.y * ys
|
||||||
|
let yz = euler.y * zs
|
||||||
|
let zz = euler.z * zs
|
||||||
|
result.setCells(
|
||||||
|
1.0 - (yy + zz), xy - wz, xz + wy,
|
||||||
|
xy + wz, 1.0 - (xx + zz), yz - wx,
|
||||||
|
xz - wy, yz + wx, 1.0 - (xx + yy))
|
||||||
|
|
||||||
|
proc setAxisAngle(self: var Basis, axis: Vector3, phi: float32) =
|
||||||
|
assert(axis.isNormalized())
|
||||||
|
let axisSq = vec3(axis.x * axis.x, axis.y * axis.y, axis.z * axis.z)
|
||||||
|
|
||||||
|
let cosine = cos(phi);
|
||||||
|
let sine = sin(phi);
|
||||||
|
|
||||||
|
self.elements[0].x = axisSq.x + cosine * (1.0 - axisSq.x)
|
||||||
|
self.elements[0].y = axis.x * axis.y * (1.0 - cosine) - axis.z * sine
|
||||||
|
self.elements[0].z = axis.z * axis.x * (1.0 - cosine) + axis.y * sine
|
||||||
|
|
||||||
|
self.elements[1].x = axis.x * axis.y * (1.0 - cosine) + axis.z * sine
|
||||||
|
self.elements[1].y = axisSq.y + cosine * (1.0 - axisSq.y)
|
||||||
|
self.elements[1].z = axis.y * axis.z * (1.0 - cosine) - axis.x * sine
|
||||||
|
|
||||||
|
self.elements[2].x = axis.z * axis.x * (1.0 - cosine) - axis.y * sine
|
||||||
|
self.elements[2].y = axis.y * axis.z * (1.0 - cosine) + axis.x * sine
|
||||||
|
self.elements[2].z = axisSq.z + cosine * (1.0 - axisSq.z)
|
||||||
|
|
||||||
|
proc initBasis*(axis: Vector3, phi: float32): Basis {.inline.} =
|
||||||
|
result.setAxisAngle(axis, phi)
|
||||||
|
|
||||||
|
proc setEuler*(self: var Basis, euler: Vector3) =
|
||||||
|
var c = cos(euler.x)
|
||||||
|
var s = sin(euler.x)
|
||||||
|
|
||||||
|
let xmat = initBasis(1.0, 0.0, 0.0, 0.0, c, -s, 0.0, s, c)
|
||||||
|
|
||||||
|
c = cos(euler.y)
|
||||||
|
s = sin(euler.y)
|
||||||
|
let ymat = initBasis(c, 0.0, s, 0.0, 1.0, 0.0, -s, 0.0, c)
|
||||||
|
|
||||||
|
c = cos(euler.z)
|
||||||
|
s = sin(euler.z)
|
||||||
|
let zmat = initBasis(c, -s, 0.0, s, c, 0.0, 0.0, 0.0, 1.0)
|
||||||
|
|
||||||
|
self = xmat * (ymat * zmat)
|
||||||
|
|
||||||
|
proc getEuler*(self: Basis): Vector3 =
|
||||||
|
result.y = arcsin(self.elements[0].z)
|
||||||
|
if result.y < PI * 0.5:
|
||||||
|
if result.y > -PI * 0.5:
|
||||||
|
result.x = arctan2(-self.elements[1].z, self.elements[2].z)
|
||||||
|
result.z = arctan2(-self.elements[0].y, self.elements[0].x)
|
||||||
|
else:
|
||||||
|
let r = arctan2(self.elements[1].x, self.elements[1].y)
|
||||||
|
result.x = -r
|
||||||
|
else:
|
||||||
|
let r = arctan2(self.elements[0].y, self.elements[1].y)
|
||||||
|
result.x = r
|
||||||
|
|
||||||
|
proc initBasis*(euler: Vector3): Basis {.inline.} =
|
||||||
|
result.setEuler(euler)
|
||||||
|
|
||||||
|
proc outer*(self, other: Vector3): Basis {.inline.} =
|
||||||
|
let row0 = vec3(self.x * other.x, self.x * other.y, self.x * other.z)
|
||||||
|
let row1 = vec3(self.y * other.x, self.y * other.y, self.y * other.z)
|
||||||
|
let row2 = vec3(self.z * other.x, self.z * other.y, self.z * other.z)
|
||||||
|
initBasis(row0, row1, row2)
|
||||||
|
|
||||||
|
proc toDiagonalMatrix*(self: Vector3): Basis {.inline.} =
|
||||||
|
initBasis(
|
||||||
|
self.x, 0, 0,
|
||||||
|
0, self.y, 0,
|
||||||
|
0, 0, self.z
|
||||||
|
)
|
||||||
|
|
||||||
|
proc `$`*(self: Basis): string {.inline.} =
|
||||||
|
result = newStringOfCap(128)
|
||||||
|
for i in 0..2:
|
||||||
|
for j in 0..2:
|
||||||
|
if i != 0 or j != 0:
|
||||||
|
result.add(", ")
|
||||||
|
result.add($self[i][j])
|
||||||
|
|
||||||
|
proc hash*(self: Basis): Hash {.inline.} =
|
||||||
|
!$(self.elements[0].hash() !& self.elements[1].hash() !& self.elements[2].hash())
|
||||||
|
|
||||||
|
template cofac(row1, col1, row2, col2: int): float32 =
|
||||||
|
self.elements[row1][col1] * self.elements[row2][col2] -
|
||||||
|
self.elements[row1][col2] * self.elements[row2][col1]
|
||||||
|
|
||||||
|
proc determinant(self: Basis): float32 {.inline.} =
|
||||||
|
self[0][0] * cofac(1, 1, 2, 2) -
|
||||||
|
self[1][0] * cofac(0, 1, 2, 2) +
|
||||||
|
self[2][0] * cofac(0, 1, 1, 2)
|
||||||
|
|
||||||
|
proc invert*(self: var Basis) =
|
||||||
|
let co = [cofac(1, 1, 2, 2), cofac(1, 2, 2, 0), cofac(1, 0, 2, 1)]
|
||||||
|
let det = self.elements[0][0] * co[0] +
|
||||||
|
self.elements[0][1] * co[1] +
|
||||||
|
self.elements[0][2] * co[2]
|
||||||
|
assert(det != 0)
|
||||||
|
let s = 1.0'f32 / det
|
||||||
|
self.setCells(
|
||||||
|
co[0] * s, cofac(0, 2, 2, 1) * s, cofac(0, 1, 1, 2) * s,
|
||||||
|
co[1] * s, cofac(0, 0, 2, 2) * s, cofac(0, 2, 1, 0) * s,
|
||||||
|
co[2] * s, cofac(0, 1, 2, 0) * s, cofac(0, 0, 1, 1) * s
|
||||||
|
)
|
||||||
|
|
||||||
|
proc inverse*(self: Basis): Basis {.inline.} =
|
||||||
|
result = self
|
||||||
|
result.invert()
|
||||||
|
|
||||||
|
proc axis*(self: Basis; idx: range[0..2]): Vector3 {.inline.} =
|
||||||
|
vec3(self[0][idx], self[1][idx], self[2][idx])
|
||||||
|
|
||||||
|
proc setAxis*(self: var Basis; idx: range[0..2]; value: Vector3) {.inline.} =
|
||||||
|
self.elements[0][idx] = value.x
|
||||||
|
self.elements[1][idx] = value.y
|
||||||
|
self.elements[2][idx] = value.z
|
||||||
|
|
||||||
|
proc row*(self: Basis; row: range[0..2]): Vector3 {.inline.} =
|
||||||
|
self.elements[row]
|
||||||
|
|
||||||
|
proc setRow*(self: var Basis; row: range[0..2]; value: Vector3) {.inline.} =
|
||||||
|
self.elements[row] = value
|
||||||
|
|
||||||
|
proc getMainDiagonal*(self: Basis): Vector3 {.inline.} =
|
||||||
|
vec3(self.elements[0][0], self.elements[1][1], self.elements[2][2])
|
||||||
|
|
||||||
|
proc zero*(self: var Basis) {.inline.} =
|
||||||
|
self.elements[0].zero()
|
||||||
|
self.elements[1].zero()
|
||||||
|
self.elements[2].zero()
|
||||||
|
|
||||||
|
proc orthonormalize(self: var Basis) =
|
||||||
|
var x = self.axis(0)
|
||||||
|
var y = self.axis(1)
|
||||||
|
var z = self.axis(2)
|
||||||
|
|
||||||
|
x.normalize()
|
||||||
|
y = y - x * x.dot(y)
|
||||||
|
y.normalize()
|
||||||
|
z = z - x * x.dot(z) - y * y.dot(z)
|
||||||
|
z.normalize()
|
||||||
|
|
||||||
|
self.setAxis(0, x)
|
||||||
|
self.setAxis(1, y)
|
||||||
|
self.setAxis(2, z)
|
||||||
|
|
||||||
|
proc orthonormalized*(self: Basis): Basis {.inline.} =
|
||||||
|
result = self
|
||||||
|
result.orthonormalize()
|
||||||
|
|
||||||
|
proc transpose*(self: var Basis) {.inline.} =
|
||||||
|
swap(self.elements[0].x, self.elements[1].x)
|
||||||
|
swap(self.elements[0].z, self.elements[2].x)
|
||||||
|
swap(self.elements[1].z, self.elements[2].y)
|
||||||
|
|
||||||
|
proc transposed*(self: Basis): Basis {.inline.} =
|
||||||
|
result = self
|
||||||
|
result.transpose()
|
||||||
|
|
||||||
|
proc isOrthogonal*(self: Basis): bool {.inline.} =
|
||||||
|
let id = initBasis()
|
||||||
|
let m = self * self.transposed()
|
||||||
|
result = id.isEqualApprox(m)
|
||||||
|
|
||||||
|
proc isRotation*(self: Basis): bool {.inline.} =
|
||||||
|
self.determinant().isEqualApprox(1.0) and self.isOrthogonal()
|
||||||
|
|
||||||
|
proc isSymmetric*(self: Basis): bool {.inline.} =
|
||||||
|
if not self.elements[0][1].isEqualApprox(self.elements[1][0]):
|
||||||
|
return false
|
||||||
|
if not self.elements[0][2].isEqualApprox(self.elements[2][0]):
|
||||||
|
return false
|
||||||
|
if not self.elements[1][2].isEqualApprox(self.elements[2][1]):
|
||||||
|
return false
|
||||||
|
result = true
|
||||||
|
|
||||||
|
proc scale*(self: var Basis, scale: Vector3) =
|
||||||
|
self[0].x *= scale.x
|
||||||
|
self[0].y *= scale.x
|
||||||
|
self[0].z *= scale.x
|
||||||
|
self[1].x *= scale.y
|
||||||
|
self[1].y *= scale.y
|
||||||
|
self[1].z *= scale.y
|
||||||
|
self[2].x *= scale.z
|
||||||
|
self[2].y *= scale.z
|
||||||
|
self[2].z *= scale.z
|
||||||
|
|
||||||
|
proc scaled*(self: Basis, scale: Vector3): Basis =
|
||||||
|
result = self
|
||||||
|
result.scale(scale)
|
||||||
|
|
||||||
|
proc rotated*(self: Basis; axis: Vector3; phi: float32): Basis {.inline.} =
|
||||||
|
initBasis(axis, phi) * self
|
||||||
|
|
||||||
|
proc rotate*(self: var Basis; axis: Vector3; phi: float32) {.inline.} =
|
||||||
|
self = self.rotated(axis, phi)
|
||||||
|
|
||||||
|
proc rotated*(self: Basis; euler: Vector3): Basis {.inline.} =
|
||||||
|
initBasis(euler) * self
|
||||||
|
|
||||||
|
proc rotate*(self: var Basis; euler: Vector3) {.inline.} =
|
||||||
|
self = self.rotated(euler)
|
||||||
|
|
||||||
|
proc getScale*(self: Basis): Vector3 =
|
||||||
|
let detSign = if self.determinant() > 0: 1'f32 else: -1'f32
|
||||||
|
result = detSign * vec3(
|
||||||
|
vec3(self.elements[0].x, self.elements[1].x, self.elements[2].x).length(),
|
||||||
|
vec3(self.elements[0].y, self.elements[1].y, self.elements[2].y).length(),
|
||||||
|
vec3(self.elements[0].z, self.elements[1].z, self.elements[2].z).length(),
|
||||||
|
)
|
||||||
|
|
||||||
|
proc getRotation*(self: Basis): Vector3 {.inline.} =
|
||||||
|
var m = self.orthonormalized()
|
||||||
|
let det = m.determinant()
|
||||||
|
if det < 0:
|
||||||
|
m.scale(vec3(-1, -1, -1))
|
||||||
|
result = m.getEuler()
|
||||||
|
|
||||||
|
proc setScale*(self: var Basis; scale: Vector3) =
|
||||||
|
let e = self.getEuler()
|
||||||
|
self = initBasis() # reset to identity
|
||||||
|
self.scale(scale)
|
||||||
|
self.rotate(e)
|
||||||
|
|
||||||
|
proc setRotationEuler*(self: var Basis; euler: Vector3) =
|
||||||
|
let s = self.getScale()
|
||||||
|
self = initBasis()
|
||||||
|
self.scale(s)
|
||||||
|
self.rotate(euler)
|
||||||
|
|
||||||
|
proc setRotationAxisAngle*(self: var Basis; axis: Vector3; angle: float32) =
|
||||||
|
let s = self.getScale()
|
||||||
|
self = initBasis()
|
||||||
|
self.scale(s)
|
||||||
|
self.rotate(axis, angle)
|
||||||
|
|
||||||
|
proc asQuat*(self: Basis): Quat =
|
||||||
|
let trace = self.elements[0].x + self.elements[1].y + self.elements[2].z
|
||||||
|
var temp: array[4, float32]
|
||||||
|
if trace > 0'f32:
|
||||||
|
var s = sqrt(trace + 1.0)
|
||||||
|
temp[3] = s * 0.5
|
||||||
|
s = 0.5 / s
|
||||||
|
|
||||||
|
temp[0] = (self.elements[2].y - self.elements[1].z) * s
|
||||||
|
temp[1] = (self.elements[0].z - self.elements[2].x) * s
|
||||||
|
temp[2] = (self.elements[1].x - self.elements[0].y) * s
|
||||||
|
else:
|
||||||
|
let i = if self.elements[0].x < self.elements[1].y:
|
||||||
|
if self.elements[1].y < self.elements[2].z: 2 else: 1
|
||||||
|
else:
|
||||||
|
if self.elements[0].x < self.elements[2].z: 2 else: 0
|
||||||
|
let j = (i + 1) mod 3
|
||||||
|
let k = (i + 2) mod 3
|
||||||
|
|
||||||
|
var s = sqrt(self.elements[i][i] - self.elements[j][j] -
|
||||||
|
self.elements[k][k] + 1.0)
|
||||||
|
temp[i] = s * 0.5
|
||||||
|
s = 0.5 / s
|
||||||
|
|
||||||
|
temp[3] = (self.elements[k][j] - self.elements[j][k]) * s
|
||||||
|
temp[j] = (self.elements[j][i] + self.elements[i][j]) * s
|
||||||
|
temp[k] = (self.elements[k][i] + self.elements[i][k]) * s
|
||||||
|
|
||||||
|
result = initQuat(temp[0], temp[1], temp[2], temp[3])
|
||||||
|
|
||||||
|
proc xform*(self: Basis; v: Vector3): Vector3 {.inline.} =
|
||||||
|
vec3(
|
||||||
|
self.elements[0].dot(v),
|
||||||
|
self.elements[1].dot(v),
|
||||||
|
self.elements[2].dot(v)
|
||||||
|
)
|
||||||
|
|
||||||
|
proc xformInv*(self: Basis; v: Vector3): Vector3 {.inline.} =
|
||||||
|
vec3(
|
||||||
|
self.elements[0].x * v.x + self.elements[1].x * v.y + self.elements[2].x * v.z,
|
||||||
|
self.elements[0].y * v.x + self.elements[1].y * v.y + self.elements[2].y * v.z,
|
||||||
|
self.elements[0].z * v.x + self.elements[1].z * v.y + self.elements[2].z * v.z,
|
||||||
|
)
|
||||||
|
|
||||||
|
const orthoBases = [
|
||||||
|
initBasis(1, 0, 0, 0, 1, 0, 0, 0, 1),
|
||||||
|
initBasis(0, -1, 0, 1, 0, 0, 0, 0, 1),
|
||||||
|
initBasis(-1, 0, 0, 0, -1, 0, 0, 0, 1),
|
||||||
|
initBasis(0, 1, 0, -1, 0, 0, 0, 0, 1),
|
||||||
|
initBasis(1, 0, 0, 0, 0, -1, 0, 1, 0),
|
||||||
|
initBasis(0, 0, 1, 1, 0, 0, 0, 1, 0),
|
||||||
|
initBasis(-1, 0, 0, 0, 0, 1, 0, 1, 0),
|
||||||
|
initBasis(0, 0, -1, -1, 0, 0, 0, 1, 0),
|
||||||
|
initBasis(1, 0, 0, 0, -1, 0, 0, 0, -1),
|
||||||
|
initBasis(0, 1, 0, 1, 0, 0, 0, 0, -1),
|
||||||
|
initBasis(-1, 0, 0, 0, 1, 0, 0, 0, -1),
|
||||||
|
initBasis(0, -1, 0, -1, 0, 0, 0, 0, -1),
|
||||||
|
initBasis(1, 0, 0, 0, 0, 1, 0, -1, 0),
|
||||||
|
initBasis(0, 0, -1, 1, 0, 0, 0, -1, 0),
|
||||||
|
initBasis(-1, 0, 0, 0, 0, -1, 0, -1, 0),
|
||||||
|
initBasis(0, 0, 1, -1, 0, 0, 0, -1, 0),
|
||||||
|
initBasis(0, 0, 1, 0, 1, 0, -1, 0, 0),
|
||||||
|
initBasis(0, -1, 0, 0, 0, 1, -1, 0, 0),
|
||||||
|
initBasis(0, 0, -1, 0, -1, 0, -1, 0, 0),
|
||||||
|
initBasis(0, 1, 0, 0, 0, -1, -1, 0, 0),
|
||||||
|
initBasis(0, 0, 1, 0, -1, 0, 1, 0, 0),
|
||||||
|
initBasis(0, 1, 0, 0, 0, 1, 1, 0, 0),
|
||||||
|
initBasis(0, 0, -1, 0, 1, 0, 1, 0, 0),
|
||||||
|
initBasis(0, -1, 0, 0, 0, -1, 1, 0, 0)
|
||||||
|
]
|
||||||
|
|
||||||
|
proc orthogonalIndex*(self: Basis): int =
|
||||||
|
var orth = self
|
||||||
|
for i in 0..2:
|
||||||
|
for j in 0..2:
|
||||||
|
var v = orth[i][j]
|
||||||
|
if v > 0.5:
|
||||||
|
v = 1.0'f32
|
||||||
|
elif v < -0.5:
|
||||||
|
v = -1.0'f32
|
||||||
|
else:
|
||||||
|
v = 0'f32
|
||||||
|
orth[i][j] = v
|
||||||
|
|
||||||
|
for idx, base in orthoBases:
|
||||||
|
if base == orth:
|
||||||
|
return idx
|
||||||
|
|
||||||
|
proc setOrthogonalIndex*(self: var Basis, idx: range[0..23]) =
|
||||||
|
self = orthoBases[idx]
|
||||||
|
|
||||||
|
proc rotate*(self: var Vector3; axis: Vector3; phi: float32) =
|
||||||
|
self = initBasis(axis, phi).xform(self)
|
||||||
|
|
||||||
|
proc rotated*(self: Vector3; axis: Vector3; phi: float32): Vector3 =
|
||||||
|
result = self
|
||||||
|
result.rotate(axis, phi)
|
||||||
|
|
||||||
|
{.pop.} # stackTrace: off
|
||||||
88
godot/core/colors.nim
Normal file
88
godot/core/colors.nim
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
# Copyright (c) 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
import hashes
|
||||||
|
|
||||||
|
import godotcoretypes, gdnativeapi
|
||||||
|
|
||||||
|
proc initColor*(r, g, b: float32; a: float32 = 1.0'f32): Color {.inline.} =
|
||||||
|
Color(
|
||||||
|
r: r,
|
||||||
|
g: g,
|
||||||
|
b: b,
|
||||||
|
a: a
|
||||||
|
)
|
||||||
|
|
||||||
|
proc initColor*(): Color {.inline.} =
|
||||||
|
## Initializes black color with 1.0 alpha
|
||||||
|
initColor(0, 0, 0)
|
||||||
|
|
||||||
|
proc h*(self: Color): float32 {.inline.} =
|
||||||
|
getGDNativeAPI().colorGetH(self)
|
||||||
|
|
||||||
|
proc s*(self: Color): float32 {.inline.} =
|
||||||
|
getGDNativeAPI().colorGetS(self)
|
||||||
|
|
||||||
|
proc v*(self: Color): float32 {.inline.} =
|
||||||
|
getGDNativeAPI().colorGetV(self)
|
||||||
|
|
||||||
|
proc `$`*(self: Color): string {.inline.} =
|
||||||
|
result = newStringOfCap(50)
|
||||||
|
result.add($self.r)
|
||||||
|
result.add(", ")
|
||||||
|
result.add($self.g)
|
||||||
|
result.add(", ")
|
||||||
|
result.add($self.b)
|
||||||
|
result.add(", ")
|
||||||
|
result.add($self.a)
|
||||||
|
|
||||||
|
proc hash*(self: Color): Hash {.inline.} =
|
||||||
|
!$(self.r.hash() !& self.g.hash() !& self.b.hash() !& self.a.hash())
|
||||||
|
|
||||||
|
proc toHex(val: float32, target: var string, targetIdx: int) =
|
||||||
|
let val = clamp(int(val * 255), 0, 255)
|
||||||
|
let nums = [(val and 0xF0) shr 4, val and 0xF]
|
||||||
|
for i, num in nums:
|
||||||
|
target[targetIdx + i] = if num < 10: chr(ord('0') + num)
|
||||||
|
else: chr(ord('A') + (num - 10))
|
||||||
|
|
||||||
|
proc toHtml*(self: Color, withAlpha: bool): string =
|
||||||
|
let size = if withAlpha: 8 else: 6
|
||||||
|
result = newString(size)
|
||||||
|
toHex(self.r, result, 0)
|
||||||
|
toHex(self.g, result, 2)
|
||||||
|
toHex(self.b, result, 4)
|
||||||
|
if withAlpha:
|
||||||
|
toHex(self.b, result, 6)
|
||||||
|
|
||||||
|
proc toARGB32*(self: Color): uint32 {.inline.} =
|
||||||
|
result = uint8(self.a * 255)
|
||||||
|
result = (result shl 8) or uint8(self.r * 255)
|
||||||
|
result = (result shl 8) or uint8(self.g * 255)
|
||||||
|
result = (result shl 8) or uint8(self.b * 255)
|
||||||
|
|
||||||
|
proc gray*(self: Color): float32 {.inline.} =
|
||||||
|
getGDNativeAPI().colorGray(self)
|
||||||
|
|
||||||
|
proc inverted*(self: Color): Color {.inline.} =
|
||||||
|
getGDNativeAPI().colorInverted(self).toColor()
|
||||||
|
|
||||||
|
proc contrasted*(self: Color): Color {.inline.} =
|
||||||
|
getGDNativeAPI().colorContrasted(self).toColor()
|
||||||
|
|
||||||
|
proc lerp*(self: Color; b: Color; t: float32): Color {.inline.} =
|
||||||
|
getGDNativeAPI().colorLinearInterpolate(self, b, t).toColor()
|
||||||
|
|
||||||
|
proc blend*(self: Color; over: Color): Color {.inline.} =
|
||||||
|
getGDNativeAPI().colorBlend(self, over).toColor()
|
||||||
|
|
||||||
|
proc `==`*(a, b: Color): bool {.inline.} =
|
||||||
|
a.r == b.r and a.g == b.g and a.b == b.b and a.a == b.a
|
||||||
|
|
||||||
|
proc `<`*(a, b: Color): bool =
|
||||||
|
if a.r == b.r:
|
||||||
|
if a.g == b.g:
|
||||||
|
if a.b == b.b:
|
||||||
|
return a.a < b.a
|
||||||
|
return a.b < b.b
|
||||||
|
return a.g < b.g
|
||||||
|
return a.r < b.r
|
||||||
110
godot/core/dictionaries.nim
Normal file
110
godot/core/dictionaries.nim
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
# Copyright 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
import hashes
|
||||||
|
import internal/godotinternaltypes, internal/godotdictionaries,
|
||||||
|
internal/godotvariants, internal/godotstrings
|
||||||
|
|
||||||
|
type
|
||||||
|
Dictionary* = ref object
|
||||||
|
godotDictionary: GodotDictionary
|
||||||
|
|
||||||
|
proc dictionaryFinalizer(dict: Dictionary) =
|
||||||
|
dict.godotDictionary.deinit()
|
||||||
|
|
||||||
|
proc newDictionary*(): Dictionary {.inline.} =
|
||||||
|
new(result, dictionaryFinalizer)
|
||||||
|
initGodotDictionary(result.godotDictionary)
|
||||||
|
|
||||||
|
proc newDictionary*(dict: GodotDictionary): Dictionary {.inline.} =
|
||||||
|
new(result, dictionaryFinalizer)
|
||||||
|
result.godotDictionary = dict
|
||||||
|
|
||||||
|
proc godotDictionary*(dict: Dictionary): ptr GodotDictionary =
|
||||||
|
## WARNING: do not keep the returned value for longer than the lifetime of
|
||||||
|
## ``dict``
|
||||||
|
addr dict.godotDictionary
|
||||||
|
|
||||||
|
proc len*(self: Dictionary): int {.inline.} =
|
||||||
|
self.godotDictionary.len.int
|
||||||
|
|
||||||
|
proc isEmpty*(self: Dictionary): bool {.inline.} =
|
||||||
|
self.godotDictionary.isEmpty()
|
||||||
|
|
||||||
|
proc clear*(self: Dictionary) {.inline.} =
|
||||||
|
self.godotDictionary.clear()
|
||||||
|
|
||||||
|
proc hash*(self: Dictionary): Hash {.inline.} =
|
||||||
|
hash(self.godotDictionary.godotHash())
|
||||||
|
|
||||||
|
import variants, arrays
|
||||||
|
|
||||||
|
proc newVariant*(dict: Dictionary): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
initGodotVariant(result.godotVariant[], dict.godotDictionary)
|
||||||
|
|
||||||
|
proc asDictionary*(self: Variant): Dictionary {.inline.} =
|
||||||
|
newDictionary(self.godotVariant[].asGodotDictionary())
|
||||||
|
|
||||||
|
proc contains*(self: Dictionary; key: Variant): bool {.inline.}=
|
||||||
|
self.godotDictionary.contains(key.godotVariant[])
|
||||||
|
|
||||||
|
proc contains*(self: Dictionary; keys: Array): bool {.inline.} =
|
||||||
|
self.godotDictionary.contains(keys.godotArray[])
|
||||||
|
|
||||||
|
proc del*(self: Dictionary; key: Variant) {.inline.} =
|
||||||
|
self.godotDictionary.del(key.godotVariant[])
|
||||||
|
|
||||||
|
proc keys*(self: Dictionary): Array {.inline.} =
|
||||||
|
newArray(self.godotDictionary.keys())
|
||||||
|
|
||||||
|
proc values*(self: Dictionary): Array {.inline.} =
|
||||||
|
newArray(self.godotDictionary.values())
|
||||||
|
|
||||||
|
proc `[]`*(self: Dictionary; key: Variant): Variant {.inline.} =
|
||||||
|
newVariant(self.godotDictionary[key.godotVariant[]])
|
||||||
|
|
||||||
|
proc `[]`*(self: Dictionary; keyStr: string): Variant {.inline.} =
|
||||||
|
var godotVariant: GodotVariant
|
||||||
|
var godotStr = keyStr.toGodotString()
|
||||||
|
initGodotVariant(godotVariant, godotStr)
|
||||||
|
result = newVariant(self.godotDictionary[godotVariant])
|
||||||
|
godotStr.deinit()
|
||||||
|
godotVariant.deinit()
|
||||||
|
|
||||||
|
proc `[]=`*(self: Dictionary; key, value: Variant) {.inline.} =
|
||||||
|
self.godotDictionary[key.godotVariant[]] = value.godotVariant[]
|
||||||
|
|
||||||
|
proc `==`*(self, other: Dictionary): bool {.inline.} =
|
||||||
|
if self.isNil and other.isNil: return true
|
||||||
|
if self.isNil != other.isNil: return false
|
||||||
|
result = self.godotDictionary == other.godotDictionary
|
||||||
|
|
||||||
|
proc toJson*(self: Dictionary): string {.inline.} =
|
||||||
|
var s = self.godotDictionary.toJson()
|
||||||
|
result = $s
|
||||||
|
s.deinit()
|
||||||
|
|
||||||
|
iterator keys*(dict: Dictionary): Variant =
|
||||||
|
let keyArr = dict.keys()
|
||||||
|
for key in keyArr:
|
||||||
|
yield key
|
||||||
|
|
||||||
|
iterator values*(dict: Dictionary): Variant =
|
||||||
|
let valArr = dict.values()
|
||||||
|
for val in valArr:
|
||||||
|
yield val
|
||||||
|
|
||||||
|
iterator pairs*(dict: Dictionary): tuple[key, val: Variant] =
|
||||||
|
for key in keys(dict):
|
||||||
|
yield (key, dict[key])
|
||||||
|
|
||||||
|
proc `$`*(self: Dictionary): string =
|
||||||
|
result = newStringOfCap(32)
|
||||||
|
result.add('{')
|
||||||
|
for k, v in self:
|
||||||
|
if result.len > 1:
|
||||||
|
result.add(", ")
|
||||||
|
result.add($k)
|
||||||
|
result.add(": ")
|
||||||
|
result.add($v)
|
||||||
|
result.add('}')
|
||||||
64
godot/core/godotbase.nim
Normal file
64
godot/core/godotbase.nim
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
# Copyright (c) 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
import math, godotinternal
|
||||||
|
|
||||||
|
# math helpers
|
||||||
|
|
||||||
|
{.push stackTrace: off.}
|
||||||
|
const EPSILON = 0.00001'f32
|
||||||
|
proc isEqualApprox*(a, b: float32): bool {.inline, noinit.} =
|
||||||
|
abs(a - b) < EPSILON
|
||||||
|
|
||||||
|
proc isEqualApprox*(a, b: float64): bool {.inline, noinit.} =
|
||||||
|
abs(a - b) < EPSILON
|
||||||
|
|
||||||
|
proc sign*(a: float32): float32 {.inline, noinit.} =
|
||||||
|
if a < 0: -1.0'f32 else: 1.0'f32
|
||||||
|
|
||||||
|
proc sign*(a: float64): float64 {.inline, noinit.} =
|
||||||
|
if a < 0: -1.0'f64 else: 1.0'f64
|
||||||
|
|
||||||
|
proc stepify*(value, step: float64): float64 {.inline, noinit.} =
|
||||||
|
if step != 0'f64:
|
||||||
|
floor(value / step + 0.5'f64) * step
|
||||||
|
else:
|
||||||
|
value
|
||||||
|
|
||||||
|
proc stepify*(value, step: float32): float32 {.inline, noinit.} =
|
||||||
|
if step != 0'f32:
|
||||||
|
floor(value / step + 0.5'f32) * step
|
||||||
|
else:
|
||||||
|
value
|
||||||
|
|
||||||
|
when (NimMajor, NimMinor, NimPatch) < (0, 20, 4):
|
||||||
|
# Newer Nim has these procs in system module
|
||||||
|
|
||||||
|
proc min*(x, y: float32): float32 {.inline, noinit.} =
|
||||||
|
if x <= y: x else: y
|
||||||
|
|
||||||
|
proc abs*(x: float32): float32 {.inline, noinit.} =
|
||||||
|
if x < 0.0: -x else: x
|
||||||
|
|
||||||
|
proc max*(x, y: float32): float32 {.inline, noinit.} =
|
||||||
|
if y <= x: x else: y
|
||||||
|
|
||||||
|
{.pop.} # stackTrace: off
|
||||||
|
|
||||||
|
template printWarning*(warning: typed) =
|
||||||
|
## Prints ``warning`` to Godot log, adding filename and line information.
|
||||||
|
let instInfo = instantiationInfo()
|
||||||
|
godotPrintWarning(cstring($warning), cstring"", cstring(instInfo.filename), instInfo.line.cint)
|
||||||
|
|
||||||
|
template printError*(error: typed) =
|
||||||
|
## Prints ``error`` to Godot log, adding filename and line information.
|
||||||
|
let instInfo = instantiationInfo()
|
||||||
|
godotPrintError(cstring($error), cstring"", cstring(instInfo.filename), instInfo.line.cint)
|
||||||
|
|
||||||
|
proc print*(parts: varargs[string, `$`]) =
|
||||||
|
## Prints concatenated ``parts`` to Godot log.
|
||||||
|
var combined = ""
|
||||||
|
for v in parts:
|
||||||
|
combined.add(v)
|
||||||
|
var s = combined.toGodotString()
|
||||||
|
godotPrint(s)
|
||||||
|
s.deinit()
|
||||||
102
godot/core/godotcoretypes.nim
Normal file
102
godot/core/godotcoretypes.nim
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
# Copyright 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
type
|
||||||
|
Color* {.byref.} = object
|
||||||
|
r*: float32
|
||||||
|
g*: float32
|
||||||
|
b*: float32
|
||||||
|
a*: float32
|
||||||
|
|
||||||
|
Vector3* {.byref.} = object
|
||||||
|
x*: float32
|
||||||
|
y*: float32
|
||||||
|
z*: float32
|
||||||
|
|
||||||
|
Vector2* {.byref.} = object
|
||||||
|
x*: float32
|
||||||
|
y*: float32
|
||||||
|
|
||||||
|
Plane* {.byref.} = object
|
||||||
|
normal*: Vector3
|
||||||
|
d*: float32
|
||||||
|
|
||||||
|
Basis* {.byref.} = object
|
||||||
|
elements*: array[3, Vector3]
|
||||||
|
|
||||||
|
Quat* {.byref.} = object
|
||||||
|
x*: float32
|
||||||
|
y*: float32
|
||||||
|
z*: float32
|
||||||
|
w*: float32
|
||||||
|
|
||||||
|
AABB* {.byref.} = object
|
||||||
|
position*: Vector3
|
||||||
|
size*: Vector3
|
||||||
|
|
||||||
|
Rect2* {.byref.} = object
|
||||||
|
position*: Vector2
|
||||||
|
size*: Vector2
|
||||||
|
|
||||||
|
Transform2D* {.byref.} = object
|
||||||
|
elements*: array[3, Vector2]
|
||||||
|
|
||||||
|
Transform* {.byref.} = object
|
||||||
|
basis*: Basis
|
||||||
|
origin*: Vector3
|
||||||
|
|
||||||
|
RID* {.byref.} = object
|
||||||
|
data: array[sizeof(int), byte]
|
||||||
|
|
||||||
|
Error* {.size: sizeof(cint), pure.} = enum
|
||||||
|
OK,
|
||||||
|
Failed, ## Generic fail error
|
||||||
|
Unavailable, ## What is requested is unsupported/unavailable
|
||||||
|
Unconfigured, ## The object being used hasnt been properly set up yet
|
||||||
|
Unauthorized, ## Missing credentials for requested resource
|
||||||
|
ParameterRangeError, ## Parameter given out of range (5)
|
||||||
|
OutOfMemory, ## Out of memory
|
||||||
|
FileNotFound,
|
||||||
|
FileBadDrive,
|
||||||
|
FileBadPath,
|
||||||
|
FileNoPermission, ## (10)
|
||||||
|
FileAlreadyInUse,
|
||||||
|
FileCantOpen,
|
||||||
|
FileCantWrite,
|
||||||
|
FileCantRead,
|
||||||
|
FileUnrecognized, ## (15)
|
||||||
|
FileCorrupt,
|
||||||
|
FileMissingDependencies,
|
||||||
|
FileEOF,
|
||||||
|
CantOpen, ## Can't open a resource/socket/file
|
||||||
|
CantCreate, ## (20)
|
||||||
|
QueryFailed,
|
||||||
|
AlreadyInUse,
|
||||||
|
Locked, ## resource is locked
|
||||||
|
Timeout,
|
||||||
|
CantConnect, ## (25)
|
||||||
|
CantResolve,
|
||||||
|
ConnectionError,
|
||||||
|
CantAquireResource,
|
||||||
|
CantFork,
|
||||||
|
InvalidData, ## Data passed is invalid (30)
|
||||||
|
InvalidParameter, ## Parameter passed is invalid
|
||||||
|
AlreadyExists, ## When adding, item already exists
|
||||||
|
DoesNotExist, ## When retrieving/erasing, it item does not exist
|
||||||
|
DatabaseCantRead, ## Database is full
|
||||||
|
DatabaseCantWrite, ## Database is full (35)
|
||||||
|
CompilationFailed,
|
||||||
|
MethodNotFound,
|
||||||
|
LinkFailed,
|
||||||
|
ScriptFailed,
|
||||||
|
CyclicLink, ## (40)
|
||||||
|
InvalidDeclaration,
|
||||||
|
DuplicateSymbol,
|
||||||
|
PauseError,
|
||||||
|
Busy,
|
||||||
|
Skip, ## (45)
|
||||||
|
Help, ## user requested help!!
|
||||||
|
Bug,
|
||||||
|
## a bug in the software certainly happened, due to a double
|
||||||
|
## check failing or unexpected behavior.
|
||||||
|
PrinterOnFire, ## the parallel port printer is engulfed in flames
|
||||||
|
WTF ## shit happens, has never been used, though
|
||||||
1
godot/core/nim.cfg
Normal file
1
godot/core/nim.cfg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
--path:"$projectdir/../"
|
||||||
73
godot/core/nodepaths.nim
Normal file
73
godot/core/nodepaths.nim
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
# Copyright 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
import hashes
|
||||||
|
|
||||||
|
import internal/godotinternaltypes, internal/godotnodepaths,
|
||||||
|
internal/godotstrings
|
||||||
|
|
||||||
|
type
|
||||||
|
NodePath* = ref object
|
||||||
|
path: GodotNodePath
|
||||||
|
|
||||||
|
proc nodePathFinalizer(path: NodePath) =
|
||||||
|
path.path.deinit()
|
||||||
|
|
||||||
|
proc newNodePath*(path: GodotNodePath): NodePath =
|
||||||
|
## Moves the GodotNodePath into Nim wrapper. The ``path`` will be destroyed
|
||||||
|
## automatically when the result is no longer referenced.
|
||||||
|
new(result, nodePathFinalizer)
|
||||||
|
result.path = path
|
||||||
|
|
||||||
|
proc newNodePath*(s: string): NodePath =
|
||||||
|
new(result, nodePathFinalizer)
|
||||||
|
var str = s.toGodotString()
|
||||||
|
initGodotNodePath(result.path, str)
|
||||||
|
str.deinit()
|
||||||
|
|
||||||
|
proc godotNodePath*(path: NodePath): ptr GodotNodePath {.inline.} =
|
||||||
|
## WARNING: do not keep the returned value for longer than the lifetime of
|
||||||
|
## ``path``
|
||||||
|
result = addr path.path
|
||||||
|
|
||||||
|
proc `$`*(self: NodePath): string {.inline.} =
|
||||||
|
var s = self.path.toGodotString()
|
||||||
|
result = $s
|
||||||
|
s.deinit()
|
||||||
|
|
||||||
|
proc hash*(self: NodePath): Hash {.inline.} =
|
||||||
|
($self).hash()
|
||||||
|
|
||||||
|
proc isAbsolute*(self: NodePath): bool {.inline.} =
|
||||||
|
self.path.isAbsolute()
|
||||||
|
|
||||||
|
proc nameCount*(self: NodePath): int {.inline.} =
|
||||||
|
int(self.path.nameCount())
|
||||||
|
|
||||||
|
proc getName*(self: NodePath; idx: int): string {.inline.} =
|
||||||
|
var s = self.path.getName(idx.cint)
|
||||||
|
result = $s
|
||||||
|
s.deinit()
|
||||||
|
|
||||||
|
proc subnameCount*(self: NodePath): int {.inline.} =
|
||||||
|
int(self.path.subnameCount())
|
||||||
|
|
||||||
|
proc getSubname*(self: NodePath; idx: int): string {.inline.} =
|
||||||
|
var s = self.path.getSubname(idx.cint)
|
||||||
|
result = $s
|
||||||
|
s.deinit()
|
||||||
|
|
||||||
|
proc getConcatenatedSubnames*(self: NodePath): string {.inline.} =
|
||||||
|
var s = self.path.getConcatenatedSubnames()
|
||||||
|
result = $s
|
||||||
|
s.deinit()
|
||||||
|
|
||||||
|
proc isEmpty*(self: NodePath): bool {.inline.} =
|
||||||
|
self.path.isEmpty()
|
||||||
|
|
||||||
|
proc `==`*(a, b: NodePath): bool =
|
||||||
|
if a.isNil and b.isNil: return true
|
||||||
|
if a.isNil != b.isNil: return false
|
||||||
|
result = a.path == b.path
|
||||||
|
|
||||||
|
converter fromString*(s: string): NodePath =
|
||||||
|
newNodePath(s)
|
||||||
66
godot/core/planes.nim
Normal file
66
godot/core/planes.nim
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
# Copyright (c) 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
import hashes
|
||||||
|
|
||||||
|
import vector3
|
||||||
|
|
||||||
|
import internal/godotinternaltypes, internal/godotstrings
|
||||||
|
import godotcoretypes, gdnativeapi
|
||||||
|
|
||||||
|
proc initPlane*(a, b, c, d: float32): Plane {.inline.} =
|
||||||
|
getGDNativeAPI().planeNewWithReals(result, a, b, c, d)
|
||||||
|
|
||||||
|
proc initPlane*(v1, v2, v3: Vector3): Plane {.inline.} =
|
||||||
|
getGDNativeAPI().planeNewWithVectors(result, v1, v2, v3)
|
||||||
|
|
||||||
|
proc initPlane*(normal: Vector3; d: float32): Plane {.inline.} =
|
||||||
|
result = Plane(
|
||||||
|
normal: normal,
|
||||||
|
d: d
|
||||||
|
)
|
||||||
|
|
||||||
|
proc `$`*(self: Plane): string {.inline.} =
|
||||||
|
$getGDNativeAPI().planeAsString(self)
|
||||||
|
|
||||||
|
proc hash*(self: Plane): Hash {.inline, noinit.} =
|
||||||
|
!$(self.normal.hash() !& self.d.hash())
|
||||||
|
|
||||||
|
proc normalized*(self: Plane): Plane {.inline.} =
|
||||||
|
getGDNativeAPI().planeNormalized(self).toPlane()
|
||||||
|
|
||||||
|
proc center*(self: Plane): Vector3 {.inline.} =
|
||||||
|
getGDNativeAPI().planeCenter(self).toVector3()
|
||||||
|
|
||||||
|
proc getAnyPoint*(self: Plane): Vector3 {.inline.} =
|
||||||
|
getGDNativeAPI().planeGetAnyPoint(self).toVector3()
|
||||||
|
|
||||||
|
proc isPointOver*(self: Plane; point: Vector3): bool {.inline.} =
|
||||||
|
getGDNativeAPI().planeIsPointOver(self, point)
|
||||||
|
|
||||||
|
proc distanceTo*(self: Plane; point: Vector3): float32 {.inline.} =
|
||||||
|
getGDNativeAPI().planeDistanceTo(self, point)
|
||||||
|
|
||||||
|
proc contains*(self: Plane; point: Vector3;
|
||||||
|
epsilon: float32): bool {.inline.} =
|
||||||
|
getGDNativeAPI().planeHasPoint(self, point, epsilon)
|
||||||
|
|
||||||
|
proc project*(self: Plane; point: Vector3): Vector3 {.inline.} =
|
||||||
|
getGDNativeAPI().planeProject(self, point).toVector3()
|
||||||
|
|
||||||
|
proc intersect3*(self: Plane; dest: var Vector3;
|
||||||
|
b, c: Plane): bool {.inline.} =
|
||||||
|
getGDNativeAPI().planeIntersect3(self, dest, b, c)
|
||||||
|
|
||||||
|
proc intersectsRay*(self: Plane; dest: var Vector3;
|
||||||
|
v, dir: Vector3): bool {.inline.} =
|
||||||
|
getGDNativeAPI().planeIntersectsRay(self, dest, v, dir)
|
||||||
|
|
||||||
|
proc intersectsSegment*(self: Plane; dest: var Vector3;
|
||||||
|
segmentBegin, segmentEnd: Vector3): bool {.inline.} =
|
||||||
|
getGDNativeAPI().planeIntersectsSegment(self, dest, segmentBegin, segmentEnd)
|
||||||
|
|
||||||
|
proc `-`*(self: Plane): Plane {.inline.} =
|
||||||
|
getGDNativeAPI().planeOperatorNeg(self).toPlane()
|
||||||
|
|
||||||
|
proc `==`*(a, b: Plane): bool {.inline.} =
|
||||||
|
getGDNativeAPI().planeOperatorEqual(a, b)
|
||||||
167
godot/core/poolarrays.nim
Normal file
167
godot/core/poolarrays.nim
Normal file
|
|
@ -0,0 +1,167 @@
|
||||||
|
# Copyright 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
import hashes
|
||||||
|
|
||||||
|
import godotcoretypes
|
||||||
|
import internal/godotinternaltypes, internal/godotpoolarrays,
|
||||||
|
internal/godotstrings
|
||||||
|
import vector2, vector3, colors
|
||||||
|
|
||||||
|
template definePoolArrayBase(T, GodotT, DataT, fieldName, newProcName,
|
||||||
|
initProcName) =
|
||||||
|
type
|
||||||
|
T* = ref object
|
||||||
|
fieldName: GodotT
|
||||||
|
|
||||||
|
proc poolArrayFinalizer(arr: T) =
|
||||||
|
arr.fieldName.deinit()
|
||||||
|
|
||||||
|
proc newProcName*(): T {.inline.} =
|
||||||
|
new(result, poolArrayFinalizer)
|
||||||
|
initProcName(result.fieldName)
|
||||||
|
|
||||||
|
proc fieldName*(self: T): ptr GodotT {.inline.} =
|
||||||
|
## WARNING: do not keep the returned value for longer than the lifetime of
|
||||||
|
## the array.
|
||||||
|
addr self.fieldName
|
||||||
|
|
||||||
|
proc newProcName*(arr: GodotT): T {.inline.} =
|
||||||
|
new(result, poolArrayFinalizer)
|
||||||
|
result.fieldName = arr
|
||||||
|
|
||||||
|
proc hash*(arr: T): Hash =
|
||||||
|
for item in arr.fieldName.items():
|
||||||
|
result = result !&
|
||||||
|
(when type(item) is GodotString: ($item).hash() else: item.hash())
|
||||||
|
result = !$result
|
||||||
|
|
||||||
|
definePoolArrayBase(PoolByteArray, GodotPoolByteArray, uint8,
|
||||||
|
godotPoolByteArray, newPoolByteArray,
|
||||||
|
initGodotPoolByteArray)
|
||||||
|
definePoolArrayBase(PoolIntArray, GodotPoolIntArray, cint,
|
||||||
|
godotPoolIntArray, newPoolIntArray,
|
||||||
|
initGodotPoolIntArray)
|
||||||
|
definePoolArrayBase(PoolRealArray, GodotPoolRealArray, float32,
|
||||||
|
godotPoolRealArray, newPoolRealArray,
|
||||||
|
initGodotPoolRealArray)
|
||||||
|
definePoolArrayBase(PoolVector2Array, GodotPoolVector2Array, Vector2,
|
||||||
|
godotPoolVector2Array, newPoolVector2Array,
|
||||||
|
initGodotPoolVector2Array)
|
||||||
|
definePoolArrayBase(PoolVector3Array, GodotPoolVector3Array, Vector3,
|
||||||
|
godotPoolVector3Array, newPoolVector3Array,
|
||||||
|
initGodotPoolVector3Array)
|
||||||
|
definePoolArrayBase(PoolColorArray, GodotPoolColorArray, Color,
|
||||||
|
godotPoolColorArray, newPoolColorArray,
|
||||||
|
initGodotPoolColorArray)
|
||||||
|
definePoolArrayBase(PoolStringArray, GodotPoolStringArray, string,
|
||||||
|
godotPoolStringArray, newPoolStringArray,
|
||||||
|
initGodotPoolStringArray)
|
||||||
|
|
||||||
|
import arrays
|
||||||
|
|
||||||
|
template definePoolArray(T, GodotT, DataT, fieldName, newProcName, initProcName;
|
||||||
|
noData = false) =
|
||||||
|
|
||||||
|
proc newProcName*(arr: Array): T {.inline.} =
|
||||||
|
new(result, poolArrayFinalizer)
|
||||||
|
initProcName(result.fieldName, arr.godotArray[])
|
||||||
|
|
||||||
|
proc add*(self: T; arr: T) {.inline.} =
|
||||||
|
self.fieldName.add(arr.fieldName)
|
||||||
|
|
||||||
|
proc delete*(self: T; idx: int) {.inline.} =
|
||||||
|
self.fieldName.delete(idx.cint)
|
||||||
|
|
||||||
|
proc reverse*(self: T) {.inline.} =
|
||||||
|
self.fieldName.reverse()
|
||||||
|
|
||||||
|
proc setLen*(self: T; size: int) {.inline.} =
|
||||||
|
self.fieldName.setLen(size.cint)
|
||||||
|
|
||||||
|
proc len*(self: T): int {.inline.} =
|
||||||
|
self.fieldName.len.int
|
||||||
|
|
||||||
|
proc subarray*(self: T, idxFrom, idxTo: int): T {.inline.} =
|
||||||
|
## Indexes are inclusive, negative values count from the end of the array.
|
||||||
|
assert(idxFrom >= low(cint) and idxFrom <= high(cint) and
|
||||||
|
idxTo >= low(cint) and idxTo <= high(cint))
|
||||||
|
newProcName(self.fieldName.subarray(idxFrom.cint, idxTo.cint))
|
||||||
|
|
||||||
|
when not noData:
|
||||||
|
proc add*(self: T; data: DataT) {.inline.} =
|
||||||
|
self.fieldName.add(data)
|
||||||
|
|
||||||
|
proc insert*(self: T; idx: int; data: DataT): Error {.inline.} =
|
||||||
|
self.fieldName.insert(idx.cint, data)
|
||||||
|
|
||||||
|
proc `[]=`*(self: T; idx: int; data: DataT) {.inline.} =
|
||||||
|
self.fieldName[idx.cint] = data
|
||||||
|
|
||||||
|
proc `[]`*(self: T; idx: int): DataT {.inline.} =
|
||||||
|
self.fieldName[idx.cint]
|
||||||
|
|
||||||
|
iterator items*(arr: T): DataT =
|
||||||
|
for item in arr.fieldName.items:
|
||||||
|
yield item
|
||||||
|
|
||||||
|
iterator pairs*(arr: T): tuple[key: int, val: DataT] =
|
||||||
|
for pair in arr.fieldName.pairs:
|
||||||
|
yield (pair[0].int, pair[1])
|
||||||
|
|
||||||
|
iterator mitems*(arr: T): var DataT =
|
||||||
|
for item in arr.fieldName.mitems:
|
||||||
|
yield item
|
||||||
|
|
||||||
|
iterator mpairs*(arr: T): tuple[key: int, val: var DataT] =
|
||||||
|
for pair in arr.fieldName.mpairs:
|
||||||
|
yield (pair[0].int, pair[1])
|
||||||
|
|
||||||
|
definePoolArray(PoolByteArray, GodotPoolByteArray, uint8,
|
||||||
|
godotPoolByteArray, newPoolByteArray,
|
||||||
|
initGodotPoolByteArray)
|
||||||
|
definePoolArray(PoolIntArray, GodotPoolIntArray, cint,
|
||||||
|
godotPoolIntArray, newPoolIntArray,
|
||||||
|
initGodotPoolIntArray)
|
||||||
|
definePoolArray(PoolRealArray, GodotPoolRealArray, float32,
|
||||||
|
godotPoolRealArray, newPoolRealArray,
|
||||||
|
initGodotPoolRealArray)
|
||||||
|
definePoolArray(PoolVector2Array, GodotPoolVector2Array, Vector2,
|
||||||
|
godotPoolVector2Array, newPoolVector2Array,
|
||||||
|
initGodotPoolVector2Array)
|
||||||
|
definePoolArray(PoolVector3Array, GodotPoolVector3Array, Vector3,
|
||||||
|
godotPoolVector3Array, newPoolVector3Array,
|
||||||
|
initGodotPoolVector3Array)
|
||||||
|
definePoolArray(PoolColorArray, GodotPoolColorArray, Color,
|
||||||
|
godotPoolColorArray, newPoolColorArray,
|
||||||
|
initGodotPoolColorArray)
|
||||||
|
definePoolArray(PoolStringArray, GodotPoolStringArray, string,
|
||||||
|
godotPoolStringArray, newPoolStringArray,
|
||||||
|
initGodotPoolStringArray, true)
|
||||||
|
|
||||||
|
proc add*(self: PoolStringArray; data: string) =
|
||||||
|
var s = data.toGodotString()
|
||||||
|
self.godotPoolStringArray.add(s)
|
||||||
|
s.deinit()
|
||||||
|
|
||||||
|
proc insert*(self: PoolStringArray; idx: int; data: string): Error =
|
||||||
|
var s = data.toGodotString()
|
||||||
|
result = self.godotPoolStringArray.insert(idx.cint, s)
|
||||||
|
s.deinit()
|
||||||
|
|
||||||
|
proc `[]=`*(self: PoolStringArray; idx: int; data: string) =
|
||||||
|
var s = data.toGodotString()
|
||||||
|
self.godotPoolStringArray[idx.cint] = s
|
||||||
|
s.deinit()
|
||||||
|
|
||||||
|
proc `[]`*(self: PoolStringArray; idx: int): string =
|
||||||
|
var s = self.godotPoolStringArray[idx.cint]
|
||||||
|
result = $s
|
||||||
|
s.deinit()
|
||||||
|
|
||||||
|
iterator items*(arr: PoolStringArray): string =
|
||||||
|
for i in 0..<arr.len:
|
||||||
|
yield arr[i]
|
||||||
|
|
||||||
|
iterator pairs*(arr: PoolStringArray): tuple[key: int, val: string] =
|
||||||
|
for i in 0..<arr.len:
|
||||||
|
yield (i, arr[i])
|
||||||
84
godot/core/quats.nim
Normal file
84
godot/core/quats.nim
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
# Copyright (c) 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
import hashes
|
||||||
|
|
||||||
|
import internal/godotinternaltypes, internal/godotstrings
|
||||||
|
import godotcoretypes, gdnativeapi
|
||||||
|
|
||||||
|
proc initQuat*(x, y, z, w: float32): Quat {.inline.} =
|
||||||
|
result = Quat(
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
z: z,
|
||||||
|
w: w
|
||||||
|
)
|
||||||
|
|
||||||
|
proc initQuat*(axis: Vector3; angle: float32): Quat {.inline.} =
|
||||||
|
getGDNativeAPI().quatNewWithAxisAngle(result, axis, angle)
|
||||||
|
|
||||||
|
proc `$`*(self: Quat): string {.inline.} =
|
||||||
|
$getGDNativeAPI().quatAsString(self)
|
||||||
|
|
||||||
|
proc hash*(self: Quat): Hash {.inline.} =
|
||||||
|
!$(self.x.hash() !& self.y.hash() !& self.z.hash() !& self.w.hash())
|
||||||
|
|
||||||
|
proc length*(self: Quat): float32 {.inline.} =
|
||||||
|
getGDNativeAPI().quatLength(self)
|
||||||
|
|
||||||
|
proc lengthSquared*(self: Quat): float32 {.inline.} =
|
||||||
|
getGDNativeAPI().quatLengthSquared(self)
|
||||||
|
|
||||||
|
proc normalized*(self: Quat): Quat {.inline.} =
|
||||||
|
getGDNativeAPI().quatNormalized(self).toQuat()
|
||||||
|
|
||||||
|
proc isNormalized*(self: Quat): bool {.inline.} =
|
||||||
|
getGDNativeAPI().quatIsNormalized(self)
|
||||||
|
|
||||||
|
proc inverse*(self: Quat): Quat {.inline.} =
|
||||||
|
getGDNativeAPI().quatInverse(self).toQuat()
|
||||||
|
|
||||||
|
proc dot*(a, b: Quat): float32 {.inline.} =
|
||||||
|
getGDNativeAPI().quatDot(a, b)
|
||||||
|
|
||||||
|
proc xform*(self: Quat; v: Vector3): Vector3 {.inline.} =
|
||||||
|
getGDNativeAPI().quatXform(self, v).toVector3()
|
||||||
|
|
||||||
|
proc slerp*(self: Quat; b: Quat; t: float32): Quat {.inline.} =
|
||||||
|
getGDNativeAPI().quatSlerp(self, b, t).toQuat()
|
||||||
|
|
||||||
|
proc slerpni*(self: Quat; b: Quat; t: float32): Quat {.inline.} =
|
||||||
|
getGDNativeAPI().quatSlerpni(self, b, t).toQuat()
|
||||||
|
|
||||||
|
proc cubicSlerp*(self, b, preA, postB: Quat;
|
||||||
|
t: float32): Quat {.inline.} =
|
||||||
|
getGDNativeAPI().quatCubicSlerp(self, b, preA, postB, t).toQuat()
|
||||||
|
|
||||||
|
proc `*`*(a: Quat, b: float32): Quat {.inline.} =
|
||||||
|
getGDNativeAPI().quatOperatorMultiply(a, b).toQuat()
|
||||||
|
|
||||||
|
proc `*=`*(a: var Quat, b: float32) {.inline.} =
|
||||||
|
a = a * b
|
||||||
|
|
||||||
|
proc `+`*(a, b: Quat): Quat {.inline.} =
|
||||||
|
getGDNativeAPI().quatOperatorAdd(a, b).toQuat()
|
||||||
|
|
||||||
|
proc `+=`*(a: var Quat, b: Quat) {.inline.} =
|
||||||
|
a = a + b
|
||||||
|
|
||||||
|
proc `-`*(a, b: Quat): Quat {.inline.} =
|
||||||
|
getGDNativeAPI().quatOperatorSubtract(a, b).toQuat()
|
||||||
|
|
||||||
|
proc `-=`* (a: var Quat, b: Quat) {.inline.} =
|
||||||
|
a = a - b
|
||||||
|
|
||||||
|
proc `/`*(self: Quat; b: float32): Quat {.inline.} =
|
||||||
|
getGDNativeAPI().quatOperatorDivide(self, b).toQuat()
|
||||||
|
|
||||||
|
proc `/=`*(self: var Quat, b: float32) {.inline.} =
|
||||||
|
self = self / b
|
||||||
|
|
||||||
|
proc `==`*(a, b: Quat): bool {.inline.} =
|
||||||
|
getGDNativeAPI().quatOperatorEqual(a, b)
|
||||||
|
|
||||||
|
proc `-`*(self: Quat): Quat {.inline.} =
|
||||||
|
getGDNativeAPI().quatOperatorNeg(self).toQuat()
|
||||||
153
godot/core/rect2.nim
Normal file
153
godot/core/rect2.nim
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
# Copyright (c) 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
import hashes
|
||||||
|
|
||||||
|
import vector2
|
||||||
|
import internal/godotinternaltypes, internal/godotstrings
|
||||||
|
import godotcoretypes, gdnativeapi
|
||||||
|
|
||||||
|
{.push stackTrace: off.}
|
||||||
|
|
||||||
|
proc initRect2*(): Rect2 {.inline, noinit.} =
|
||||||
|
Rect2()
|
||||||
|
|
||||||
|
proc initRect2*(pos, size: Vector2): Rect2 {.inline, noinit.} =
|
||||||
|
Rect2(position: pos, size: size)
|
||||||
|
|
||||||
|
proc initRect2*(x, y, sizeX, sizeY: float32): Rect2 {.inline, noinit.} =
|
||||||
|
Rect2(position: vec2(x, y), size: vec2(sizeX, sizeY))
|
||||||
|
|
||||||
|
proc `$`*(self: Rect2): string {.inline, noinit.} =
|
||||||
|
$getGDNativeAPI().rect2AsString(self)
|
||||||
|
|
||||||
|
proc hash*(self: Rect2): Hash {.inline, noinit.} =
|
||||||
|
!$(self.position.hash() !& self.size.hash())
|
||||||
|
|
||||||
|
proc area*(self: Rect2): float32 {.inline, noinit.} =
|
||||||
|
self.size.x * self.size.y
|
||||||
|
|
||||||
|
proc intersects*(a, b: Rect2): bool {.inline, noinit.} =
|
||||||
|
if a.position.x >= (b.position.x + b.size.x):
|
||||||
|
return false
|
||||||
|
if a.position.x + a.size.x <= b.position.x:
|
||||||
|
return false
|
||||||
|
if a.position.y >= (b.position.y + b.size.y):
|
||||||
|
return false
|
||||||
|
if a.position.y + a.size.y <= b.position.y:
|
||||||
|
return false
|
||||||
|
result = true
|
||||||
|
|
||||||
|
proc distanceTo*(self: Rect2, p: Vector2): float32 {.noinit.} =
|
||||||
|
var inside = true
|
||||||
|
if p.x < self.position.x:
|
||||||
|
let d = self.position.x - p.x
|
||||||
|
result = d
|
||||||
|
inside = false
|
||||||
|
if p.y < self.position.y:
|
||||||
|
let d = self.position.y - p.y
|
||||||
|
result = if inside: d else: min(result, d)
|
||||||
|
inside = false
|
||||||
|
if p.x >= (self.position.x + self.size.x):
|
||||||
|
let d = p.x - (self.position.x + self.size.x)
|
||||||
|
result = if inside: d else: min(result, d)
|
||||||
|
inside = false
|
||||||
|
if p.y >= (self.position.y + self.size.y):
|
||||||
|
let d = p.y - (self.position.y + self.size.y)
|
||||||
|
result = if inside: d else: min(result, d)
|
||||||
|
inside = false
|
||||||
|
|
||||||
|
if inside:
|
||||||
|
result = 0'f32
|
||||||
|
|
||||||
|
proc encloses*(a, b: Rect2): bool {.inline, noinit.} =
|
||||||
|
b.position.x >= a.position.x and b.position.y >= a.position.y and
|
||||||
|
(b.position.x + b.size.x) < (a.position.x + a.size.x) and
|
||||||
|
(b.position.y + b.size.y) < (a.position.y + a.size.y)
|
||||||
|
|
||||||
|
proc hasNoArea*(self: Rect2): bool {.inline, noinit.} =
|
||||||
|
self.size.x <= 0 or self.size.y <= 0
|
||||||
|
|
||||||
|
proc clip*(self, b: Rect2): Rect2 {.inline, noinit.} =
|
||||||
|
if not self.intersects(b):
|
||||||
|
return initRect2()
|
||||||
|
|
||||||
|
result = self
|
||||||
|
|
||||||
|
result.position.x = max(b.position.x, self.position.x)
|
||||||
|
result.position.y = max(b.position.y, self.position.y)
|
||||||
|
|
||||||
|
let bEnd = b.position + b.size
|
||||||
|
let selfEnd = self.position + self.size
|
||||||
|
|
||||||
|
result.size.x = min(bEnd.x, selfEnd.x) - result.position.x
|
||||||
|
result.size.y = min(bEnd.y, selfEnd.y) - result.position.y
|
||||||
|
|
||||||
|
proc merge*(self, b: Rect2): Rect2 {.inline, noinit.} =
|
||||||
|
result.position.x = min(b.position.x, self.position.x)
|
||||||
|
result.position.y = min(b.position.y, self.position.y)
|
||||||
|
|
||||||
|
result.size.x = max(b.position.x + b.size.x, self.position.x + self.size.x)
|
||||||
|
result.size.y = max(b.position.y + b.size.y, self.position.y + self.size.y)
|
||||||
|
result.size -= result.position
|
||||||
|
|
||||||
|
proc contains*(self: Rect2; point: Vector2): bool {.inline, noinit.} =
|
||||||
|
if point.x < self.position.x:
|
||||||
|
return false
|
||||||
|
if point.y < self.position.y:
|
||||||
|
return false
|
||||||
|
|
||||||
|
if point.x >= self.position.x + self.size.x:
|
||||||
|
return false
|
||||||
|
if point.y >= self.position.y + self.size.y:
|
||||||
|
return false
|
||||||
|
|
||||||
|
result = true
|
||||||
|
|
||||||
|
proc grow*(self: Rect2; by: float32): Rect2 {.inline, noinit.} =
|
||||||
|
## Returns Rect2 enlarged by the specified size in every direction.
|
||||||
|
result = self
|
||||||
|
|
||||||
|
result.position.x -= by
|
||||||
|
result.position.y -= by
|
||||||
|
|
||||||
|
result.size.x += by * 2
|
||||||
|
result.size.y += by * 2
|
||||||
|
|
||||||
|
proc growIndividual*(self: Rect2, left, top: float32,
|
||||||
|
right, bottom: float32): Rect2 {.inline, noinit.} =
|
||||||
|
result = self
|
||||||
|
result.position.x -= left
|
||||||
|
result.position.y -= top
|
||||||
|
result.size.x += left + right
|
||||||
|
result.size.y += top + bottom
|
||||||
|
|
||||||
|
proc expandTo*(self: var Rect2, to: Vector2) {.inline.} =
|
||||||
|
var startPoint = self.position
|
||||||
|
var endPoint = self.position + self.size
|
||||||
|
|
||||||
|
if to.x < startPoint.x:
|
||||||
|
startPoint.x = to.x
|
||||||
|
if to.y < startPoint.y:
|
||||||
|
startPoint.y = to.y
|
||||||
|
|
||||||
|
if to.x > endPoint.x:
|
||||||
|
endPoint.x = to.x
|
||||||
|
if to.y > endPoint.y:
|
||||||
|
endPoint.y = to.y
|
||||||
|
|
||||||
|
self.position = startPoint
|
||||||
|
self.size = endPoint - startPoint
|
||||||
|
|
||||||
|
proc expand*(self: Rect2; to: Vector2): Rect2 {.inline, noinit.} =
|
||||||
|
result = self
|
||||||
|
result.expandTo(to)
|
||||||
|
|
||||||
|
proc abs*(self: Rect2): Rect2 {.inline, noinit.} =
|
||||||
|
Rect2(position: vec2(self.position.x + min(self.size.x, 0'f32),
|
||||||
|
self.position.y + min(self.size.y, 0'f32)),
|
||||||
|
size: abs(self.size))
|
||||||
|
|
||||||
|
proc `==`*(a, b: Rect2): bool {.inline, noinit.} =
|
||||||
|
a.position == b.position and a.size == b.size
|
||||||
|
|
||||||
|
{.pop.} # stackTrace: off
|
||||||
26
godot/core/rids.nim
Normal file
26
godot/core/rids.nim
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
# Copyright (c) 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
import hashes
|
||||||
|
|
||||||
|
import godotcoretypes, internal/godotinternaltypes, gdnativeapi
|
||||||
|
|
||||||
|
proc initRID*(): RID {.inline.} =
|
||||||
|
getGDNativeAPI().ridNew(result)
|
||||||
|
|
||||||
|
proc initRID*(obj: ptr GodotObject): RID {.inline.} =
|
||||||
|
getGDNativeAPI().ridNewWithResource(result, obj)
|
||||||
|
|
||||||
|
proc id*(self: RID): uint32 {.inline.} =
|
||||||
|
cast[uint32](getGDNativeAPI().ridGetId(self))
|
||||||
|
|
||||||
|
proc `$`*(self: RID): string {.inline.} =
|
||||||
|
$self.id
|
||||||
|
|
||||||
|
proc hash*(self: RID): Hash {.inline.} =
|
||||||
|
self.id.hash()
|
||||||
|
|
||||||
|
proc `==`*(a, b: RID): bool {.inline.} =
|
||||||
|
getGDNativeAPI().ridOperatorEqual(a, b)
|
||||||
|
|
||||||
|
proc `<`*(a, b: RID): bool {.inline.} =
|
||||||
|
getGDNativeAPI().ridOperatorLess(a, b)
|
||||||
79
godot/core/transform2d.nim
Normal file
79
godot/core/transform2d.nim
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
# Copyright (c) 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
import hashes, vector2
|
||||||
|
|
||||||
|
import internal/godotinternaltypes, internal/godotstrings
|
||||||
|
import godotcoretypes, gdnativeapi
|
||||||
|
|
||||||
|
proc initTransform2D*(): Transform2D {.inline.} =
|
||||||
|
getGDNativeAPI().transform2DNewIdentity(result)
|
||||||
|
|
||||||
|
proc initTransform2D*(rot: float32; pos: Vector2): Transform2D {.inline.} =
|
||||||
|
getGDNativeAPI().transform2DNew(result, rot, pos)
|
||||||
|
|
||||||
|
proc initTransform2D*(xAxis, yAxis, origin: Vector2): Transform2D {.inline.} =
|
||||||
|
getGDNativeAPI().transform2DNewAxisOrigin(result, xAxis, yAxis, origin)
|
||||||
|
|
||||||
|
proc `$`*(self: Transform2D): string {.inline.} =
|
||||||
|
$getGDNativeAPI().transform2DAsString(self)
|
||||||
|
|
||||||
|
proc hash*(self: Transform2D): Hash {.inline, noinit.} =
|
||||||
|
!$(self.elements[0].hash() !& self.elements[1].hash() !& self.elements[2].hash())
|
||||||
|
|
||||||
|
proc inverse*(self: Transform2D): Transform2D {.inline.} =
|
||||||
|
getGDNativeAPI().transform2DInverse(self).toTransform2D()
|
||||||
|
|
||||||
|
proc affineInverse*(self: Transform2D): Transform2D {.inline.} =
|
||||||
|
getGDNativeAPI().transform2DAffineInverse(self).toTransform2D()
|
||||||
|
|
||||||
|
proc rotation*(self: Transform2D): float32 {.inline.} =
|
||||||
|
getGDNativeAPI().transform2DGetRotation(self)
|
||||||
|
|
||||||
|
proc origin*(self: Transform2D): Vector2 {.inline.} =
|
||||||
|
getGDNativeAPI().transform2DGetOrigin(self).toVector2()
|
||||||
|
|
||||||
|
proc scale*(self: Transform2D): Vector2 {.inline.} =
|
||||||
|
getGDNativeAPI().transform2DGetScale(self).toVector2()
|
||||||
|
|
||||||
|
proc orthonormalized*(self: Transform2D): Transform2D {.inline.} =
|
||||||
|
getGDNativeAPI().transform2DOrthonormalized(self).toTransform2D()
|
||||||
|
|
||||||
|
proc rotated*(self: Transform2D; phi: float32): Transform2D {.inline.} =
|
||||||
|
getGDNativeAPI().transform2DRotated(self, phi).toTransform2D()
|
||||||
|
|
||||||
|
proc scaled*(self: Transform2D; scale: Vector2): Transform2D {.inline.} =
|
||||||
|
getGDNativeAPI().transform2DScaled(self, scale).toTransform2D()
|
||||||
|
|
||||||
|
proc translated*(self: Transform2D; offset: Vector2): Transform2D {.inline.} =
|
||||||
|
getGDNativeAPI().transform2DTranslated(self, offset).toTransform2D()
|
||||||
|
|
||||||
|
proc xformVector2*(self: Transform2D; v: Vector2): Vector2 {.inline.} =
|
||||||
|
getGDNativeAPI().transform2DXformVector2(self, v).toVector2()
|
||||||
|
|
||||||
|
proc xformInvVector2*(self: Transform2D; v: Vector2): Vector2 {.inline.} =
|
||||||
|
getGDNativeAPI().transform2DXformInvVector2(self, v).toVector2()
|
||||||
|
|
||||||
|
proc basisXformVector2*(self: Transform2D; v: Vector2): Vector2 {.inline.} =
|
||||||
|
getGDNativeAPI().transform2DBasisXformVector2(self, v).toVector2()
|
||||||
|
|
||||||
|
proc basisXformInvVector2*(self: Transform2D; v: Vector2): Vector2 {.inline.} =
|
||||||
|
getGDNativeAPI().transform2DBasisXformInvVector2(self, v).toVector2()
|
||||||
|
|
||||||
|
proc xformRect2*(self: Transform2D; rect: Rect2): Rect2 {.inline.} =
|
||||||
|
getGDNativeAPI().transform2DXformRect2(self, rect).toRect2()
|
||||||
|
|
||||||
|
proc xformInvRect2*(self: Transform2D; rect: Rect2): Rect2 {.inline.} =
|
||||||
|
getGDNativeAPI().transform2DXformInvRect2(self, rect).toRect2()
|
||||||
|
|
||||||
|
proc interpolateWith*(self, m: Transform2D;
|
||||||
|
c: float32): Transform2D {.inline.} =
|
||||||
|
getGDNativeAPI().transform2DInterpolateWith(self, m, c).toTransform2D()
|
||||||
|
|
||||||
|
proc `==`*(a, b: Transform2D): bool {.inline.} =
|
||||||
|
getGDNativeAPI().transform2DOperatorEqual(a, b)
|
||||||
|
|
||||||
|
proc `*`*(a, b: Transform2D): Transform2D {.inline.} =
|
||||||
|
getGDNativeAPI().transform2DOperatorMultiply(a, b).toTransform2D()
|
||||||
|
|
||||||
|
proc `*=`*(a: var Transform2D, b: Transform2D) {.inline.} =
|
||||||
|
a = a * b
|
||||||
76
godot/core/transforms.nim
Normal file
76
godot/core/transforms.nim
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
# Copyright (c) 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
import hashes
|
||||||
|
|
||||||
|
import internal/godotinternaltypes, internal/godotstrings
|
||||||
|
import godotcoretypes, gdnativeapi
|
||||||
|
import basis, vector3
|
||||||
|
|
||||||
|
proc initTransform*(): Transform {.inline.} =
|
||||||
|
result.basis = initBasis()
|
||||||
|
|
||||||
|
proc initTransform*(xAxis, yAxis, zAxis,
|
||||||
|
origin: Vector3): Transform {.inline.} =
|
||||||
|
var basis: Basis
|
||||||
|
basis.setAxis(0, xAxis)
|
||||||
|
basis.setAxis(1, yAxis)
|
||||||
|
basis.setAxis(2, zAxis)
|
||||||
|
Transform(basis: basis, origin: origin)
|
||||||
|
|
||||||
|
proc initTransform*(basis: Basis, origin: Vector3): Transform {.inline.} =
|
||||||
|
Transform(basis: basis, origin: origin)
|
||||||
|
|
||||||
|
proc `$`*(self: Transform): string {.inline.} =
|
||||||
|
$getGDNativeAPI().transformAsString(self)
|
||||||
|
|
||||||
|
proc hash*(self: Transform): Hash {.inline.} =
|
||||||
|
!$(self.basis.hash() !& self.origin.hash())
|
||||||
|
|
||||||
|
proc inverse*(self: Transform): Transform {.inline.} =
|
||||||
|
getGDNativeAPI().transformInverse(self).toTransform()
|
||||||
|
|
||||||
|
proc affineInverse*(self: Transform): Transform {.inline.} =
|
||||||
|
getGDNativeAPI().transformAffineInverse(self).toTransform()
|
||||||
|
|
||||||
|
proc orthonormalized*(self: Transform): Transform {.inline.} =
|
||||||
|
getGDNativeAPI().transformOrthonormalized(self).toTransform()
|
||||||
|
|
||||||
|
proc rotated*(self: Transform; axis: Vector3;
|
||||||
|
phi: float32): Transform {.inline.} =
|
||||||
|
getGDNativeAPI().transformRotated(self, axis, phi).toTransform()
|
||||||
|
|
||||||
|
proc scaled*(self: Transform; scale: Vector3): Transform {.inline.} =
|
||||||
|
getGDNativeAPI().transformScaled(self, scale).toTransform()
|
||||||
|
|
||||||
|
proc translated*(self: Transform; offset: Vector3): Transform {.inline.} =
|
||||||
|
getGDNativeAPI().transformTranslated(self, offset).toTransform()
|
||||||
|
|
||||||
|
proc lookingAt*(self: Transform; target, up: Vector3): Transform {.inline.} =
|
||||||
|
getGDNativeAPI().transformLookingAt(self, target, up).toTransform()
|
||||||
|
|
||||||
|
proc xformPlane*(self: Transform; plane: Plane): Plane {.inline.} =
|
||||||
|
getGDNativeAPI().transformXformPlane(self, plane).toPlane()
|
||||||
|
|
||||||
|
proc xformInvPlane*(self: Transform; plane: Plane): Plane {.inline.} =
|
||||||
|
getGDNativeAPI().transformXformInvPlane(self, plane).toPlane()
|
||||||
|
|
||||||
|
proc xformVector3*(self: Transform; v: Vector3): Vector3 {.inline.} =
|
||||||
|
getGDNativeAPI().transformXformVector3(self, v).toVector3()
|
||||||
|
|
||||||
|
proc xformInvVector3*(self: Transform; v: Vector3): Vector3 {.inline.} =
|
||||||
|
getGDNativeAPI().transformXformInvVector3(self, v).toVector3()
|
||||||
|
|
||||||
|
proc xformAABB*(self: Transform; rect: AABB): AABB {.inline.} =
|
||||||
|
getGDNativeAPI().transformXformAABB(self, rect).toAABB()
|
||||||
|
|
||||||
|
proc xformInvAABB*(self: Transform; rect: AABB): AABB {.inline.} =
|
||||||
|
getGDNativeAPI().transformXformInvAABB(self, rect).toAABB()
|
||||||
|
|
||||||
|
proc `==`*(self: Transform; b: Transform): bool {.inline.} =
|
||||||
|
getGDNativeAPI().transformOperatorEqual(self, b)
|
||||||
|
|
||||||
|
proc `*`*(self, other: Transform): Transform {.inline.} =
|
||||||
|
getGDNativeAPI().transformOperatorMultiply(self, other).toTransform()
|
||||||
|
|
||||||
|
proc `*=`*(self: var Transform, other: Transform) {.inline.} =
|
||||||
|
self = self * other
|
||||||
308
godot/core/variants.nim
Normal file
308
godot/core/variants.nim
Normal file
|
|
@ -0,0 +1,308 @@
|
||||||
|
import tables, hashes
|
||||||
|
|
||||||
|
import godotcoretypes
|
||||||
|
import internal/godotinternaltypes, internal/godotvariants,
|
||||||
|
internal/godotstrings, internal/godotdictionaries,
|
||||||
|
internal/godotarrays
|
||||||
|
|
||||||
|
type
|
||||||
|
Variant* = ref object
|
||||||
|
godotVariant: GodotVariant
|
||||||
|
noDeinit: bool # used to avoid copying when passing the variant to Godot
|
||||||
|
|
||||||
|
export VariantType, VariantCallErrorType, VariantCallError
|
||||||
|
|
||||||
|
proc markNoDeinit*(v: Variant) {.inline.} =
|
||||||
|
## Makes it so that internal GodotVariant object will not be destroyed
|
||||||
|
## when the reference is gone. Use only if you know what you are doing.
|
||||||
|
v.noDeinit = true
|
||||||
|
|
||||||
|
proc godotVariant*(v: Variant): ptr GodotVariant {.inline.} =
|
||||||
|
## WARNING: do not keep the returned value for longer than the lifetime of
|
||||||
|
## ``v``
|
||||||
|
addr v.godotVariant
|
||||||
|
|
||||||
|
proc getType*(v: Variant): VariantType =
|
||||||
|
v.godotVariant.getType()
|
||||||
|
|
||||||
|
proc variantFinalizer*(v: Variant) =
|
||||||
|
if not v.noDeinit:
|
||||||
|
v.godotVariant.deinit()
|
||||||
|
|
||||||
|
proc `$`*(self: Variant): string {.inline.} =
|
||||||
|
$self.godotVariant
|
||||||
|
|
||||||
|
proc newVariant*(): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
initGodotVariant(result.godotVariant)
|
||||||
|
|
||||||
|
proc newVariant*(v: Variant): Variant {.inline.} =
|
||||||
|
## Makes a copy
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
initGodotVariant(result.godotVariant, v.godotVariant)
|
||||||
|
|
||||||
|
proc newVariant*(v: GodotVariant): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
result.godotVariant = v
|
||||||
|
|
||||||
|
proc newVariant*(b: bool): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
initGodotVariant(result.godotVariant, b)
|
||||||
|
|
||||||
|
# resolves Nim call ambiguities well
|
||||||
|
template numConstructor(T, ConvT) =
|
||||||
|
proc newVariant*(i: T): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
initGodotVariant(result.godotVariant, ConvT(i))
|
||||||
|
|
||||||
|
numConstructor(uint8, uint64)
|
||||||
|
numConstructor(uint16, uint64)
|
||||||
|
numConstructor(uint32, uint64)
|
||||||
|
numConstructor(uint64, uint64)
|
||||||
|
numConstructor(uint, uint64)
|
||||||
|
|
||||||
|
numConstructor(int8, int64)
|
||||||
|
numConstructor(int16, int64)
|
||||||
|
numConstructor(int32, int64)
|
||||||
|
numConstructor(int64, int64)
|
||||||
|
numConstructor(int, int64)
|
||||||
|
|
||||||
|
proc newVariant*(r: cdouble): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
initGodotVariant(result.godotVariant, r)
|
||||||
|
|
||||||
|
proc newVariant*(s: string): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
|
||||||
|
if s.isNil:
|
||||||
|
initGodotVariant(result.godotVariant)
|
||||||
|
return
|
||||||
|
var godotStr = s.toGodotString()
|
||||||
|
initGodotVariant(result.godotVariant, godotStr)
|
||||||
|
godotStr.deinit()
|
||||||
|
|
||||||
|
import basis, nodepaths
|
||||||
|
import planes, quats, rect2, aabb, rids
|
||||||
|
import transforms, transform2d, vector2
|
||||||
|
import vector3, colors
|
||||||
|
|
||||||
|
proc newVariant*(v2: Vector2): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
initGodotVariant(result.godotVariant, v2)
|
||||||
|
|
||||||
|
proc newVariant*(rect2: Rect2): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
initGodotVariant(result.godotVariant, rect2)
|
||||||
|
|
||||||
|
proc newVariant*(v3: Vector3): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
initGodotVariant(result.godotVariant, v3)
|
||||||
|
|
||||||
|
proc newVariant*(t2d: Transform2D): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
initGodotVariant(result.godotVariant, t2d)
|
||||||
|
|
||||||
|
proc newVariant*(plane: Plane): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
initGodotVariant(result.godotVariant, plane)
|
||||||
|
|
||||||
|
proc newVariant*(quat: Quat): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
initGodotVariant(result.godotVariant, quat)
|
||||||
|
|
||||||
|
proc newVariant*(aabb: AABB): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
initGodotVariant(result.godotVariant, aabb)
|
||||||
|
|
||||||
|
proc newVariant*(basis: Basis): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
initGodotVariant(result.godotVariant, basis)
|
||||||
|
|
||||||
|
proc newVariant*(trans: Transform): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
initGodotVariant(result.godotVariant, trans)
|
||||||
|
|
||||||
|
proc newVariant*(color: Color): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
initGodotVariant(result.godotVariant, color)
|
||||||
|
|
||||||
|
proc newVariant*(nodePath: NodePath): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
initGodotVariant(result.godotVariant, nodePath.godotNodePath[])
|
||||||
|
|
||||||
|
proc newVariant*(godotNodePath: GodotNodePath): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
initGodotVariant(result.godotVariant, godotNodePath)
|
||||||
|
|
||||||
|
proc newVariant*(rid: RID): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
initGodotVariant(result.godotVariant, rid)
|
||||||
|
|
||||||
|
proc newVariant*(obj: ptr GodotObject): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
initGodotVariant(result.godotVariant, obj)
|
||||||
|
|
||||||
|
import poolarrays
|
||||||
|
|
||||||
|
proc newVariant*(pba: PoolByteArray): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
initGodotVariant(result.godotVariant, pba.godotPoolByteArray[])
|
||||||
|
|
||||||
|
proc newVariant*(pia: PoolIntArray): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
initGodotVariant(result.godotVariant, pia.godotPoolIntArray[])
|
||||||
|
|
||||||
|
proc newVariant*(pra: PoolRealArray): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
initGodotVariant(result.godotVariant, pra.godotPoolRealArray[])
|
||||||
|
|
||||||
|
proc newVariant*(psa: PoolStringArray): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
initGodotVariant(result.godotVariant, psa.godotPoolStringArray[])
|
||||||
|
|
||||||
|
proc newVariant*(pv2a: PoolVector2Array): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
initGodotVariant(result.godotVariant, pv2a.godotPoolVector2Array[])
|
||||||
|
|
||||||
|
proc newVariant*(pv3a: PoolVector3Array): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
initGodotVariant(result.godotVariant, pv3a.godotPoolVector3Array[])
|
||||||
|
|
||||||
|
proc newVariant*(pca: PoolColorArray): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
initGodotVariant(result.godotVariant, pca.godotPoolColorArray[])
|
||||||
|
|
||||||
|
proc asBool*(self: Variant): bool {.inline.} =
|
||||||
|
self.godotVariant.asBool()
|
||||||
|
|
||||||
|
proc asUInt*(self: Variant): uint64 {.inline.} =
|
||||||
|
self.godotVariant.asUInt()
|
||||||
|
|
||||||
|
proc asInt*(self: Variant): int64 {.inline.} =
|
||||||
|
self.godotVariant.asInt()
|
||||||
|
|
||||||
|
proc asReal*(self: Variant): cdouble {.inline.} =
|
||||||
|
self.godotVariant.asReal()
|
||||||
|
|
||||||
|
proc asString*(self: Variant): string {.inline.} =
|
||||||
|
$self
|
||||||
|
|
||||||
|
proc asVector2*(self: Variant): Vector2 {.inline.} =
|
||||||
|
self.godotVariant.asVector2()
|
||||||
|
|
||||||
|
proc asRect2*(self: Variant): Rect2 {.inline.} =
|
||||||
|
self.godotVariant.asRect2()
|
||||||
|
|
||||||
|
proc asVector3*(self: Variant): Vector3 {.inline.} =
|
||||||
|
self.godotVariant.asVector3()
|
||||||
|
|
||||||
|
proc asTransform2D*(self: Variant): Transform2D {.inline.} =
|
||||||
|
self.godotVariant.asTransform2D()
|
||||||
|
|
||||||
|
proc asPlane*(self: Variant): Plane {.inline.} =
|
||||||
|
self.godotVariant.asPlane()
|
||||||
|
|
||||||
|
proc asQuat*(self: Variant): Quat {.inline.} =
|
||||||
|
self.godotVariant.asQuat()
|
||||||
|
|
||||||
|
proc asAABB*(self: Variant): AABB {.inline.} =
|
||||||
|
self.godotVariant.asAABB()
|
||||||
|
|
||||||
|
proc asBasis*(self: Variant): Basis {.inline.} =
|
||||||
|
self.godotVariant.asBasis()
|
||||||
|
|
||||||
|
proc asTransform*(self: Variant): Transform {.inline.} =
|
||||||
|
self.godotVariant.asTransform()
|
||||||
|
|
||||||
|
proc asColor*(self: Variant): Color {.inline.} =
|
||||||
|
self.godotVariant.asColor()
|
||||||
|
|
||||||
|
proc asNodePath*(self: Variant): NodePath {.inline.} =
|
||||||
|
result = newNodePath(self.godotVariant.asNodePath())
|
||||||
|
|
||||||
|
proc asRID*(self: Variant): RID {.inline.} =
|
||||||
|
self.godotVariant.asRID()
|
||||||
|
|
||||||
|
proc asGodotObject*(self: Variant): ptr GodotObject {.inline.} =
|
||||||
|
self.godotVariant.asGodotObject()
|
||||||
|
|
||||||
|
proc asPoolByteArray*(self: Variant): PoolByteArray {.inline.} =
|
||||||
|
newPoolByteArray(self.godotVariant.asGodotPoolByteArray())
|
||||||
|
|
||||||
|
proc asPoolIntArray*(self: Variant): PoolIntArray {.inline.} =
|
||||||
|
newPoolIntArray(self.godotVariant.asGodotPoolIntArray())
|
||||||
|
|
||||||
|
proc asPoolRealArray*(self: Variant): PoolRealArray {.inline.} =
|
||||||
|
newPoolRealArray(self.godotVariant.asGodotPoolRealArray())
|
||||||
|
|
||||||
|
proc asPoolStringArray*(self: Variant): PoolStringArray {.inline.} =
|
||||||
|
newPoolStringArray(self.godotVariant.asGodotPoolStringArray())
|
||||||
|
|
||||||
|
proc asPoolVector2Array*(self: Variant): PoolVector2Array {.inline.} =
|
||||||
|
newPoolVector2Array(self.godotVariant.asGodotPoolVector2Array())
|
||||||
|
|
||||||
|
proc asPoolVector3Array*(self: Variant): PoolVector3Array {.inline.} =
|
||||||
|
newPoolVector3Array(self.godotVariant.asGodotPoolVector3Array())
|
||||||
|
|
||||||
|
proc asPoolColorArray*(self: Variant): PoolColorArray {.inline.} =
|
||||||
|
newPoolColorArray(self.godotVariant.asGodotPoolColorArray())
|
||||||
|
|
||||||
|
proc hash*(self: Variant): Hash =
|
||||||
|
proc objectHash(obj: ptr GodotObject): Hash =
|
||||||
|
if not obj.isNil: cast[int](obj).hash() else: 0.hash()
|
||||||
|
result = case self.getType():
|
||||||
|
of VariantType.Nil: Hash(0)
|
||||||
|
of VariantType.Bool: self.asBool().hash()
|
||||||
|
of VariantType.Int: self.asInt().hash()
|
||||||
|
of VariantType.Real: self.asReal().hash()
|
||||||
|
of VariantType.String: self.asString().hash()
|
||||||
|
of VariantType.Vector2: self.asVector2().hash()
|
||||||
|
of VariantType.Rect2: self.asRect2().hash()
|
||||||
|
of VariantType.Vector3: self.asVector3().hash()
|
||||||
|
of VariantType.Transform2D: self.asTransform2D().hash()
|
||||||
|
of VariantType.Plane: self.asPlane().hash()
|
||||||
|
of VariantType.Quat: self.asQuat().hash()
|
||||||
|
of VariantType.AABB: self.asAABB().hash()
|
||||||
|
of VariantType.Basis: self.asBasis().hash()
|
||||||
|
of VariantType.Transform: self.asTransform().hash()
|
||||||
|
of VariantType.Color: self.asColor().hash()
|
||||||
|
of VariantType.NodePath: self.asNodePath().hash()
|
||||||
|
of VariantType.RID: self.asRID().hash()
|
||||||
|
of VariantType.Object: self.asGodotObject().objectHash()
|
||||||
|
of VariantType.Dictionary: hash(self.godotVariant.asGodotDictionary().godotHash())
|
||||||
|
of VariantType.Array: hash(self.godotVariant.asGodotArray().godotHash())
|
||||||
|
of VariantType.PoolByteArray: self.asPoolByteArray().hash()
|
||||||
|
of VariantType.PoolIntArray: self.asPoolIntArray().hash()
|
||||||
|
of VariantType.PoolRealArray: self.asPoolRealArray().hash()
|
||||||
|
of VariantType.PoolStringArray: self.asPoolStringArray().hash()
|
||||||
|
of VariantType.PoolVector2Array: self.asPoolVector2Array().hash()
|
||||||
|
of VariantType.PoolVector3Array: self.asPoolVector3Array().hash()
|
||||||
|
of VariantType.PoolColorArray: self.asPoolColorArray().hash()
|
||||||
|
|
||||||
|
import arrays
|
||||||
|
|
||||||
|
proc newVariant*(arr: Array): Variant {.inline.} =
|
||||||
|
new(result, variantFinalizer)
|
||||||
|
initGodotVariant(result.godotVariant, arr.godotArray[])
|
||||||
|
|
||||||
|
proc asArray*(self: Variant): Array {.inline.} =
|
||||||
|
newArray(self.godotVariant.asGodotArray())
|
||||||
|
|
||||||
|
proc hasMethod*(self: Variant; meth: string): bool =
|
||||||
|
var s = meth.toGodotString()
|
||||||
|
result = self.godotVariant.hasMethod(s)
|
||||||
|
s.deinit()
|
||||||
|
|
||||||
|
proc `==`*(self, other: Variant): bool =
|
||||||
|
if self.isNil and other.isNil: return true
|
||||||
|
if self.isNil != other.isNil: return false
|
||||||
|
result = self.godotVariant == other.godotVariant
|
||||||
|
|
||||||
|
proc `<`*(self, other: Variant): bool =
|
||||||
|
result = self.godotVariant < other.godotVariant
|
||||||
|
|
||||||
|
proc hashCompare*(self, other: Variant): bool =
|
||||||
|
self.godotVariant.hashCompare(other.godotVariant)
|
||||||
|
|
||||||
|
proc booleanize*(self: Variant): bool =
|
||||||
|
self.godotVariant.booleanize()
|
||||||
214
godot/core/vector2.nim
Normal file
214
godot/core/vector2.nim
Normal file
|
|
@ -0,0 +1,214 @@
|
||||||
|
# Copyright (c) 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
import math, godotbase, hashes
|
||||||
|
|
||||||
|
import internal/godotinternaltypes, internal/godotstrings
|
||||||
|
import godotcoretypes, gdnativeapi
|
||||||
|
|
||||||
|
const EPSILON = 0.00001'f32
|
||||||
|
|
||||||
|
{.push stackTrace: off.}
|
||||||
|
|
||||||
|
proc vec2*(): Vector2 {.inline, noinit.} =
|
||||||
|
Vector2()
|
||||||
|
|
||||||
|
proc vec2*(x, y: float32): Vector2 {.inline, noinit.} =
|
||||||
|
Vector2(x: x, y: y)
|
||||||
|
|
||||||
|
proc `$`*(self: Vector2): string {.inline, noinit.} =
|
||||||
|
$getGDNativeAPI().vector2AsString(self)
|
||||||
|
|
||||||
|
proc hash*(self: Vector2): Hash {.inline, noinit.} =
|
||||||
|
!$(self.x.hash() !& self.y.hash())
|
||||||
|
|
||||||
|
proc `+`*(self, other: Vector2): Vector2 {.inline, noinit.} =
|
||||||
|
Vector2(x: self.x + other.x, y: self.y + other.y)
|
||||||
|
|
||||||
|
proc `+=`*(self: var Vector2, other: Vector2) {.inline, noinit.} =
|
||||||
|
self.x += other.x
|
||||||
|
self.y += other.y
|
||||||
|
|
||||||
|
proc `-`*(self, other: Vector2): Vector2 {.inline, noinit.} =
|
||||||
|
Vector2(x: self.x - other.x, y: self.y - other.y)
|
||||||
|
|
||||||
|
proc `-=`*(self: var Vector2, other: Vector2) {.inline, noinit.} =
|
||||||
|
self.x -= other.x
|
||||||
|
self.y -= other.y
|
||||||
|
|
||||||
|
proc `*`*(self, other: Vector2): Vector2 {.inline, noinit.} =
|
||||||
|
Vector2(x: self.x * other.x, y: self.y * other.y)
|
||||||
|
|
||||||
|
proc `*=`*(self: var Vector2, other: Vector2) {.inline, noinit.} =
|
||||||
|
self.x *= other.x
|
||||||
|
self.y *= other.y
|
||||||
|
|
||||||
|
proc `*`*(self: Vector2, scalar: float32): Vector2 {.inline, noinit.} =
|
||||||
|
Vector2(x: self.x * scalar, y: self.y * scalar)
|
||||||
|
|
||||||
|
proc `*`*(scalar: float32, v: Vector2): Vector2 {.inline, noinit.} =
|
||||||
|
v * scalar
|
||||||
|
|
||||||
|
proc `*=`*(self: var Vector2, scalar: float32) {.inline, noinit.} =
|
||||||
|
self.x *= scalar
|
||||||
|
self.y *= scalar
|
||||||
|
|
||||||
|
proc `/`*(self, other: Vector2): Vector2 {.inline, noinit.} =
|
||||||
|
Vector2(x: self.x / other.x, y: self.y / other.y)
|
||||||
|
|
||||||
|
proc `/=`*(self: var Vector2, other: Vector2) {.inline, noinit.} =
|
||||||
|
self.x /= other.x
|
||||||
|
self.y /= other.y
|
||||||
|
|
||||||
|
proc `/`*(self: Vector2; scalar: float32): Vector2 {.inline, noinit.} =
|
||||||
|
Vector2(x: self.x / scalar, y: self.y / scalar)
|
||||||
|
|
||||||
|
proc `/=`*(self: var Vector2; scalar: float32) {.inline, noinit.} =
|
||||||
|
self = self / scalar
|
||||||
|
|
||||||
|
proc `==`*(self, other: Vector2): bool {.inline, noinit.} =
|
||||||
|
self.x == other.x and self.y == other.y
|
||||||
|
|
||||||
|
proc `<`*(self, other: Vector2): bool {.inline, noinit.} =
|
||||||
|
if self.x == other.x:
|
||||||
|
self.y < other.y
|
||||||
|
else:
|
||||||
|
self.x < other.x
|
||||||
|
|
||||||
|
proc `>`*(self, other: Vector2): bool {.inline, noinit.} =
|
||||||
|
if self.x == other.x:
|
||||||
|
self.y > other.y
|
||||||
|
else:
|
||||||
|
self.x > other.x
|
||||||
|
|
||||||
|
proc `-`*(self: Vector2): Vector2 {.inline, noinit.} =
|
||||||
|
Vector2(x: -self.x, y: -self.y)
|
||||||
|
|
||||||
|
proc length*(self: Vector2): float32 {.inline, noinit.} =
|
||||||
|
sqrt(self.x * self.x + self.y * self.y)
|
||||||
|
|
||||||
|
proc lengthSquared*(self: Vector2): float32 {.inline, noinit.} =
|
||||||
|
self.x * self.x + self.y * self.y
|
||||||
|
|
||||||
|
proc normalize*(self: var Vector2) {.inline.} =
|
||||||
|
var len = self.x * self.x + self.y * self.y
|
||||||
|
if len != 0:
|
||||||
|
len = sqrt(len)
|
||||||
|
self.x /= len
|
||||||
|
self.y /= len
|
||||||
|
|
||||||
|
proc normalized*(self: Vector2): Vector2 {.inline, noinit.} =
|
||||||
|
result = self
|
||||||
|
result.normalize()
|
||||||
|
|
||||||
|
proc angle*(self: Vector2): float32 {.inline, noinit.} =
|
||||||
|
arctan2(self.y, self.x)
|
||||||
|
|
||||||
|
proc isNormalized*(self: Vector2): bool {.inline, noinit.} =
|
||||||
|
isEqualApprox(self.lengthSquared(), 1.0)
|
||||||
|
|
||||||
|
proc distanceTo*(self, to: Vector2): float32 {.inline, noinit.} =
|
||||||
|
sqrt((self.x - to.x) * (self.x - to.x) + (self.y - to.y) * (self.y - to.y))
|
||||||
|
|
||||||
|
proc distanceSquaredTo*(self, to: Vector2): float32 {.inline, noinit.} =
|
||||||
|
(self.x - to.x) * (self.x - to.x) + (self.y - to.y) * (self.y - to.y)
|
||||||
|
|
||||||
|
proc dot*(a, b: Vector2): float32 {.inline, noinit.} =
|
||||||
|
a.x * b.x + a.y * b.y
|
||||||
|
|
||||||
|
proc cross*(a, b: Vector2): float32 {.inline, noinit.} =
|
||||||
|
a.x * b.y - a.y * b.x
|
||||||
|
|
||||||
|
proc cross*(self: Vector2, scalar: float32): Vector2 {.inline, noinit.} =
|
||||||
|
Vector2(x: scalar * self.y, y: -scalar * self.x)
|
||||||
|
|
||||||
|
proc angleTo*(self, to: Vector2): float32 {.noinit.} =
|
||||||
|
arctan2(cross(self, to), dot(self, to))
|
||||||
|
|
||||||
|
proc angleToPoint*(self, to: Vector2): float32 {.inline, noinit.} =
|
||||||
|
arctan2(self.y - to.y, self.x - to.x)
|
||||||
|
|
||||||
|
proc floor*(self: Vector2): Vector2 {.inline, noinit.} =
|
||||||
|
Vector2(x: floor(self.x), y: floor(self.y))
|
||||||
|
|
||||||
|
proc planeProject*(self: Vector2, d: float32,
|
||||||
|
vec: Vector2): Vector2 {.noinit.} =
|
||||||
|
vec - self * (self.dot(vec) - d)
|
||||||
|
|
||||||
|
proc project*(self, other: Vector2): Vector2 {.noinit.} =
|
||||||
|
self * (other.dot(self) / self.dot(self))
|
||||||
|
|
||||||
|
proc lerp*(self, b: Vector2; t: float32): Vector2 {.inline, noinit.} =
|
||||||
|
result = self
|
||||||
|
result.x += t * (b.x - self.x)
|
||||||
|
result.y += t * (b.y - self.y)
|
||||||
|
|
||||||
|
proc cubicInterpolate*(self, b, preA, postB: Vector2;
|
||||||
|
t: float32): Vector2 {.noinit.} =
|
||||||
|
let p0 = preA
|
||||||
|
let p1 = self
|
||||||
|
let p2 = b
|
||||||
|
let p3 = postB
|
||||||
|
|
||||||
|
let t2 = t * t
|
||||||
|
let t3 = t2 * t
|
||||||
|
|
||||||
|
result = 0.5'f32 * ((p1 * 2.0'f32)) +
|
||||||
|
(-p0 + p2) * t +
|
||||||
|
(2.0 * p0 - 5.0 * p1 + 4 * p2 - p3) * t2 +
|
||||||
|
(-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3
|
||||||
|
|
||||||
|
proc setRotation*(self: var Vector2, radians: float32) {.inline, noinit.} =
|
||||||
|
self.x = cos(radians)
|
||||||
|
self.y = sin(radians)
|
||||||
|
|
||||||
|
proc rotated*(self: Vector2; phi: float32): Vector2 {.inline, noinit.} =
|
||||||
|
result.setRotation(phi)
|
||||||
|
result *= self.length()
|
||||||
|
|
||||||
|
proc tangent*(self: Vector2): Vector2 {.inline, noinit.} =
|
||||||
|
Vector2(x: self.y, y: -self.x)
|
||||||
|
|
||||||
|
proc snapped*(self: Vector2; by: Vector2): Vector2 {.inline, noinit.} =
|
||||||
|
Vector2(x: stepify(self.x, by.x), y: stepify(self.y, by.y))
|
||||||
|
|
||||||
|
proc aspect*(self: Vector2): float32 {.inline, noinit.} =
|
||||||
|
self.x / self.y
|
||||||
|
|
||||||
|
proc slide*(self, n: Vector2): Vector2 {.noinit.} =
|
||||||
|
when not defined(release):
|
||||||
|
if not n.isNormalized():
|
||||||
|
printError("Normal not normalized in slide. " & getStackTrace())
|
||||||
|
return vec2()
|
||||||
|
result = self - n * self.dot(n)
|
||||||
|
|
||||||
|
proc reflect*(self, n: Vector2): Vector2 {.noinit.} =
|
||||||
|
when not defined(release):
|
||||||
|
if not n.isNormalized():
|
||||||
|
printError("Normal not normalized in bounce. " & getStackTrace())
|
||||||
|
return vec2()
|
||||||
|
result = 2.0 * n * self.dot(n) - self
|
||||||
|
|
||||||
|
proc bounce*(self, n: Vector2): Vector2 {.inline, noinit.} =
|
||||||
|
-self.reflect(n)
|
||||||
|
|
||||||
|
proc abs*(self: Vector2): Vector2 {.inline, noinit.} =
|
||||||
|
Vector2(x: abs(self.x), y: abs(self.y))
|
||||||
|
|
||||||
|
proc clamped*(self: Vector2; length: float32): Vector2 {.noinit.} =
|
||||||
|
let len = self.length()
|
||||||
|
result = self
|
||||||
|
if len > 0 and length < len:
|
||||||
|
result /= len
|
||||||
|
result *= length
|
||||||
|
|
||||||
|
proc moveToward*(vFrom, to: Vector2, delta: float32): Vector2 =
|
||||||
|
let
|
||||||
|
vd = to - vFrom
|
||||||
|
vLen = vd.length
|
||||||
|
|
||||||
|
if vLen <= delta or vLen < EPSILON:
|
||||||
|
result = to
|
||||||
|
else:
|
||||||
|
result = vFrom + (vd / vLen) * delta
|
||||||
|
|
||||||
|
{.pop.} # stackTrace: off
|
||||||
254
godot/core/vector3.nim
Normal file
254
godot/core/vector3.nim
Normal file
|
|
@ -0,0 +1,254 @@
|
||||||
|
# Copyright (c) 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
import math, hashes
|
||||||
|
import godotbase, godotcoretypes
|
||||||
|
|
||||||
|
const EPSILON = 0.00001'f32
|
||||||
|
|
||||||
|
{.push stackTrace: off.}
|
||||||
|
|
||||||
|
proc vec3*(): Vector3 {.inline.} =
|
||||||
|
Vector3()
|
||||||
|
|
||||||
|
proc vec3*(x, y, z: float32): Vector3 {.inline.} =
|
||||||
|
Vector3(x: x, y: y, z: z)
|
||||||
|
|
||||||
|
proc `$`*(self: Vector3): string {.inline.} =
|
||||||
|
result = newStringOfCap(40)
|
||||||
|
result.add('(')
|
||||||
|
result.add($self.x)
|
||||||
|
result.add(", ")
|
||||||
|
result.add($self.y)
|
||||||
|
result.add(", ")
|
||||||
|
result.add($self.z)
|
||||||
|
result.add(')')
|
||||||
|
|
||||||
|
proc hash*(self: Vector3): Hash {.inline, noinit.} =
|
||||||
|
!$(self.x.hash() !& self.y.hash() !& self.z.hash())
|
||||||
|
|
||||||
|
proc `+`*(a, b: Vector3): Vector3 {.inline.} =
|
||||||
|
result.x = a.x + b.x
|
||||||
|
result.y = a.y + b.y
|
||||||
|
result.z = a.z + b.z
|
||||||
|
|
||||||
|
proc `+=`*(a: var Vector3, b: Vector3) {.inline.} =
|
||||||
|
a.x += b.x
|
||||||
|
a.y += b.y
|
||||||
|
a.z += b.z
|
||||||
|
|
||||||
|
proc `-`*(a, b: Vector3): Vector3 {.inline.} =
|
||||||
|
result.x = a.x - b.x
|
||||||
|
result.y = a.y - b.y
|
||||||
|
result.z = a.z - b.z
|
||||||
|
|
||||||
|
proc `-=`*(a: var Vector3, b: Vector3) {.inline.} =
|
||||||
|
a.x -= b.x
|
||||||
|
a.y -= b.y
|
||||||
|
a.z -= b.z
|
||||||
|
|
||||||
|
proc `*`*(a, b: Vector3): Vector3 {.inline.} =
|
||||||
|
result.x = a.x * b.x
|
||||||
|
result.y = a.y * b.y
|
||||||
|
result.z = a.z * b.z
|
||||||
|
|
||||||
|
proc `*=`*(a: var Vector3, b: Vector3) {.inline.}=
|
||||||
|
a.x *= b.x
|
||||||
|
a.y *= b.y
|
||||||
|
a.z *= b.z
|
||||||
|
|
||||||
|
proc `*`*(a: Vector3; b: float32): Vector3 {.inline.} =
|
||||||
|
result.x = a.x * b
|
||||||
|
result.y = a.y * b
|
||||||
|
result.z = a.z * b
|
||||||
|
|
||||||
|
proc `*`*(b: float32; a: Vector3): Vector3 {.inline.} =
|
||||||
|
a * b
|
||||||
|
|
||||||
|
proc `*=`*(a: var Vector3; b: float32) {.inline.} =
|
||||||
|
a.x *= b
|
||||||
|
a.y *= b
|
||||||
|
a.z *= b
|
||||||
|
|
||||||
|
proc `/`*(a, b: Vector3): Vector3 =
|
||||||
|
result.x = a.x / b.x
|
||||||
|
result.y = a.y / b.y
|
||||||
|
result.z = a.z / b.z
|
||||||
|
|
||||||
|
proc `/=`*(a: var Vector3; b: Vector3) {.inline.} =
|
||||||
|
a.x /= b.x
|
||||||
|
a.y /= b.y
|
||||||
|
a.z /= b.z
|
||||||
|
|
||||||
|
proc `/`*(a: Vector3; b: float32): Vector3 =
|
||||||
|
result.x = a.x / b
|
||||||
|
result.y = a.y / b
|
||||||
|
result.z = a.z / b
|
||||||
|
|
||||||
|
proc `/=`*(a: var Vector3; b: float32) {.inline.} =
|
||||||
|
a.x /= b
|
||||||
|
a.y /= b
|
||||||
|
a.z /= b
|
||||||
|
|
||||||
|
proc `==`*(a, b: Vector3): bool {.inline.} =
|
||||||
|
a.x == b.x and a.y == b.y and a.z == b.z
|
||||||
|
|
||||||
|
proc `<`*(a, b: Vector3): bool =
|
||||||
|
if a.x == b.x:
|
||||||
|
if a.y == b.y:
|
||||||
|
return a.z < b.z
|
||||||
|
return a.y < b.y
|
||||||
|
return a.x < b.x
|
||||||
|
|
||||||
|
proc `-`*(self: Vector3): Vector3 =
|
||||||
|
result.x = -self.x
|
||||||
|
result.y = -self.y
|
||||||
|
result.z = -self.z
|
||||||
|
|
||||||
|
proc `[]`*(self: Vector3, idx: range[0..2]): float32 {.inline.} =
|
||||||
|
cast[array[3, float32]](self)[idx]
|
||||||
|
|
||||||
|
proc `[]`*(self: var Vector3, idx: range[0..2]): var float32 {.inline.} =
|
||||||
|
cast[ptr array[3, float32]](addr self)[][idx]
|
||||||
|
|
||||||
|
proc `[]=`*(self: var Vector3, idx: range[0..2],
|
||||||
|
val: float32) {.inline.} =
|
||||||
|
case idx:
|
||||||
|
of 0: self.x = val
|
||||||
|
of 1: self.y = val
|
||||||
|
of 2: self.z = val
|
||||||
|
|
||||||
|
proc minAxis*(self: Vector3): int {.inline.} =
|
||||||
|
if self.x < self.y:
|
||||||
|
if self.x < self.z: 0 else: 2
|
||||||
|
else:
|
||||||
|
if self.y < self.z: 1 else: 2
|
||||||
|
|
||||||
|
proc maxAxis*(self: Vector3): int {.inline.} =
|
||||||
|
if self.x < self.y:
|
||||||
|
if self.y < self.z: 2 else: 1
|
||||||
|
else:
|
||||||
|
if self.x < self.z: 2 else: 0
|
||||||
|
|
||||||
|
proc length*(self: Vector3): float32 {.inline.} =
|
||||||
|
let x2 = self.x * self.x
|
||||||
|
let y2 = self.y * self.y
|
||||||
|
let z2 = self.z * self.z
|
||||||
|
|
||||||
|
result = sqrt(x2 + y2 + z2)
|
||||||
|
|
||||||
|
proc lengthSquared*(self: Vector3): float32 {.inline.} =
|
||||||
|
let x2 = self.x * self.x
|
||||||
|
let y2 = self.y * self.y
|
||||||
|
let z2 = self.z * self.z
|
||||||
|
|
||||||
|
result = x2 + y2 + z2
|
||||||
|
|
||||||
|
proc normalize*(self: var Vector3) {.inline.} =
|
||||||
|
let len = self.length()
|
||||||
|
if len == 0:
|
||||||
|
self.x = 0
|
||||||
|
self.y = 0
|
||||||
|
self.z = 0
|
||||||
|
else:
|
||||||
|
self.x /= len
|
||||||
|
self.y /= len
|
||||||
|
self.z /= len
|
||||||
|
|
||||||
|
proc normalized*(self: Vector3): Vector3 {.inline.} =
|
||||||
|
result = self
|
||||||
|
result.normalize()
|
||||||
|
|
||||||
|
proc isNormalized*(self: Vector3): bool {.inline.} =
|
||||||
|
self.lengthSquared().isEqualApprox(1.0'f32)
|
||||||
|
|
||||||
|
proc zero*(self: var Vector3) {.inline.} =
|
||||||
|
self.x = 0
|
||||||
|
self.y = 0
|
||||||
|
self.z = 0
|
||||||
|
|
||||||
|
proc inverse*(self: Vector3): Vector3 {.inline.} =
|
||||||
|
vec3(1.0'f32 / self.x, 1.0'f32 / self.y, 1.0'f32 / self.z)
|
||||||
|
|
||||||
|
proc cross*(self, other: Vector3): Vector3 {.inline.} =
|
||||||
|
vec3(
|
||||||
|
self.y * other.z - self.z * other.y,
|
||||||
|
self.z * other.x - self.x * other.z,
|
||||||
|
self.x * other.y - self.y * other.x)
|
||||||
|
|
||||||
|
proc dot*(self, other: Vector3): float32 {.inline.} =
|
||||||
|
self.x * other.x + self.y * other.y + self.z * other.z
|
||||||
|
|
||||||
|
proc abs*(self: Vector3): Vector3 {.inline.} =
|
||||||
|
vec3(abs(self.x), abs(self.y), abs(self.z))
|
||||||
|
|
||||||
|
proc sign*(self: Vector3): Vector3 {.inline.} =
|
||||||
|
vec3(sign(self.x), sign(self.y), sign(self.z))
|
||||||
|
|
||||||
|
proc floor*(self: Vector3): Vector3 {.inline.} =
|
||||||
|
vec3(floor(self.x), floor(self.y), floor(self.z))
|
||||||
|
|
||||||
|
proc ceil*(self: Vector3): Vector3 {.inline.} =
|
||||||
|
vec3(ceil(self.x), ceil(self.y), ceil(self.z))
|
||||||
|
|
||||||
|
proc lerp*(self: Vector3, other: Vector3, t: float32): Vector3 {.inline.} =
|
||||||
|
vec3(
|
||||||
|
self.x + t * (other.x - self.x),
|
||||||
|
self.y + t * (other.y - self.y),
|
||||||
|
self.z + t * (other.z - self.z)
|
||||||
|
)
|
||||||
|
|
||||||
|
proc distanceTo*(self, other: Vector3): float32 {.inline.} =
|
||||||
|
(other - self).length()
|
||||||
|
|
||||||
|
proc distanceSquaredTo*(self, other: Vector3): float32 {.inline.} =
|
||||||
|
(other - self).lengthSquared()
|
||||||
|
|
||||||
|
proc angleTo*(self, other: Vector3): float32 {.inline.} =
|
||||||
|
arctan2(self.cross(other).length(), self.dot(other))
|
||||||
|
|
||||||
|
proc slide*(self, n: Vector3): Vector3 {.inline.} =
|
||||||
|
assert(n.isNormalized())
|
||||||
|
result = self - n * self.dot(n)
|
||||||
|
|
||||||
|
proc reflect*(self, n: Vector3): Vector3 {.inline.} =
|
||||||
|
assert(n.isNormalized())
|
||||||
|
result = 2.0'f32 * n * self.dot(n) - self
|
||||||
|
|
||||||
|
proc bounce*(self, n: Vector3): Vector3 {.inline.} =
|
||||||
|
-self.reflect(n)
|
||||||
|
|
||||||
|
proc snap*(self: var Vector3, other: Vector3) =
|
||||||
|
self.x = stepify(self.x, other.x)
|
||||||
|
self.y = stepify(self.y, other.y)
|
||||||
|
self.z = stepify(self.z, other.z)
|
||||||
|
|
||||||
|
proc snapped*(self: Vector3, other: Vector3): Vector3 =
|
||||||
|
result = self
|
||||||
|
result.snap(other)
|
||||||
|
|
||||||
|
proc cubicInterpolate*(self, b, preA, postB: Vector3;
|
||||||
|
t: float32): Vector3 =
|
||||||
|
let p0 = preA
|
||||||
|
let p1 = self
|
||||||
|
let p2 = b
|
||||||
|
let p3 = postB
|
||||||
|
|
||||||
|
let t2 = t * t
|
||||||
|
let t3 = t2 * t
|
||||||
|
|
||||||
|
result = 0.5 * ((p1 * 2.0) +
|
||||||
|
(-p0 + p2) * t +
|
||||||
|
(2.0 * p0 - 5.0 * p1 + 4 * p2 - p3) * t2 +
|
||||||
|
(-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3)
|
||||||
|
|
||||||
|
proc moveToward*(vFrom, to: Vector3, delta: float32): Vector3 =
|
||||||
|
let
|
||||||
|
vd = to - vFrom
|
||||||
|
vLen = vd.length
|
||||||
|
|
||||||
|
if vLen <= delta or vLen < EPSILON:
|
||||||
|
result = to
|
||||||
|
else:
|
||||||
|
result = vFrom + (vd / vLen) * delta
|
||||||
|
|
||||||
|
{.pop.} # stackTrace: off
|
||||||
3617
godot/gdnativeapi.nim
Normal file
3617
godot/gdnativeapi.nim
Normal file
File diff suppressed because it is too large
Load diff
18
godot/godot.nim
Normal file
18
godot/godot.nim
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Copyright 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
import core/godotbase, godotinternal
|
||||||
|
import core/godotcoretypes
|
||||||
|
import core/vector2, core/rect2, core/vector3, core/transform2d, core/planes,
|
||||||
|
core/quats
|
||||||
|
import core/aabb, core/basis, core/transforms, core/colors, core/nodepaths,
|
||||||
|
core/rids
|
||||||
|
import core/dictionaries, core/arrays, core/poolarrays, core/variants
|
||||||
|
|
||||||
|
import nim/godotmacros, nim/godotnim
|
||||||
|
|
||||||
|
export godotbase, godotcoretypes, vector2, rect2, vector3, transform2d, planes,
|
||||||
|
quats, aabb, basis, transforms, colors, nodepaths, rids, dictionaries,
|
||||||
|
arrays, poolarrays, variants
|
||||||
|
export godotmacros, godotnim
|
||||||
|
|
||||||
|
export GodotPropertyHint, GodotPropertyUsage
|
||||||
2
godot/godot.nim.cfg
Normal file
2
godot/godot.nim.cfg
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
--path:"$projectdir"
|
||||||
|
-d:useRealtimeGc
|
||||||
1115
godot/godotapigen.nim
Normal file
1115
godot/godotapigen.nim
Normal file
File diff suppressed because it is too large
Load diff
122
godot/godotinternal.nim
Normal file
122
godot/godotinternal.nim
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
# Copyright 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
import internal/godotinternaltypes, internal/godotarrays,
|
||||||
|
internal/godotnodepaths, internal/godotpoolarrays, internal/godotstrings,
|
||||||
|
internal/godotvariants, internal/godotdictionaries
|
||||||
|
|
||||||
|
import gdnativeapi
|
||||||
|
export godotinternaltypes, godotarrays, godotnodepaths, godotpoolarrays,
|
||||||
|
godotstrings, godotvariants, godotdictionaries
|
||||||
|
|
||||||
|
proc getMethod*(className: cstring;
|
||||||
|
methodName: cstring): ptr GodotMethodBind {.inline.} =
|
||||||
|
getGDNativeAPI().methodBindGetMethod(className, methodName)
|
||||||
|
|
||||||
|
proc ptrCall*(methodBind: ptr GodotMethodBind;
|
||||||
|
instance: ptr GodotObject;
|
||||||
|
args: ptr array[MAX_ARG_COUNT, pointer];
|
||||||
|
ret: pointer) {.inline.} =
|
||||||
|
getGDNativeAPI().methodBindPtrCall(methodBind, instance, args, ret)
|
||||||
|
|
||||||
|
proc call*(methodBind: ptr GodotMethodBind;
|
||||||
|
instance: ptr GodotObject;
|
||||||
|
args: ptr array[MAX_ARG_COUNT, ptr GodotVariant]; argCount: cint;
|
||||||
|
callError: var VariantCallError): GodotVariant {.inline.} =
|
||||||
|
getGDNativeAPI().methodBindCall(
|
||||||
|
methodBind, instance, args, argCount, callError)
|
||||||
|
|
||||||
|
proc nativeScriptRegisterClass*(libHandle: pointer; name, base: cstring;
|
||||||
|
createFunc: GodotInstanceCreateFunc;
|
||||||
|
destroyFunc: GodotInstanceDestroyFunc)
|
||||||
|
{.inline.} =
|
||||||
|
getGDNativeAPI().nativeScriptRegisterClass(
|
||||||
|
libHandle, name, base, createFunc, destroyFunc)
|
||||||
|
|
||||||
|
proc nativeScriptRegisterToolClass*(libHandle: pointer; name, base: cstring;
|
||||||
|
createFunc: GodotInstanceCreateFunc;
|
||||||
|
destroyFunc: GodotInstanceDestroyFunc)
|
||||||
|
{.inline.} =
|
||||||
|
getGDNativeAPI().nativeScriptRegisterToolClass(
|
||||||
|
libHandle, name, base, createFunc, destroyFunc)
|
||||||
|
|
||||||
|
proc nativeScriptRegisterMethod*(libHandle: pointer;
|
||||||
|
name: cstring; function_name: cstring;
|
||||||
|
attr: GodotMethodAttributes;
|
||||||
|
meth: GodotInstanceMethod) {.inline.} =
|
||||||
|
getGDNativeAPI().nativeScriptRegisterMethod(
|
||||||
|
libHandle, name, functionName, attr, meth)
|
||||||
|
|
||||||
|
proc nativeScriptRegisterProperty*(libHandle: pointer;
|
||||||
|
name, path: cstring;
|
||||||
|
attr: ptr GodotPropertyAttributes;
|
||||||
|
setFunc: GodotPropertySetFunc;
|
||||||
|
getFunc: GodotPropertyGetFunc) {.inline.} =
|
||||||
|
getGDNativeAPI().nativeScriptRegisterProperty(
|
||||||
|
libHandle, name, path, attr, setFunc, getFunc)
|
||||||
|
|
||||||
|
proc nativeScriptRegisterSignal*(libHandle: pointer; name: cstring;
|
||||||
|
signal: GodotSignal) {.inline.} =
|
||||||
|
getGDNativeAPI().nativeScriptRegisterSignal(libHandle, name, signal)
|
||||||
|
|
||||||
|
proc getUserdata*(instance: ptr GodotObject): pointer {.inline.} =
|
||||||
|
getGDNativeAPI().nativeScriptGetUserdata(instance)
|
||||||
|
|
||||||
|
proc getClassConstructor*(className: cstring): GodotClassConstructor
|
||||||
|
{.inline.} =
|
||||||
|
getGDNativeAPI().getClassConstructor(className)
|
||||||
|
|
||||||
|
proc deinit*(o: ptr GodotObject) {.inline.} =
|
||||||
|
getGDNativeAPI().objectDestroy(o)
|
||||||
|
|
||||||
|
# print using Godot's error handler list
|
||||||
|
|
||||||
|
proc godotPrintError*(description, function, file: cstring;
|
||||||
|
line: cint) {.inline.} =
|
||||||
|
getGDNativeAPI().printError(description, function, file, line)
|
||||||
|
|
||||||
|
proc godotPrintWarning*(description, function, file: cstring;
|
||||||
|
line: cint) {.inline.} =
|
||||||
|
getGDNativeAPI().printWarning(description, function, file, line)
|
||||||
|
|
||||||
|
proc godotPrint*(message: GodotString) {.inline.} =
|
||||||
|
getGDNativeAPI().print(message)
|
||||||
|
|
||||||
|
var getClassMethodBind: ptr GodotMethodBind
|
||||||
|
proc getClassName*(o: ptr GodotObject): string =
|
||||||
|
if getClassMethodBind.isNil:
|
||||||
|
getClassMethodBind = getMethod(cstring"Object", cstring"get_class")
|
||||||
|
var ret: GodotString
|
||||||
|
getClassMethodBind.ptrCall(o, nil, addr ret)
|
||||||
|
result = $ret
|
||||||
|
deinit(ret)
|
||||||
|
if result.len > 2 and result[^2] == 'S' and result[^1] == 'W':
|
||||||
|
# There are physics type not known by ClassDB
|
||||||
|
result = result[0..result.len-3]
|
||||||
|
|
||||||
|
proc getClassNameRaw*(o: ptr GodotObject): GodotString =
|
||||||
|
if getClassMethodBind.isNil:
|
||||||
|
getClassMethodBind = getMethod(cstring"Object", cstring"get_class")
|
||||||
|
getClassMethodBind.ptrCall(o, nil, addr result)
|
||||||
|
|
||||||
|
proc getGodotSingleton*(name: cstring): ptr GodotObject {.inline.} =
|
||||||
|
getGDNativeAPI().globalGetSingleton(name)
|
||||||
|
|
||||||
|
# System Functions
|
||||||
|
|
||||||
|
proc godotAlloc*(bytes: cint): pointer {.inline.} =
|
||||||
|
## Allocates the specified number of bytes.
|
||||||
|
## Using this instead of stdlib proc will help Godot track how much memory
|
||||||
|
## is in use in debug mode.
|
||||||
|
getGDNativeAPI().alloc(bytes)
|
||||||
|
|
||||||
|
proc godotRealloc*(p: pointer; bytes: cint): pointer {.inline.} =
|
||||||
|
## Reallocates the pointer for the specified number of bytes.
|
||||||
|
## Using this instead of stdlib proc will help Godot track how much memory
|
||||||
|
## is in use in debug mode.
|
||||||
|
getGDNativeAPI().realloc(p, bytes)
|
||||||
|
|
||||||
|
proc godotFree*(p: pointer) {.inline.} =
|
||||||
|
## Frees the memory pointed to by the pointer.
|
||||||
|
## Using this instead of stdlib proc will help Godot track how much memory
|
||||||
|
## is in use in debug mode.
|
||||||
|
getGDNativeAPI().free(p)
|
||||||
19
godot/internal/backwardcompat.inc.nim
Normal file
19
godot/internal/backwardcompat.inc.nim
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Copyright 2019 Xored Software, Inc.
|
||||||
|
|
||||||
|
when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
|
||||||
|
import macros, sets
|
||||||
|
|
||||||
|
proc strVal(n: NimNode): string {.used.} =
|
||||||
|
case n.kind
|
||||||
|
of nnkIdent:
|
||||||
|
$n.ident
|
||||||
|
of nnkSym:
|
||||||
|
$n.symbol
|
||||||
|
else:
|
||||||
|
macros.strVal(n)
|
||||||
|
|
||||||
|
proc toHashSet[A](keys: openArray[A]): HashSet[A] {.inline, used.} =
|
||||||
|
toSet(keys)
|
||||||
|
|
||||||
|
proc initHashSet[A](): HashSet[A] {.inline, used.} =
|
||||||
|
initSet[A]()
|
||||||
162
godot/internal/godotarrays.nim
Normal file
162
godot/internal/godotarrays.nim
Normal file
|
|
@ -0,0 +1,162 @@
|
||||||
|
# Copyright (c) 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
import godotinternaltypes, gdnativeapi, core/godotcoretypes
|
||||||
|
|
||||||
|
proc len*(self: GodotArray): cint {.inline.} =
|
||||||
|
getGDNativeAPI().arraySize(self)
|
||||||
|
|
||||||
|
import hashes
|
||||||
|
|
||||||
|
proc initGodotArray*(dest: var GodotArray) {.inline.} =
|
||||||
|
getGDNativeAPI().arrayNew(dest)
|
||||||
|
|
||||||
|
proc initGodotArray*(dest: var GodotArray;
|
||||||
|
pca: GodotPoolColorArray) {.inline.} =
|
||||||
|
getGDNativeAPI().arrayNewPoolColorArray(dest, pca)
|
||||||
|
|
||||||
|
proc initGodotArray*(dest: var GodotArray;
|
||||||
|
pv3a: GodotPoolVector3Array) {.inline.} =
|
||||||
|
getGDNativeAPI().arrayNewPoolVector3Array(dest, pv3a)
|
||||||
|
|
||||||
|
proc initGodotArray*(dest: var GodotArray;
|
||||||
|
pv2a: GodotPoolVector2Array) {.inline.} =
|
||||||
|
getGDNativeAPI().arrayNewPoolVector2Array(dest, pv2a)
|
||||||
|
|
||||||
|
proc initGodotArray*(dest: var GodotArray;
|
||||||
|
psa: GodotPoolStringArray) {.inline.} =
|
||||||
|
getGDNativeAPI().arrayNewPoolStringArray(dest, psa)
|
||||||
|
|
||||||
|
proc initGodotArray*(dest: var GodotArray;
|
||||||
|
pra: GodotPoolRealArray) {.inline.} =
|
||||||
|
getGDNativeAPI().arrayNewPoolRealArray(dest, pra)
|
||||||
|
|
||||||
|
proc initGodotArray*(dest: var GodotArray;
|
||||||
|
pia: GodotPoolIntArray) {.inline.} =
|
||||||
|
getGDNativeAPI().arrayNewPoolIntArray(dest, pia)
|
||||||
|
|
||||||
|
proc initGodotArray*(dest: var GodotArray;
|
||||||
|
pba: GodotPoolByteArray) {.inline.} =
|
||||||
|
getGDNativeAPI().arrayNewPoolByteArray(dest, pba)
|
||||||
|
|
||||||
|
proc initGodotArray*(dest: var GodotArray; src: GodotArray) {.inline.} =
|
||||||
|
getGDNativeAPI().arrayNewCopy(dest, src)
|
||||||
|
|
||||||
|
proc deinit*(self: var GodotArray) {.inline.} =
|
||||||
|
getGDNativeAPI().arrayDestroy(self)
|
||||||
|
|
||||||
|
proc `[]=`*(self: var GodotArray; idx: cint; value: GodotVariant) {.inline.} =
|
||||||
|
getGDNativeAPI().arraySet(self, idx, value)
|
||||||
|
|
||||||
|
proc `[]`*(self: GodotArray; idx: cint): GodotVariant {.inline.} =
|
||||||
|
getGDNativeAPI().arrayGet(self, idx)
|
||||||
|
|
||||||
|
proc mget*(self: var GodotArray; idx: cint): ptr GodotVariant {.inline.} =
|
||||||
|
getGDNativeAPI().arrayOperatorIndex(self, idx)
|
||||||
|
|
||||||
|
proc add*(self: var GodotArray; value: GodotVariant) {.inline.} =
|
||||||
|
getGDNativeAPI().arrayPushBack(self, value)
|
||||||
|
|
||||||
|
proc clear*(self: var GodotArray) {.inline.} =
|
||||||
|
getGDNativeAPI().arrayClear(self)
|
||||||
|
|
||||||
|
proc count*(self: GodotArray; value: GodotVariant): cint {.inline.} =
|
||||||
|
getGDNativeAPI().arrayCount(self, value)
|
||||||
|
|
||||||
|
proc isEmpty*(self: GodotArray): bool {.inline.} =
|
||||||
|
getGDNativeAPI().arrayEmpty(self)
|
||||||
|
|
||||||
|
proc erase*(self: var GodotArray; value: GodotVariant) {.inline.} =
|
||||||
|
getGDNativeAPI().arrayErase(self, value)
|
||||||
|
|
||||||
|
proc first*(self: GodotArray): GodotVariant {.inline.} =
|
||||||
|
getGDNativeAPI().arrayFront(self)
|
||||||
|
|
||||||
|
proc last*(self: GodotArray): GodotVariant {.inline.} =
|
||||||
|
getGDNativeAPI().arrayBack(self)
|
||||||
|
|
||||||
|
proc find*(self: GodotArray; what: GodotVariant;
|
||||||
|
fromIdx: cint): cint {.inline.} =
|
||||||
|
getGDNativeAPI().arrayFind(self, what, fromIdx)
|
||||||
|
|
||||||
|
proc findLast*(self: GodotArray; what: GodotVariant): cint {.inline.} =
|
||||||
|
getGDNativeAPI().arrayFindLast(self, what)
|
||||||
|
|
||||||
|
proc contains*(self: GodotArray; value: GodotVariant): bool {.inline.} =
|
||||||
|
getGDNativeAPI().arrayHas(self, value)
|
||||||
|
|
||||||
|
proc godotHash*(self: GodotArray): cint {.inline.} =
|
||||||
|
getGDNativeAPI().arrayHash(self)
|
||||||
|
|
||||||
|
proc hash*(self: GodotArray): Hash {.inline.} =
|
||||||
|
hash(godotHash(self))
|
||||||
|
|
||||||
|
proc insert*(self: var GodotArray; pos: cint;
|
||||||
|
value: GodotVariant): Error {.discardable, inline.} =
|
||||||
|
getGDNativeAPI().arrayInsert(self, pos, value)
|
||||||
|
|
||||||
|
proc reverse*(self: var GodotArray) {.inline.} =
|
||||||
|
getGDNativeAPI().arrayInvert(self)
|
||||||
|
|
||||||
|
proc popLast*(self: var GodotArray): GodotVariant {.inline.} =
|
||||||
|
getGDNativeAPI().arrayPopBack(self)
|
||||||
|
|
||||||
|
proc popFirst*(self: var GodotArray): GodotVariant {.inline.} =
|
||||||
|
getGDNativeAPI().arrayPopFront(self)
|
||||||
|
|
||||||
|
proc addLast*(self: var GodotArray; value: GodotVariant) {.inline.} =
|
||||||
|
getGDNativeAPI().arrayPushBack(self, value)
|
||||||
|
|
||||||
|
proc addFirst*(self: var GodotArray; value: GodotVariant) {.inline.} =
|
||||||
|
getGDNativeAPI().arrayPushFront(self, value)
|
||||||
|
|
||||||
|
proc delete*(self: var GodotArray; idx: cint) {.inline.} =
|
||||||
|
getGDNativeAPI().arrayRemove(self, idx)
|
||||||
|
|
||||||
|
proc setLen*(self: var GodotArray; size: cint) {.inline.} =
|
||||||
|
getGDNativeAPI().arrayResize(self, size)
|
||||||
|
|
||||||
|
proc rfind*(self: GodotArray; what: GodotVariant;
|
||||||
|
fromIdx: cint): cint {.inline.} =
|
||||||
|
getGDNativeAPI().arrayRFind(self, what, fromIdx)
|
||||||
|
|
||||||
|
proc sort*(self: var GodotArray) {.inline.} =
|
||||||
|
getGDNativeAPI().arraySort(self)
|
||||||
|
|
||||||
|
proc sortCustom*(self: var GodotArray; obj: ptr GodotObject;
|
||||||
|
funcName: GodotString) {.inline.} =
|
||||||
|
getGDNativeAPI().arraySortCustom(self, obj, funcName)
|
||||||
|
|
||||||
|
proc binarySearch*(self: var GodotArray, val: ptr GodotVariant,
|
||||||
|
before: bool) {.inline.} =
|
||||||
|
getGDNativeAPI().arrayBSearch(self, val, before)
|
||||||
|
|
||||||
|
proc binarySearchCustom*(self: var GodotArray, val: ptr GodotVariant,
|
||||||
|
obj: ptr GodotObject, funcName: GodotString,
|
||||||
|
before: bool) {.inline.} =
|
||||||
|
getGDNativeAPI().arrayBSearchCustom(self, val, obj, funcName, before)
|
||||||
|
|
||||||
|
iterator items*(self: GodotArray): GodotVariant =
|
||||||
|
for i in 0.cint..<self.len:
|
||||||
|
yield self[i]
|
||||||
|
|
||||||
|
iterator mitems*(self: var GodotArray): var GodotVariant =
|
||||||
|
for i in 0.cint..<self.len:
|
||||||
|
yield self.mget(i)[]
|
||||||
|
|
||||||
|
iterator pairs*(self: GodotArray): tuple[key: cint, val: GodotVariant] =
|
||||||
|
for i in 0.cint..<self.len:
|
||||||
|
yield (i, self[i])
|
||||||
|
|
||||||
|
iterator mpairs*(self: var GodotArray): tuple[key: cint,
|
||||||
|
val: var GodotVariant] =
|
||||||
|
for i in 0.cint..<self.len:
|
||||||
|
yield (i, self.mget(i)[])
|
||||||
|
|
||||||
|
proc `$`*(self: GodotArray): string =
|
||||||
|
result = newStringOfCap(32)
|
||||||
|
result.add('[')
|
||||||
|
for item in self:
|
||||||
|
if result.len > 1:
|
||||||
|
result.add(", ")
|
||||||
|
result.add($item)
|
||||||
|
result.add(']')
|
||||||
56
godot/internal/godotdictionaries.nim
Normal file
56
godot/internal/godotdictionaries.nim
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
# Copyright (c) 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
import godotinternaltypes, gdnativeapi
|
||||||
|
|
||||||
|
proc initGodotDictionary*(dest: var GodotDictionary) {.inline.} =
|
||||||
|
getGDNativeAPI().dictionaryNew(dest)
|
||||||
|
|
||||||
|
proc initGodotDictionary*(dest: var GodotDictionary;
|
||||||
|
src: GodotDictionary) {.inline.} =
|
||||||
|
getGDNativeAPI().dictionaryNewCopy(dest, src)
|
||||||
|
|
||||||
|
proc deinit*(self: var GodotDictionary) {.inline.} =
|
||||||
|
getGDNativeAPI().dictionaryDestroy(self)
|
||||||
|
|
||||||
|
proc len*(self: GodotDictionary): cint {.inline.} =
|
||||||
|
getGDNativeAPI().dictionarySize(self)
|
||||||
|
|
||||||
|
proc isEmpty*(self: GodotDictionary): bool {.inline.} =
|
||||||
|
getGDNativeAPI().dictionaryEmpty(self)
|
||||||
|
|
||||||
|
proc clear*(self: var GodotDictionary) {.inline.} =
|
||||||
|
getGDNativeAPI().dictionaryClear(self)
|
||||||
|
|
||||||
|
proc contains*(self: GodotDictionary; key: GodotVariant): bool {.inline.} =
|
||||||
|
getGDNativeAPI().dictionaryHas(self, key)
|
||||||
|
|
||||||
|
proc contains*(self: GodotDictionary; keys: GodotArray): bool {.inline.} =
|
||||||
|
getGDNativeAPI().dictionaryHasAll(self, keys)
|
||||||
|
|
||||||
|
proc del*(self: var GodotDictionary; key: GodotVariant) {.inline.} =
|
||||||
|
getGDNativeAPI().dictionaryErase(self, key)
|
||||||
|
|
||||||
|
proc godotHash*(self: GodotDictionary): cint {.inline.} =
|
||||||
|
getGDNativeAPI().dictionaryHash(self, )
|
||||||
|
|
||||||
|
proc keys*(self: GodotDictionary): GodotArray {.inline.} =
|
||||||
|
getGDNativeAPI().dictionaryKeys(self)
|
||||||
|
|
||||||
|
proc values*(self: GodotDictionary): GodotArray {.inline.} =
|
||||||
|
getGDNativeAPI().dictionaryValues(self)
|
||||||
|
|
||||||
|
proc `[]`*(self: GodotDictionary; key: GodotVariant): GodotVariant {.inline.} =
|
||||||
|
getGDNativeAPI().dictionaryGet(self, key)
|
||||||
|
|
||||||
|
proc `[]=`*(self: var GodotDictionary; key, value: GodotVariant) {.inline.} =
|
||||||
|
getGDNativeAPI().dictionarySet(self, key, value)
|
||||||
|
|
||||||
|
proc mget*(self: var GodotDictionary;
|
||||||
|
key: GodotVariant): ptr GodotVariant {.inline.} =
|
||||||
|
getGDNativeAPI().dictionaryOperatorIndex(self, key)
|
||||||
|
|
||||||
|
proc `==`*(self, other: GodotDictionary): bool {.inline.} =
|
||||||
|
getGDNativeAPI().dictionaryOperatorEqual(self, other)
|
||||||
|
|
||||||
|
proc toJson*(self: GodotDictionary): GodotString {.inline.} =
|
||||||
|
getGDNativeAPI().dictionaryToJson(self)
|
||||||
313
godot/internal/godotinternaltypes.nim
Normal file
313
godot/internal/godotinternaltypes.nim
Normal file
|
|
@ -0,0 +1,313 @@
|
||||||
|
# Copyright 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
const MAX_ARG_COUNT* = 256
|
||||||
|
|
||||||
|
type
|
||||||
|
GodotArray* {.byref.} = object
|
||||||
|
data: array[sizeof(int), byte]
|
||||||
|
|
||||||
|
GodotDictionary* {.byref.} = object
|
||||||
|
data: array[sizeof(int), byte]
|
||||||
|
|
||||||
|
GodotNodePath* {.byref.} = object
|
||||||
|
data: array[sizeof(int), byte]
|
||||||
|
|
||||||
|
GodotObject* = object
|
||||||
|
|
||||||
|
GodotPoolByteArray* {.byref.} = object
|
||||||
|
data: array[sizeof(int), byte]
|
||||||
|
GodotPoolByteArrayReadAccess* {.byref.} = object
|
||||||
|
data: array[1, byte]
|
||||||
|
GodotPoolByteArrayWriteAccess* {.byref.} = object
|
||||||
|
data: array[1, byte]
|
||||||
|
|
||||||
|
GodotPoolIntArray* {.byref.} = object
|
||||||
|
data: array[sizeof(int), byte]
|
||||||
|
GodotPoolIntArrayReadAccess* {.byref.} = object
|
||||||
|
data: array[1, byte]
|
||||||
|
GodotPoolIntArrayWriteAccess* {.byref.} = object
|
||||||
|
data: array[1, byte]
|
||||||
|
|
||||||
|
GodotPoolRealArray* {.byref.} = object
|
||||||
|
data: array[sizeof(int), byte]
|
||||||
|
GodotPoolRealArrayReadAccess* {.byref.} = object
|
||||||
|
data: array[1, byte]
|
||||||
|
GodotPoolRealArrayWriteAccess* {.byref.} = object
|
||||||
|
data: array[1, byte]
|
||||||
|
|
||||||
|
GodotPoolStringArray* {.byref.} = object
|
||||||
|
data: array[sizeof(int), byte]
|
||||||
|
GodotPoolStringArrayReadAccess* {.byref.} = object
|
||||||
|
data: array[1, byte]
|
||||||
|
GodotPoolStringArrayWriteAccess* {.byref.} = object
|
||||||
|
data: array[1, byte]
|
||||||
|
|
||||||
|
GodotPoolVector2Array* {.byref.} = object
|
||||||
|
data: array[sizeof(int), byte]
|
||||||
|
GodotPoolVector2ArrayReadAccess* {.byref.} = object
|
||||||
|
data: array[1, byte]
|
||||||
|
GodotPoolVector2ArrayWriteAccess* {.byref.} = object
|
||||||
|
data: array[1, byte]
|
||||||
|
|
||||||
|
GodotPoolVector3Array* {.byref.} = object
|
||||||
|
data: array[sizeof(int), byte]
|
||||||
|
GodotPoolVector3ArrayReadAccess* {.byref.} = object
|
||||||
|
data: array[1, byte]
|
||||||
|
GodotPoolVector3ArrayWriteAccess* {.byref.} = object
|
||||||
|
data: array[1, byte]
|
||||||
|
|
||||||
|
GodotPoolColorArray* {.byref.} = object
|
||||||
|
data: array[sizeof(int), byte]
|
||||||
|
GodotPoolColorArrayReadAccess* {.byref.} = object
|
||||||
|
data: array[1, byte]
|
||||||
|
GodotPoolColorArrayWriteAccess* {.byref.} = object
|
||||||
|
data: array[1, byte]
|
||||||
|
|
||||||
|
GodotString* {.byref.} = object
|
||||||
|
data: array[sizeof(int), byte]
|
||||||
|
|
||||||
|
cwchar_t* {.importc: "wchar_t", nodecl.} = object
|
||||||
|
|
||||||
|
GodotCharString* {.byref.} = object
|
||||||
|
data: array[sizeof(int), byte]
|
||||||
|
|
||||||
|
VariantType* {.size: sizeof(cint), pure.} = enum
|
||||||
|
Nil, ## atomic types
|
||||||
|
Bool,
|
||||||
|
Int,
|
||||||
|
Real,
|
||||||
|
String,
|
||||||
|
# math types
|
||||||
|
Vector2, ## 5
|
||||||
|
Rect2,
|
||||||
|
Vector3,
|
||||||
|
Transform2D,
|
||||||
|
Plane,
|
||||||
|
Quat, ## 10
|
||||||
|
AABB,
|
||||||
|
Basis,
|
||||||
|
Transform, ## misc types
|
||||||
|
Color,
|
||||||
|
NodePath, ## 15
|
||||||
|
RID,
|
||||||
|
Object,
|
||||||
|
Dictionary,
|
||||||
|
Array, ## 20
|
||||||
|
# arrays
|
||||||
|
PoolByteArray,
|
||||||
|
PoolIntArray,
|
||||||
|
PoolRealArray,
|
||||||
|
PoolStringArray,
|
||||||
|
PoolVector2Array, ## 25
|
||||||
|
PoolVector3Array,
|
||||||
|
PoolColorArray
|
||||||
|
|
||||||
|
VariantCallErrorType* {.size: sizeof(cint), pure.} = enum
|
||||||
|
OK,
|
||||||
|
InvalidMethod,
|
||||||
|
InvalidArgument,
|
||||||
|
TooManyArguments,
|
||||||
|
TooFewArguments,
|
||||||
|
InstanceIsNull
|
||||||
|
|
||||||
|
VariantCallError* = object
|
||||||
|
error*: VariantCallErrorType
|
||||||
|
argument*: cint
|
||||||
|
expected*: VariantType
|
||||||
|
|
||||||
|
GodotVariant* {.byref.} = object
|
||||||
|
data: array[2, int64]
|
||||||
|
data2: int
|
||||||
|
|
||||||
|
type GodotMethodBind* = object
|
||||||
|
|
||||||
|
type
|
||||||
|
GDNativeAPIVersion* = object
|
||||||
|
major*: cuint
|
||||||
|
minor*: cuint
|
||||||
|
|
||||||
|
GDNativeInitOptions* = object
|
||||||
|
inEditor*: bool
|
||||||
|
coreApiHash*: uint64
|
||||||
|
editorApiHash*: uint64
|
||||||
|
noApiHash*: uint64
|
||||||
|
reportVersionMismatch*: proc (library: ptr GodotObject, extension: cstring,
|
||||||
|
want: GDNativeAPIVersion, have: GDNativeAPIVersion) {.noconv.}
|
||||||
|
reportLoadingError*: proc (library: ptr GodotObject, what: cstring) {.noconv.}
|
||||||
|
gdNativeLibrary*: ptr GodotObject
|
||||||
|
gdNativeAPIStruct*: pointer
|
||||||
|
activeLibraryPath*: ptr GodotString
|
||||||
|
|
||||||
|
GDNativeTerminateOptions* = object
|
||||||
|
inEditor*: bool
|
||||||
|
|
||||||
|
GodotMethodRPCMode* {.size: sizeof(cint), pure.} = enum
|
||||||
|
Disabled,
|
||||||
|
Remote,
|
||||||
|
Sync,
|
||||||
|
Master,
|
||||||
|
Slave
|
||||||
|
|
||||||
|
GodotMethodAttributes* = object
|
||||||
|
rpcMode*: GodotMethodRPCMode
|
||||||
|
|
||||||
|
GodotPropertyHint* {.size: sizeof(cint), pure.} = enum
|
||||||
|
None, ## no hint provided.
|
||||||
|
Range, ## hint_text = "min,max,step,slider; // slider is optional"
|
||||||
|
ExpRange, ## hint_text = "min,max,step", exponential edit
|
||||||
|
Enum, ## hint_text= "val1,val2,val3,etc"
|
||||||
|
ExpEasing, ## exponential easing funciton (Math::ease)
|
||||||
|
Length, ## hint_text= "length" (as integer)
|
||||||
|
SpriteFrame,
|
||||||
|
KeyAccel, ## hint_text= "length" (as integer)
|
||||||
|
Flags, ## hint_text= "flag1,flag2,etc" (as bit flags)
|
||||||
|
Layers2DRender,
|
||||||
|
Layers2DPhysics,
|
||||||
|
Layers3DRender,
|
||||||
|
Layers3DPhysics,
|
||||||
|
File, ## a file path must be passed, hint_text (optionally)
|
||||||
|
## is a filter "*.png,*.wav,*.doc,"
|
||||||
|
Dir, ## a directort path must be passed
|
||||||
|
GlobalFile, ## a file path must be passed, hint_text (optionally) is a
|
||||||
|
## filter "*.png,*.wav,*.doc,"
|
||||||
|
GlobalDir, ## a directort path must be passed
|
||||||
|
ResourceType, ## a resource object type
|
||||||
|
MultilineText, ## used for string properties that can contain multiple lines
|
||||||
|
ColorNoAlpha, ## used for ignoring alpha component when editing a color
|
||||||
|
ImageCompressLossy,
|
||||||
|
ImageCompressLossless,
|
||||||
|
ObjectId,
|
||||||
|
TypeString, ## a type string, the hint is the base type to choose
|
||||||
|
NodePathToEditedNode, ## so something else can provide this
|
||||||
|
## (used in scripts)
|
||||||
|
MethodOfVariantType, ## a method of a type
|
||||||
|
MethodOfBaseType, ## a method of a base type
|
||||||
|
MethodOfInstance, ## a method of an instance
|
||||||
|
MethodOfScript, ## a method of a script & base
|
||||||
|
PropertyOfVariantType, ## a property of a type
|
||||||
|
PropertyOfBaseType, ## a property of a base type
|
||||||
|
PropertyOfInstance, ## a property of an instance
|
||||||
|
PropertyOfScript, ## a property of a script & base
|
||||||
|
PropertyHintMax
|
||||||
|
|
||||||
|
const
|
||||||
|
GODOT_PROPERTY_USAGE_STORAGE_VALUE = 1.cint
|
||||||
|
GODOT_PROPERTY_USAGE_EDITOR_VALUE = 2.cint
|
||||||
|
GODOT_PROPERTY_USAGE_NETWORK_VALUE = 4.cint
|
||||||
|
GODOT_PROPERTY_USAGE_EDITOR_HELPER_VALUE = 8.cint
|
||||||
|
GODOT_PROPERTY_USAGE_CHECKABLE_VALUE = 16.cint
|
||||||
|
GODOT_PROPERTY_USAGE_CHECKED_VALUE = 32.cint
|
||||||
|
GODOT_PROPERTY_USAGE_INTERNATIONALIZED_VALUE = 64.cint
|
||||||
|
GODOT_PROPERTY_USAGE_GROUP_VALUE = 128.cint
|
||||||
|
GODOT_PROPERTY_USAGE_CATEGORY_VALUE = 256.cint
|
||||||
|
GODOT_PROPERTY_USAGE_STORE_IF_NONZERO_VALUE = 512.cint
|
||||||
|
GODOT_PROPERTY_USAGE_STORE_IF_NONONE_VALUE = 1024.cint
|
||||||
|
GODOT_PROPERTY_USAGE_NO_INSTANCE_STATE_VALUE = 2048.cint
|
||||||
|
GODOT_PROPERTY_USAGE_RESTART_IF_CHANGED_VALUE = 4096.cint
|
||||||
|
GODOT_PROPERTY_USAGE_SCRIPT_VARIABLE_VALUE = 8192.cint
|
||||||
|
GODOT_PROPERTY_USAGE_STORE_IF_NULL_VALUE = 16384.cint
|
||||||
|
GODOT_PROPERTY_USAGE_ANIMATE_AS_TRIGGER_VALUE = 32768.cint
|
||||||
|
GODOT_PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED_VALUE = 65536.cint
|
||||||
|
|
||||||
|
GODOT_PROPERTY_USAGE_DEFAULT_VALUE: cint =
|
||||||
|
GODOT_PROPERTY_USAGE_STORAGE_VALUE or GODOT_PROPERTY_USAGE_EDITOR_VALUE or
|
||||||
|
GODOT_PROPERTY_USAGE_NETWORK_VALUE
|
||||||
|
GODOT_PROPERTY_USAGE_DEFAULT_INTL_VALUE: cint =
|
||||||
|
GODOT_PROPERTY_USAGE_STORAGE_VALUE or
|
||||||
|
GODOT_PROPERTY_USAGE_EDITOR_VALUE or GODOT_PROPERTY_USAGE_NETWORK_VALUE or
|
||||||
|
GODOT_PROPERTY_USAGE_INTERNATIONALIZED_VALUE
|
||||||
|
GODOT_PROPERTY_USAGE_NOEDITOR_VALUE: cint =
|
||||||
|
GODOT_PROPERTY_USAGE_STORAGE_VALUE or GODOT_PROPERTY_USAGE_NETWORK_VALUE
|
||||||
|
|
||||||
|
type
|
||||||
|
GodotPropertyUsage* {.size: sizeof(cint), pure.} = enum
|
||||||
|
Storage = GODOT_PROPERTY_USAGE_STORAGE_VALUE
|
||||||
|
Editor = GODOT_PROPERTY_USAGE_EDITOR_VALUE
|
||||||
|
Network = GODOT_PROPERTY_USAGE_NETWORK_VALUE
|
||||||
|
NoEditor = GODOT_PROPERTY_USAGE_NOEDITOR_VALUE
|
||||||
|
Default = GODOT_PROPERTY_USAGE_DEFAULT_VALUE
|
||||||
|
EditorHelper = GODOT_PROPERTY_USAGE_EDITOR_HELPER_VALUE
|
||||||
|
Checkable = GODOT_PROPERTY_USAGE_CHECKABLE_VALUE
|
||||||
|
## used for editing global variables
|
||||||
|
Checked = GODOT_PROPERTY_USAGE_CHECKED_VALUE
|
||||||
|
## used for editing global variables
|
||||||
|
Internationalized = GODOT_PROPERTY_USAGE_INTERNATIONALIZED_VALUE
|
||||||
|
## hint for internationalized strings
|
||||||
|
DefaultIntl = GODOT_PROPERTY_USAGE_DEFAULT_INTL_VALUE
|
||||||
|
Group = GODOT_PROPERTY_USAGE_GROUP_VALUE
|
||||||
|
## used for grouping props in the editor
|
||||||
|
Category = GODOT_PROPERTY_USAGE_CATEGORY_VALUE
|
||||||
|
NonZero = GODOT_PROPERTY_USAGE_STORE_IF_NONZERO_VALUE
|
||||||
|
## only store if nonzero
|
||||||
|
NonOne = GODOT_PROPERTY_USAGE_STORE_IF_NONONE_VALUE
|
||||||
|
## only store if false
|
||||||
|
NoInstanceState = GODOT_PROPERTY_USAGE_NO_INSTANCE_STATE_VALUE
|
||||||
|
RestartIfChanged = GODOT_PROPERTY_USAGE_RESTART_IF_CHANGED_VALUE
|
||||||
|
ScriptVariable = GODOT_PROPERTY_USAGE_SCRIPT_VARIABLE_VALUE
|
||||||
|
StoreIfNull = GODOT_PROPERTY_USAGE_STORE_IF_NULL_VALUE
|
||||||
|
AnimateAsTrigger = GODOT_PROPERTY_USAGE_ANIMATE_AS_TRIGGER_VALUE
|
||||||
|
UpdateAllIfModified = GODOT_PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED_VALUE
|
||||||
|
|
||||||
|
GodotPropertyAttributes* {.bycopy.} = object
|
||||||
|
rsetType*: GodotMethodRPCMode
|
||||||
|
typ*: cint
|
||||||
|
hint*: GodotPropertyHint
|
||||||
|
hintString*: GodotString
|
||||||
|
usage*: cint
|
||||||
|
defaultValue*: GodotVariant
|
||||||
|
|
||||||
|
GodotInstanceCreateFunc* {.bycopy.} = object
|
||||||
|
createFunc*:
|
||||||
|
proc (obj: ptr GodotObject; methodData: pointer): pointer {.noconv.}
|
||||||
|
## returns user data
|
||||||
|
methodData*: pointer
|
||||||
|
freeFunc*: proc (a2: pointer) {.noconv.}
|
||||||
|
|
||||||
|
GodotInstanceDestroyFunc* {.bycopy.} = object
|
||||||
|
destroyFunc*:
|
||||||
|
proc (obj: ptr GodotObject; methodData: pointer;
|
||||||
|
userData: pointer) {.noconv.}
|
||||||
|
methodData*: pointer
|
||||||
|
freeFunc*: proc (a2: pointer) {.noconv.}
|
||||||
|
|
||||||
|
GodotInstanceMethod* {.bycopy.} = object
|
||||||
|
meth*:
|
||||||
|
proc (obj: ptr GodotObject; methodData: pointer;
|
||||||
|
userData: pointer; numArgs: cint;
|
||||||
|
args: var array[MAX_ARG_COUNT, ptr GodotVariant]):
|
||||||
|
GodotVariant {.noconv.}
|
||||||
|
methodData*: pointer
|
||||||
|
freeFunc*: proc (a2: pointer) {.noconv.}
|
||||||
|
|
||||||
|
GodotPropertySetFunc* {.bycopy.} = object
|
||||||
|
setFunc*: proc (obj: ptr GodotObject; methodData: pointer;
|
||||||
|
userData: pointer; value: GodotVariant) {.noconv.}
|
||||||
|
methodData*: pointer
|
||||||
|
freeFunc*: proc (a2: pointer) {.noconv.}
|
||||||
|
|
||||||
|
GodotPropertyGetFunc* {.bycopy.} = object
|
||||||
|
getFunc*: proc (obj: ptr GodotObject; methodData: pointer;
|
||||||
|
userData: pointer): GodotVariant {.noconv.}
|
||||||
|
methodData*: pointer
|
||||||
|
freeFunc*: proc (a2: pointer) {.noconv.}
|
||||||
|
|
||||||
|
GodotSignalArgument* {.bycopy.} = object
|
||||||
|
name*: GodotString
|
||||||
|
typ*: cint
|
||||||
|
hint*: GodotPropertyHint
|
||||||
|
hintString*: GodotString
|
||||||
|
usage*: cint
|
||||||
|
defaultValue*: GodotVariant
|
||||||
|
|
||||||
|
GodotSignal* = object
|
||||||
|
name*: GodotString
|
||||||
|
numArgs*: cint
|
||||||
|
args*: ptr GodotSignalArgument
|
||||||
|
numDefaultArgs*: cint
|
||||||
|
defaultArgs*: ptr GodotVariant
|
||||||
|
|
||||||
|
GodotClassConstructor* = proc (): ptr GodotObject {.
|
||||||
|
noconv, gcsafe, locks: 0, raises: [], tags: [].}
|
||||||
|
|
||||||
|
template offset*[T](p: ptr T, offset: int): ptr T =
|
||||||
|
cast[ptr T](cast[ByteAddress](p) +% (offset * sizeof(T)))
|
||||||
40
godot/internal/godotnodepaths.nim
Normal file
40
godot/internal/godotnodepaths.nim
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
# Copyright 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
import godotinternaltypes, gdnativeapi
|
||||||
|
|
||||||
|
proc initGodotNodePath*(dest: var GodotNodePath; s: GodotString) {.inline.} =
|
||||||
|
getGDNativeAPI().nodePathNew(dest, s)
|
||||||
|
|
||||||
|
proc initGodotNodePath*(dest: var GodotNodePath;
|
||||||
|
src: GodotNodePath) {.inline.} =
|
||||||
|
getGDNativeAPI().nodePathNewCopy(dest, src)
|
||||||
|
|
||||||
|
proc deinit*(self: var GodotNodePath) {.inline.} =
|
||||||
|
getGDNativeAPI().nodePathDestroy(self)
|
||||||
|
|
||||||
|
proc toGodotString*(self: GodotNodePath): GodotString {.inline.} =
|
||||||
|
getGDNativeAPI().nodePathAsString(self)
|
||||||
|
|
||||||
|
proc isAbsolute*(self: GodotNodePath): bool {.inline.} =
|
||||||
|
getGDNativeAPI().nodePathIsAbsolute(self)
|
||||||
|
|
||||||
|
proc nameCount*(self: GodotNodePath): cint {.inline.} =
|
||||||
|
getGDNativeAPI().nodePathGetNameCount(self)
|
||||||
|
|
||||||
|
proc getName*(self: GodotNodePath; idx: cint): GodotString {.inline.} =
|
||||||
|
getGDNativeAPI().nodePathGetName(self, idx)
|
||||||
|
|
||||||
|
proc subnameCount*(self: GodotNodePath): cint {.inline.} =
|
||||||
|
getGDNativeAPI().nodePathGetSubnameCount(self)
|
||||||
|
|
||||||
|
proc getSubname*(self: GodotNodePath; idx: cint): GodotString {.inline.} =
|
||||||
|
getGDNativeAPI().nodePathGetSubname(self, idx)
|
||||||
|
|
||||||
|
proc getConcatenatedSubnames*(self: GodotNodePath): GodotString {.inline.} =
|
||||||
|
getGDNativeAPI().nodePathGetConcatenatedSubnames(self)
|
||||||
|
|
||||||
|
proc isEmpty*(self: GodotNodePath): bool {.inline.} =
|
||||||
|
getGDNativeAPI().nodePathIsEmpty(self)
|
||||||
|
|
||||||
|
proc `==`*(a, b: GodotNodePath): bool {.inline.} =
|
||||||
|
getGDNativeAPI().nodePathOperatorEqual(a, b)
|
||||||
269
godot/internal/godotpoolarrays.nim
Normal file
269
godot/internal/godotpoolarrays.nim
Normal file
|
|
@ -0,0 +1,269 @@
|
||||||
|
# Copyright (c) 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
import godotinternaltypes, gdnativeapi
|
||||||
|
import core/godotcoretypes
|
||||||
|
|
||||||
|
template genPoolArrayAPI(ArrayT, initIdent, DataT,
|
||||||
|
newProc, newCopyProc, newWithArrayProc, appendProc,
|
||||||
|
appendArrayProc, insertProc, invertProc, pushBackProc,
|
||||||
|
removeProc, resizeProc, setProc, getProc, sizeProc,
|
||||||
|
destroyProc, readProc, writeProc,
|
||||||
|
readAccessPtrProc, writeAccessPtrProc,
|
||||||
|
readAccessDestroyProc, writeAccessDestroyProc) =
|
||||||
|
proc initIdent*(dest: var ArrayT) {.inline.} =
|
||||||
|
getGDNativeAPI().newProc(dest)
|
||||||
|
|
||||||
|
proc initIdent*(dest: var ArrayT; src: ArrayT) {.inline.} =
|
||||||
|
getGDNativeAPI().newCopyProc(dest, src)
|
||||||
|
|
||||||
|
proc initIdent*(dest: var ArrayT; arr: GodotArray) {.inline.} =
|
||||||
|
getGDNativeAPI().newWithArrayProc(dest, arr)
|
||||||
|
|
||||||
|
proc deinit*(self: var ArrayT) {.inline.} =
|
||||||
|
getGDNativeAPI().destroyProc(self)
|
||||||
|
|
||||||
|
proc add*(self: var ArrayT; data: DataT) {.inline.} =
|
||||||
|
getGDNativeAPI().pushBackProc(self, data)
|
||||||
|
|
||||||
|
proc add*(self: var ArrayT; arr: ArrayT) {.inline.} =
|
||||||
|
getGDNativeAPI().appendArrayProc(self, arr)
|
||||||
|
|
||||||
|
proc insert*(self: var ArrayT; idx: cint;
|
||||||
|
data: DataT): Error {.inline.} =
|
||||||
|
getGDNativeAPI().insertProc(self, idx, data)
|
||||||
|
|
||||||
|
proc delete*(self: var ArrayT; idx: cint) {.inline.} =
|
||||||
|
getGDNativeAPI().removeProc(self, idx)
|
||||||
|
|
||||||
|
proc reverse*(self: var ArrayT) {.inline.} =
|
||||||
|
getGDNativeAPI().invertProc(self)
|
||||||
|
|
||||||
|
proc setLen*(self: var ArrayT; size: cint) {.inline.} =
|
||||||
|
getGDNativeAPI().resizeProc(self, size)
|
||||||
|
|
||||||
|
proc `[]=`*(self: var ArrayT; idx: cint; data: DataT) {.inline.} =
|
||||||
|
getGDNativeAPI().setProc(self, idx, data)
|
||||||
|
|
||||||
|
proc `[]`*(self: ArrayT; idx: cint): DataT {.inline.} =
|
||||||
|
let data = getGDNativeAPI().getProc(self, idx)
|
||||||
|
when DataT is Color:
|
||||||
|
data.toColor()
|
||||||
|
elif DataT is Vector2:
|
||||||
|
data.toVector2()
|
||||||
|
elif DataT is Vector3:
|
||||||
|
data.toVector3()
|
||||||
|
else:
|
||||||
|
data
|
||||||
|
|
||||||
|
proc len*(self: ArrayT): cint {.inline.} =
|
||||||
|
getGDNativeAPI().sizeProc(self)
|
||||||
|
|
||||||
|
iterator items*(self: ArrayT): DataT =
|
||||||
|
let readAccess = getGDNativeAPI().readProc(self)
|
||||||
|
let readPtr = getGDNativeAPI().readAccessPtrProc(readAccess)
|
||||||
|
for i in 0.cint..<self.len:
|
||||||
|
yield readPtr.offset(i)[]
|
||||||
|
getGDNativeAPI().readAccessDestroyProc(readAccess)
|
||||||
|
|
||||||
|
iterator mitems*(self: var ArrayT): var DataT =
|
||||||
|
let writeAccess = getGDNativeAPI().writeProc(self)
|
||||||
|
let writePtr = getGDNativeAPI().writeAccessPtrProc(writeAccess)
|
||||||
|
for i in 0.cint..<self.len:
|
||||||
|
yield writePtr.offset(i)[]
|
||||||
|
getGDNativeAPI().writeAccessDestroyProc(writeAccess)
|
||||||
|
|
||||||
|
iterator pairs*(self: ArrayT): tuple[key: cint, val: DataT] =
|
||||||
|
let readAccess = getGDNativeAPI().readProc(self)
|
||||||
|
let readPtr = getGDNativeAPI().readAccessPtrProc(readAccess)
|
||||||
|
for i in 0.cint..<self.len:
|
||||||
|
yield (i, readPtr.offset(i)[])
|
||||||
|
getGDNativeAPI().readAccessDestroyProc(readAccess)
|
||||||
|
|
||||||
|
iterator mpairs*(self: var ArrayT): tuple[key: cint, val: var DataT] =
|
||||||
|
let writeAccess = getGDNativeAPI().writeProc(self)
|
||||||
|
let writePtr = getGDNativeAPI().writeAccessPtrProc(writeAccess)
|
||||||
|
for i in 0.cint..<self.len:
|
||||||
|
yield (i, writePtr.offset(i)[])
|
||||||
|
getGDNativeAPI().writeAccessDestroyProc(writeAccess)
|
||||||
|
|
||||||
|
proc subarray*(self: ArrayT, idxFrom, idxTo: cint): ArrayT =
|
||||||
|
## Indexes are inclusive, negative values count from the end of the array.
|
||||||
|
let ownLen = self.len
|
||||||
|
var actualIdxFrom = if idxFrom < 0: idxFrom + ownLen
|
||||||
|
else: idxFrom
|
||||||
|
var actualIdxTo = if idxTo < 0: idxTo + ownLen
|
||||||
|
else: idxTo
|
||||||
|
|
||||||
|
initIdent(result)
|
||||||
|
if actualIdxFrom < 0 or actualIdxFrom >= ownLen:
|
||||||
|
let instInfo = instantiationInfo()
|
||||||
|
getGDNativeAPI().printError(
|
||||||
|
cstring"Invalid subarray begin index", cstring"subarray", instInfo.filename, instInfo.line.cint)
|
||||||
|
return
|
||||||
|
if actualIdxTo < 0 or actualIdxTo >= ownLen:
|
||||||
|
let instInfo = instantiationInfo()
|
||||||
|
getGDNativeAPI().printError(
|
||||||
|
cstring"Invalid subarray end index", cstring"subarray", instInfo.filename, instInfo.line.cint)
|
||||||
|
return
|
||||||
|
let span = actualIdxTo - actualIdxFrom + 1
|
||||||
|
result.setLen(span)
|
||||||
|
let readAccess = getGDNativeAPI().readProc(self)
|
||||||
|
let writeAccess = getGDNativeAPI().writeProc(result)
|
||||||
|
let readPtr = getGDNativeAPI().readAccessPtrProc(readAccess).offset(actualIdxFrom)
|
||||||
|
copyMem(getGDNativeAPI().writeAccessPtrProc(writeAccess), readPtr, span)
|
||||||
|
getGDNativeAPI().readAccessDestroyProc(readAccess)
|
||||||
|
getGDNativeAPI().writeAccessDestroyProc(writeAccess)
|
||||||
|
|
||||||
|
genPoolArrayAPI(GodotPoolByteArray, initGodotPoolByteArray, byte,
|
||||||
|
poolByteArrayNew,
|
||||||
|
poolByteArrayNewCopy,
|
||||||
|
poolByteArrayNewWithArray,
|
||||||
|
poolByteArrayAppend,
|
||||||
|
poolByteArrayAppendArray,
|
||||||
|
poolByteArrayInsert,
|
||||||
|
poolByteArrayInvert,
|
||||||
|
poolByteArrayPushBack,
|
||||||
|
poolByteArrayRemove,
|
||||||
|
poolByteArrayResize,
|
||||||
|
poolByteArraySet,
|
||||||
|
poolByteArrayGet,
|
||||||
|
poolByteArraySize,
|
||||||
|
poolByteArrayDestroy,
|
||||||
|
poolByteArrayRead,
|
||||||
|
poolByteArrayWrite,
|
||||||
|
poolByteArrayReadAccessPtr,
|
||||||
|
poolByteArrayWriteAccessPtr,
|
||||||
|
poolByteArrayReadAccessDestroy,
|
||||||
|
poolByteArrayWriteAccessDestroy)
|
||||||
|
|
||||||
|
genPoolArrayAPI(GodotPoolIntArray, initGodotPoolIntArray, cint,
|
||||||
|
poolIntArrayNew,
|
||||||
|
poolIntArrayNewCopy,
|
||||||
|
poolIntArrayNewWithArray,
|
||||||
|
poolIntArrayAppend,
|
||||||
|
poolIntArrayAppendArray,
|
||||||
|
poolIntArrayInsert,
|
||||||
|
poolIntArrayInvert,
|
||||||
|
poolIntArrayPushBack,
|
||||||
|
poolIntArrayRemove,
|
||||||
|
poolIntArrayResize,
|
||||||
|
poolIntArraySet,
|
||||||
|
poolIntArrayGet,
|
||||||
|
poolIntArraySize,
|
||||||
|
poolIntArrayDestroy,
|
||||||
|
poolIntArrayRead,
|
||||||
|
poolIntArrayWrite,
|
||||||
|
poolIntArrayReadAccessPtr,
|
||||||
|
poolIntArrayWriteAccessPtr,
|
||||||
|
poolIntArrayReadAccessDestroy,
|
||||||
|
poolIntArrayWriteAccessDestroy)
|
||||||
|
|
||||||
|
genPoolArrayAPI(GodotPoolRealArray, initGodotPoolRealArray, float32,
|
||||||
|
poolRealArrayNew,
|
||||||
|
poolRealArrayNewCopy,
|
||||||
|
poolRealArrayNewWithArray,
|
||||||
|
poolRealArrayAppend,
|
||||||
|
poolRealArrayAppendArray,
|
||||||
|
poolRealArrayInsert,
|
||||||
|
poolRealArrayInvert,
|
||||||
|
poolRealArrayPushBack,
|
||||||
|
poolRealArrayRemove,
|
||||||
|
poolRealArrayResize,
|
||||||
|
poolRealArraySet,
|
||||||
|
poolRealArrayGet,
|
||||||
|
poolRealArraySize,
|
||||||
|
poolRealArrayDestroy,
|
||||||
|
poolRealArrayRead,
|
||||||
|
poolRealArrayWrite,
|
||||||
|
poolRealArrayReadAccessPtr,
|
||||||
|
poolRealArrayWriteAccessPtr,
|
||||||
|
poolRealArrayReadAccessDestroy,
|
||||||
|
poolRealArrayWriteAccessDestroy)
|
||||||
|
|
||||||
|
genPoolArrayAPI(GodotPoolStringArray, initGodotPoolStringArray, GodotString,
|
||||||
|
poolStringArrayNew,
|
||||||
|
poolStringArrayNewCopy,
|
||||||
|
poolStringArrayNewWithArray,
|
||||||
|
poolStringArrayAppend,
|
||||||
|
poolStringArrayAppendArray,
|
||||||
|
poolStringArrayInsert,
|
||||||
|
poolStringArrayInvert,
|
||||||
|
poolStringArrayPushBack,
|
||||||
|
poolStringArrayRemove,
|
||||||
|
poolStringArrayResize,
|
||||||
|
poolStringArraySet,
|
||||||
|
poolStringArrayGet,
|
||||||
|
poolStringArraySize,
|
||||||
|
poolStringArrayDestroy,
|
||||||
|
poolStringArrayRead,
|
||||||
|
poolStringArrayWrite,
|
||||||
|
poolStringArrayReadAccessPtr,
|
||||||
|
poolStringArrayWriteAccessPtr,
|
||||||
|
poolStringArrayReadAccessDestroy,
|
||||||
|
poolStringArrayWriteAccessDestroy)
|
||||||
|
|
||||||
|
genPoolArrayAPI(GodotPoolVector2Array, initGodotPoolVector2Array, Vector2,
|
||||||
|
poolVector2ArrayNew,
|
||||||
|
poolVector2ArrayNewCopy,
|
||||||
|
poolVector2ArrayNewWithArray,
|
||||||
|
poolVector2ArrayAppend,
|
||||||
|
poolVector2ArrayAppendArray,
|
||||||
|
poolVector2ArrayInsert,
|
||||||
|
poolVector2ArrayInvert,
|
||||||
|
poolVector2ArrayPushBack,
|
||||||
|
poolVector2ArrayRemove,
|
||||||
|
poolVector2ArrayResize,
|
||||||
|
poolVector2ArraySet,
|
||||||
|
poolVector2ArrayGet,
|
||||||
|
poolVector2ArraySize,
|
||||||
|
poolVector2ArrayDestroy,
|
||||||
|
poolVector2ArrayRead,
|
||||||
|
poolVector2ArrayWrite,
|
||||||
|
poolVector2ArrayReadAccessPtr,
|
||||||
|
poolVector2ArrayWriteAccessPtr,
|
||||||
|
poolVector2ArrayReadAccessDestroy,
|
||||||
|
poolVector2ArrayWriteAccessDestroy)
|
||||||
|
|
||||||
|
genPoolArrayAPI(GodotPoolVector3Array, initGodotPoolVector3Array, Vector3,
|
||||||
|
poolVector3ArrayNew,
|
||||||
|
poolVector3ArrayNewCopy,
|
||||||
|
poolVector3ArrayNewWithArray,
|
||||||
|
poolVector3ArrayAppend,
|
||||||
|
poolVector3ArrayAppendArray,
|
||||||
|
poolVector3ArrayInsert,
|
||||||
|
poolVector3ArrayInvert,
|
||||||
|
poolVector3ArrayPushBack,
|
||||||
|
poolVector3ArrayRemove,
|
||||||
|
poolVector3ArrayResize,
|
||||||
|
poolVector3ArraySet,
|
||||||
|
poolVector3ArrayGet,
|
||||||
|
poolVector3ArraySize,
|
||||||
|
poolVector3ArrayDestroy,
|
||||||
|
poolVector3ArrayRead,
|
||||||
|
poolVector3ArrayWrite,
|
||||||
|
poolVector3ArrayReadAccessPtr,
|
||||||
|
poolVector3ArrayWriteAccessPtr,
|
||||||
|
poolVector3ArrayReadAccessDestroy,
|
||||||
|
poolVector3ArrayWriteAccessDestroy)
|
||||||
|
|
||||||
|
genPoolArrayAPI(GodotPoolColorArray, initGodotPoolColorArray, Color,
|
||||||
|
poolColorArrayNew,
|
||||||
|
poolColorArrayNewCopy,
|
||||||
|
poolColorArrayNewWithArray,
|
||||||
|
poolColorArrayAppend,
|
||||||
|
poolColorArrayAppendArray,
|
||||||
|
poolColorArrayInsert,
|
||||||
|
poolColorArrayInvert,
|
||||||
|
poolColorArrayPushBack,
|
||||||
|
poolColorArrayRemove,
|
||||||
|
poolColorArrayResize,
|
||||||
|
poolColorArraySet,
|
||||||
|
poolColorArrayGet,
|
||||||
|
poolColorArraySize,
|
||||||
|
poolColorArrayDestroy,
|
||||||
|
poolColorArrayRead,
|
||||||
|
poolColorArrayWrite,
|
||||||
|
poolColorArrayReadAccessPtr,
|
||||||
|
poolColorArrayWriteAccessPtr,
|
||||||
|
poolColorArrayReadAccessDestroy,
|
||||||
|
poolColorArrayWriteAccessDestroy)
|
||||||
54
godot/internal/godotstrings.nim
Normal file
54
godot/internal/godotstrings.nim
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
# Copyright (c) 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
import godotinternaltypes, gdnativeapi
|
||||||
|
|
||||||
|
proc initGodotString(dest: var GodotString) {.inline, raises: [].} =
|
||||||
|
getGDNativeAPI().stringNew(dest)
|
||||||
|
|
||||||
|
proc initGodotString(dest: var GodotString; contents: cstring;
|
||||||
|
size: cint) {.inline.} =
|
||||||
|
## Initializes ``dest`` from UTF-8 ``contents``
|
||||||
|
dest = getGDNativeAPI().stringCharsToUtf8WithLen(contents, size)
|
||||||
|
|
||||||
|
proc `==`*(self, b: GodotString): bool {.inline.} =
|
||||||
|
getGDNativeAPI().stringOperatorEqual(self, b)
|
||||||
|
|
||||||
|
proc `<`*(self, b: GodotString): bool {.inline.} =
|
||||||
|
getGDNativeAPI().stringOperatorLess(self, b)
|
||||||
|
|
||||||
|
proc `&`*(self, b: GodotString): GodotString {.inline.} =
|
||||||
|
getGDNativeAPI().stringOperatorPlus(self, b)
|
||||||
|
|
||||||
|
proc deinit*(self: var GodotString) {.inline.} =
|
||||||
|
getGDNativeAPI().stringDestroy(self)
|
||||||
|
|
||||||
|
proc len*(self: GodotString): cint {.inline.} =
|
||||||
|
getGDNativeAPI().stringLength(self)
|
||||||
|
|
||||||
|
proc dataPtr*(self: GodotString): ptr cwchar_t {.inline.} =
|
||||||
|
getGDNativeAPI().stringWideStr(self)
|
||||||
|
|
||||||
|
proc `$`*(self: GodotString): string =
|
||||||
|
## Converts the ``GodotString`` into Nim string
|
||||||
|
var charStr = getGDNativeAPI().stringUtf8(self)
|
||||||
|
let length = getGDNativeAPI().charStringLength(charStr)
|
||||||
|
result = newString(length)
|
||||||
|
copyMem(addr result[0], getGDNativeAPI().charStringGetData(charStr), length)
|
||||||
|
getGDNativeAPI().charStringDestroy(charStr)
|
||||||
|
|
||||||
|
proc toGodotString*(s: string): GodotString {.inline.} =
|
||||||
|
## Converts the Nim string into ``GodotString``
|
||||||
|
when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
|
||||||
|
if s.isNil:
|
||||||
|
initGodotString(result)
|
||||||
|
else:
|
||||||
|
initGodotString(result, cstring(s), cint(s.len + 1))
|
||||||
|
else:
|
||||||
|
initGodotString(result, cstring(s), cint(s.len + 1))
|
||||||
|
|
||||||
|
proc toGodotString*(s: cstring): GodotString {.inline.} =
|
||||||
|
## Converts the cstring into ``GodotString``
|
||||||
|
if s.isNil:
|
||||||
|
initGodotString(result)
|
||||||
|
else:
|
||||||
|
initGodotString(result, s, cint(s.len + 1))
|
||||||
217
godot/internal/godotvariants.nim
Normal file
217
godot/internal/godotvariants.nim
Normal file
|
|
@ -0,0 +1,217 @@
|
||||||
|
# Copyright 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
import core/godotcoretypes, godotinternaltypes, gdnativeapi
|
||||||
|
|
||||||
|
proc getType*(p: GodotVariant): VariantType {.inline.} =
|
||||||
|
getGDNativeAPI().variantGetType(p)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewNil(dest)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant, src: GodotVariant) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewCopy(dest, src)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant; b: bool) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewBool(dest, b)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant; i: uint64) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewUInt(dest, i)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant; i: int64) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewInt(dest, i)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant; r: cdouble) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewReal(dest, r)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant; s: GodotString) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewString(dest, s)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant; v2: Vector2) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewVector2(dest, v2)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant; rect2: Rect2) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewRect2(dest, rect2)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant; v3: Vector3) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewVector3(dest, v3)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant; t2d: Transform2D) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewTransform2D(dest, t2d)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant; plane: Plane) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewPlane(dest, plane)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant; quat: Quat) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewQuat(dest, quat)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant; aabb: AABB) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewAABB(dest, aabb)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant; basis: Basis) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewBasis(dest, basis)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant; trans: Transform) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewTransform(dest, trans)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant; color: Color) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewColor(dest, color)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant;
|
||||||
|
nodePath: GodotNodePath) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewNodePath(dest, nodePath)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant; rid: RID) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewRID(dest, rid)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant;
|
||||||
|
obj: ptr GodotObject) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewObject(dest, obj)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant; arr: GodotArray) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewArray(dest, arr)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant;
|
||||||
|
pba: GodotPoolByteArray) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewPoolByteArray(dest, pba)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant;
|
||||||
|
pia: GodotPoolIntArray) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewPoolIntArray(dest, pia)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant;
|
||||||
|
pra: GodotPoolRealArray) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewPoolRealArray(dest, pra)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant;
|
||||||
|
psa: GodotPoolStringArray) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewPoolStringArray(dest, psa)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant;
|
||||||
|
pv2a: GodotPoolVector2Array) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewPoolVector2Array(dest, pv2a)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant;
|
||||||
|
pv3a: GodotPoolVector3Array) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewPoolVector3Array(dest, pv3a)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant;
|
||||||
|
pca: GodotPoolColorArray) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewPoolColorArray(dest, pca)
|
||||||
|
|
||||||
|
proc initGodotVariant*(dest: var GodotVariant;
|
||||||
|
dict: GodotDictionary) {.inline.} =
|
||||||
|
getGDNativeAPI().variantNewDictionary(dest, dict)
|
||||||
|
|
||||||
|
proc deinit*(v: var GodotVariant) {.inline.} =
|
||||||
|
getGDNativeAPI().variantDestroy(v)
|
||||||
|
|
||||||
|
proc asBool*(self: GodotVariant): bool {.inline.} =
|
||||||
|
getGDNativeAPI().variantAsBool(self)
|
||||||
|
|
||||||
|
proc asUInt*(self: GodotVariant): uint64 {.inline.} =
|
||||||
|
getGDNativeAPI().variantAsUInt(self)
|
||||||
|
|
||||||
|
proc asInt*(self: GodotVariant): int64 {.inline.} =
|
||||||
|
getGDNativeAPI().variantAsInt(self)
|
||||||
|
|
||||||
|
proc asReal*(self: GodotVariant): cdouble {.inline.} =
|
||||||
|
getGDNativeAPI().variantAsReal(self)
|
||||||
|
|
||||||
|
proc asGodotString*(self: GodotVariant): GodotString {.inline.} =
|
||||||
|
getGDNativeAPI().variantAsString(self)
|
||||||
|
|
||||||
|
proc asVector2*(self: GodotVariant): Vector2 {.inline.} =
|
||||||
|
getGDNativeAPI().variantAsVector2(self).toVector2()
|
||||||
|
|
||||||
|
proc asRect2*(self: GodotVariant): Rect2 {.inline.} =
|
||||||
|
getGDNativeAPI().variantAsRect2(self).toRect2()
|
||||||
|
|
||||||
|
proc asVector3*(self: GodotVariant): Vector3 {.inline.} =
|
||||||
|
getGDNativeAPI().variantAsVector3(self).toVector3()
|
||||||
|
|
||||||
|
proc asTransform2D*(self: GodotVariant): Transform2D {.inline.} =
|
||||||
|
getGDNativeAPI().variantAsTransform2D(self).toTransform2D()
|
||||||
|
|
||||||
|
proc asPlane*(self: GodotVariant): Plane {.inline.} =
|
||||||
|
getGDNativeAPI().variantAsPlane(self).toPlane()
|
||||||
|
|
||||||
|
proc asQuat*(self: GodotVariant): Quat {.inline.} =
|
||||||
|
getGDNativeAPI().variantAsQuat(self).toQuat()
|
||||||
|
|
||||||
|
proc asAABB*(self: GodotVariant): AABB {.inline.} =
|
||||||
|
getGDNativeAPI().variantAsAABB(self).toAABB()
|
||||||
|
|
||||||
|
proc asBasis*(self: GodotVariant): Basis {.inline.} =
|
||||||
|
getGDNativeAPI().variantAsBasis(self).toBasis()
|
||||||
|
|
||||||
|
proc asTransform*(self: GodotVariant): Transform {.inline.} =
|
||||||
|
getGDNativeAPI().variantAsTransform(self).toTransform()
|
||||||
|
|
||||||
|
proc asColor*(self: GodotVariant): Color {.inline.} =
|
||||||
|
getGDNativeAPI().variantAsColor(self).toColor()
|
||||||
|
|
||||||
|
proc asNodePath*(self: GodotVariant): GodotNodePath {.inline.} =
|
||||||
|
getGDNativeAPI().variantAsNodePath(self)
|
||||||
|
|
||||||
|
proc asRID*(self: GodotVariant): RID {.inline.} =
|
||||||
|
getGDNativeAPI().variantAsRID(self)
|
||||||
|
|
||||||
|
proc asGodotObject*(self: GodotVariant): ptr GodotObject {.inline.} =
|
||||||
|
getGDNativeAPI().variantAsObject(self)
|
||||||
|
|
||||||
|
proc asGodotArray*(self: GodotVariant): GodotArray {.inline.} =
|
||||||
|
getGDNativeAPI().variantAsArray(self)
|
||||||
|
|
||||||
|
proc asGodotPoolByteArray*(self: GodotVariant): GodotPoolByteArray {.inline.} =
|
||||||
|
getGDNativeAPI().variantAsPoolByteArray(self)
|
||||||
|
|
||||||
|
proc asGodotPoolIntArray*(self: GodotVariant): GodotPoolIntArray {.inline.} =
|
||||||
|
getGDNativeAPI().variantAsPoolIntArray(self)
|
||||||
|
|
||||||
|
proc asGodotPoolRealArray*(self: GodotVariant): GodotPoolRealArray {.inline.} =
|
||||||
|
getGDNativeAPI().variantAsPoolRealArray(self)
|
||||||
|
|
||||||
|
proc asGodotPoolStringArray*(self: GodotVariant): GodotPoolStringArray
|
||||||
|
{.inline.} =
|
||||||
|
getGDNativeAPI().variantAsPoolStringArray(self)
|
||||||
|
|
||||||
|
proc asGodotPoolVector2Array*(self: GodotVariant): GodotPoolVector2Array
|
||||||
|
{.inline.} =
|
||||||
|
getGDNativeAPI().variantAsPoolVector2Array(self)
|
||||||
|
|
||||||
|
proc asGodotPoolVector3Array*(self: GodotVariant): GodotPoolVector3Array
|
||||||
|
{.inline.} =
|
||||||
|
getGDNativeAPI().variantAsPoolVector3Array(self)
|
||||||
|
|
||||||
|
proc asGodotPoolColorArray*(self: GodotVariant): GodotPoolColorArray
|
||||||
|
{.inline.} =
|
||||||
|
getGDNativeAPI().variantAsPoolColorArray(self)
|
||||||
|
|
||||||
|
proc asGodotDictionary*(self: GodotVariant): GodotDictionary {.inline.} =
|
||||||
|
getGDNativeAPI().variantAsDictionary(self)
|
||||||
|
|
||||||
|
proc call*(self: var GodotVariant; meth: GodotString;
|
||||||
|
args: ptr array[256, ptr GodotVariant]; argCount: cint;
|
||||||
|
error: var VariantCallError): GodotVariant {.inline.} =
|
||||||
|
getGDNativeAPI().variantCall(self, meth, args, argCount, error)
|
||||||
|
|
||||||
|
proc hasMethod*(self: GodotVariant; meth: GodotString): bool {.inline.} =
|
||||||
|
getGDNativeAPI().variantHasMethod(self, meth)
|
||||||
|
|
||||||
|
proc `==`*(self, other: GodotVariant): bool {.inline.} =
|
||||||
|
getGDNativeAPI().variantOperatorEqual(self, other)
|
||||||
|
|
||||||
|
proc `<`*(self, other: GodotVariant): bool {.inline.} =
|
||||||
|
getGDNativeAPI().variantOperatorLess(self, other)
|
||||||
|
|
||||||
|
proc hashCompare*(self, other: GodotVariant): bool {.inline.} =
|
||||||
|
getGDNativeAPI().variantHashCompare(self, other)
|
||||||
|
|
||||||
|
proc booleanize*(self: GodotVariant): bool {.inline.} =
|
||||||
|
getGDNativeAPI().variantBooleanize(self)
|
||||||
|
|
||||||
|
import godotstrings
|
||||||
|
proc `$`*(self: GodotVariant): string =
|
||||||
|
var s = self.asGodotString()
|
||||||
|
result = $s
|
||||||
|
s.deinit()
|
||||||
1
godot/internal/nim.cfg
Normal file
1
godot/internal/nim.cfg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
--path:"$projectdir/../"
|
||||||
684
godot/nim/godotmacros.nim
Normal file
684
godot/nim/godotmacros.nim
Normal file
|
|
@ -0,0 +1,684 @@
|
||||||
|
# Copyright 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
import macros, tables, typetraits, strutils, sets, sequtils, options, algorithm
|
||||||
|
import godotinternal, internal/godotvariants
|
||||||
|
import godotnim, core/variants
|
||||||
|
|
||||||
|
type
|
||||||
|
VarDecl = ref object
|
||||||
|
name: NimNode
|
||||||
|
typ: NimNode
|
||||||
|
defaultValue: NimNode
|
||||||
|
isNoGodot: bool
|
||||||
|
hint: Option[string]
|
||||||
|
hintStr: Option[string]
|
||||||
|
usage: NimNode
|
||||||
|
isExported: bool
|
||||||
|
|
||||||
|
MethodDecl = ref object
|
||||||
|
name: string
|
||||||
|
args: seq[VarDecl]
|
||||||
|
isVirtual: bool
|
||||||
|
returnType: NimNode
|
||||||
|
nimNode: NimNode
|
||||||
|
isNoGodot: bool
|
||||||
|
|
||||||
|
ObjectDecl = ref object
|
||||||
|
name: string
|
||||||
|
parentName: string
|
||||||
|
fields: seq[VarDecl]
|
||||||
|
methods: seq[MethodDecl]
|
||||||
|
isTool: bool
|
||||||
|
|
||||||
|
ParseError = object of Exception
|
||||||
|
|
||||||
|
include "internal/backwardcompat.inc.nim"
|
||||||
|
|
||||||
|
proc godotToNim[T](val: Variant): (T, ConversionResult) =
|
||||||
|
mixin fromVariant
|
||||||
|
result[1] = fromVariant(result[0], val)
|
||||||
|
|
||||||
|
proc nimToGodot[T](val: T): Variant =
|
||||||
|
mixin toVariant
|
||||||
|
when compiles(toVariant(val)):
|
||||||
|
result = toVariant(val)
|
||||||
|
else:
|
||||||
|
const err = "Cannot convert Nim value of type " & T.name &
|
||||||
|
" into Variant"
|
||||||
|
{.error: err.}
|
||||||
|
|
||||||
|
template parseError(node: NimNode, msg: string) =
|
||||||
|
raise newException(ParseError, lineinfo(node) & ": " & msg)
|
||||||
|
|
||||||
|
proc extractNames(definition: NimNode):
|
||||||
|
tuple[name, parentName: string] =
|
||||||
|
if definition.kind == nnkIdent:
|
||||||
|
result.name = definition.strVal
|
||||||
|
else:
|
||||||
|
if not (definition.kind == nnkInfix and
|
||||||
|
definition[0].strVal == "of"):
|
||||||
|
parseError(definition, "invalid type definition")
|
||||||
|
result.name = definition[1].strVal
|
||||||
|
case definition[2].kind:
|
||||||
|
of nnkIdent:
|
||||||
|
result.parentName = definition[2].strVal
|
||||||
|
else:
|
||||||
|
parseError(definition[2], "parent type expected")
|
||||||
|
|
||||||
|
when not declared(newRStrLit):
|
||||||
|
proc newRStrLit(s: string): NimNode {.compileTime.} =
|
||||||
|
result = newNimNode(nnkRStrLit)
|
||||||
|
result.strVal = s
|
||||||
|
|
||||||
|
proc newCStringLit(s: string): NimNode {.compileTime.} =
|
||||||
|
newNimNode(nnkCallStrLit).add(ident("cstring"), newRStrLit(s))
|
||||||
|
|
||||||
|
iterator pragmas(node: NimNode):
|
||||||
|
tuple[key: string, value: NimNode, index: int] =
|
||||||
|
assert node.kind in {nnkPragma, nnkEmpty}
|
||||||
|
for index in countdown(node.len - 1, 0):
|
||||||
|
if node[index].kind == nnkExprColonExpr:
|
||||||
|
yield (node[index][0].strVal, node[index][1], index)
|
||||||
|
elif node[index].kind == nnkIdent:
|
||||||
|
yield (node[index].strVal, nil, index)
|
||||||
|
|
||||||
|
proc removePragmaNode(statement: NimNode,
|
||||||
|
pname: string): NimNode {.compileTime.} =
|
||||||
|
## Removes the pragma from the node and returns value of the pragma
|
||||||
|
## Works for routine nodes or nnkPragmaExpr
|
||||||
|
if not (RoutineNodes.contains(statement.kind) or
|
||||||
|
statement.kind == nnkPragmaExpr):
|
||||||
|
return nil
|
||||||
|
|
||||||
|
result = nil
|
||||||
|
var pragmas = if RoutineNodes.contains(statement.kind): statement.pragma()
|
||||||
|
else: statement[1]
|
||||||
|
for ident, val, i in pragmas(pragmas):
|
||||||
|
if ident.eqIdent(pname):
|
||||||
|
pragmas.del(i)
|
||||||
|
return val
|
||||||
|
|
||||||
|
proc removePragma(statement: NimNode, pname: string): bool =
|
||||||
|
## Removes the pragma from the node and returns whether pragma was removed
|
||||||
|
if not (RoutineNodes.contains(statement.kind) or
|
||||||
|
statement.kind == nnkPragmaExpr):
|
||||||
|
return false
|
||||||
|
var pragmas = if RoutineNodes.contains(statement.kind): statement.pragma()
|
||||||
|
else: statement[1]
|
||||||
|
for ident, val, i in pragmas(pragmas):
|
||||||
|
if ident.eqIdent(pname):
|
||||||
|
pragmas.del(i)
|
||||||
|
return true
|
||||||
|
|
||||||
|
proc removeStrPragma(statement: NimNode,
|
||||||
|
pname: string): Option[string] {.compileTime.} =
|
||||||
|
## Removes the pragma from the node and returns value of the pragma
|
||||||
|
## Works for routine nodes or nnkPragmaExpr
|
||||||
|
let node = removePragmaNode(statement, pname)
|
||||||
|
result = if node.isNil: none(string)
|
||||||
|
else: some($node)
|
||||||
|
|
||||||
|
proc isExported(node: NimNode): bool {.compileTime.} =
|
||||||
|
if node.kind == nnkPragmaExpr:
|
||||||
|
result = isExported(node[0])
|
||||||
|
elif node.kind == nnkPostfix:
|
||||||
|
result = ($node[0] == "*")
|
||||||
|
|
||||||
|
proc identDefsToVarDecls(identDefs: NimNode): seq[VarDecl] =
|
||||||
|
assert(identDefs.kind == nnkIdentDefs)
|
||||||
|
result = newSeqOfCap[VarDecl](identDefs.len - 2)
|
||||||
|
|
||||||
|
var typ = identDefs[identDefs.len - 2]
|
||||||
|
if typ.kind == nnkEmpty:
|
||||||
|
let defaultValue = identDefs[identDefs.len - 1]
|
||||||
|
if defaultValue.kind != nnkEmpty:
|
||||||
|
typ = newCall("type", defaultValue)
|
||||||
|
|
||||||
|
for i in 0..<(identDefs.len - 2):
|
||||||
|
let nameNode = identDefs[i].copyNimTree()
|
||||||
|
let hint = removeStrPragma(nameNode, "hint")
|
||||||
|
let hintStr = removeStrPragma(nameNode, "hintStr")
|
||||||
|
let usage = removePragmaNode(nameNode, "usage")
|
||||||
|
let isGdExport = removePragma(nameNode, "gdExport")
|
||||||
|
|
||||||
|
result.add(VarDecl(
|
||||||
|
name: if nameNode.kind == nnkPragmaExpr: nameNode[0].basename()
|
||||||
|
else: nameNode.basename(),
|
||||||
|
typ: typ,
|
||||||
|
defaultValue: identDefs[identDefs.len - 1],
|
||||||
|
hint: hint,
|
||||||
|
hintStr: hintStr,
|
||||||
|
isNoGodot: not isGdExport,
|
||||||
|
usage: usage,
|
||||||
|
isExported: nameNode.isExported()
|
||||||
|
))
|
||||||
|
|
||||||
|
proc parseMethod(meth: NimNode): MethodDecl =
|
||||||
|
assert(meth.kind in {nnkProcDef, nnkMethodDef})
|
||||||
|
let isGdExport = removePragma(meth, "gdExport")
|
||||||
|
let isNoGodot = (meth.kind != nnkMethodDef and not isGdExport) or
|
||||||
|
removePragma(meth, "noGdExport")
|
||||||
|
result = MethodDecl(
|
||||||
|
name: $meth[0].basename,
|
||||||
|
args: newSeq[VarDecl](),
|
||||||
|
returnType: meth[3][0],
|
||||||
|
isVirtual: meth.kind == nnkMethodDef,
|
||||||
|
isNoGodot: isNoGodot,
|
||||||
|
nimNode: meth
|
||||||
|
)
|
||||||
|
for i in 1..<meth[3].len:
|
||||||
|
var identDefs = meth[3][i]
|
||||||
|
result.args.add(identDefsToVarDecls(identDefs))
|
||||||
|
|
||||||
|
proc parseVarSection(decl: NimNode): seq[VarDecl] =
|
||||||
|
assert(decl.kind == nnkVarSection)
|
||||||
|
for i in 0..<decl.len:
|
||||||
|
if i == 0:
|
||||||
|
result = identDefsToVarDecls(decl[i])
|
||||||
|
else:
|
||||||
|
result.add(identDefsToVarDecls(decl[i]))
|
||||||
|
|
||||||
|
proc parseType(ast: NimNode): ObjectDecl =
|
||||||
|
let definition = ast[0]
|
||||||
|
let body = ast[^1]
|
||||||
|
result = ObjectDecl(
|
||||||
|
fields: newSeq[VarDecl](),
|
||||||
|
methods: newSeq[MethodDecl]()
|
||||||
|
)
|
||||||
|
(result.name, result.parentName) = extractNames(definition)
|
||||||
|
|
||||||
|
var isTool = false
|
||||||
|
for i in 1..(ast.len - 2):
|
||||||
|
let option = ast[i]
|
||||||
|
if option.kind != nnkIdent:
|
||||||
|
parseError(option, "type specifier expected")
|
||||||
|
if option.strVal == "tool":
|
||||||
|
isTool = true
|
||||||
|
else:
|
||||||
|
parseError(option, "valid type specifier expected")
|
||||||
|
result.isTool = isTool
|
||||||
|
|
||||||
|
if result.parentName.len == 0: result.parentName = "Object"
|
||||||
|
for statement in body:
|
||||||
|
case statement.kind:
|
||||||
|
of nnkVarSection:
|
||||||
|
let varSection = parseVarSection(statement)
|
||||||
|
result.fields.add(varSection)
|
||||||
|
of nnkProcDef, nnkMethodDef:
|
||||||
|
let meth = parseMethod(statement)
|
||||||
|
result.methods.add(meth)
|
||||||
|
of nnkCommentStmt:
|
||||||
|
discard
|
||||||
|
else:
|
||||||
|
parseError(statement, "field or method declaration expected")
|
||||||
|
|
||||||
|
macro invokeVarArgs(procIdent, objIdent;
|
||||||
|
minArgs, maxArgs: static[int], numArgsIdent,
|
||||||
|
argSeqIdent; argTypes: seq[NimNode],
|
||||||
|
hasReturnValue, isStaticCall: static[bool]): untyped =
|
||||||
|
## Produces statement in form:
|
||||||
|
##
|
||||||
|
## .. code-block:: nim
|
||||||
|
## case numArgs:
|
||||||
|
## of 0:
|
||||||
|
## meth(self)
|
||||||
|
## of 1:
|
||||||
|
## let (arg0, err) = godotToNim[ArgT](argSeq[0])
|
||||||
|
## if err != ConversionResult.OK:
|
||||||
|
## error(...)
|
||||||
|
## return
|
||||||
|
## meth(self, arg0)
|
||||||
|
## else:
|
||||||
|
## error(...)
|
||||||
|
|
||||||
|
template conv(procLit, argT, argSeq, idx, argIdent, errIdent) =
|
||||||
|
let v = newVariant(argSeq[idx][])
|
||||||
|
v.markNoDeinit() # args will be destroyed externally
|
||||||
|
let (argIdent, errIdent) = godotToNim[argT](v)
|
||||||
|
if errIdent != ConversionResult.OK:
|
||||||
|
let errorKind = if errIdent == ConversionResult.TypeError: "a type error"
|
||||||
|
else: "a range error"
|
||||||
|
printError(
|
||||||
|
"Failed to invoke Nim procedure " & $procLit &
|
||||||
|
": " & errorKind & " has occurred when converting argument " & $idx &
|
||||||
|
" of Godot type " & $argSeq[idx][].getType())
|
||||||
|
return
|
||||||
|
|
||||||
|
# these help to avoid exporting internal modules
|
||||||
|
# thanks to closed symbol binding
|
||||||
|
template initGodotVariantCall(result) =
|
||||||
|
initGodotVariant(result)
|
||||||
|
|
||||||
|
template initGodotVariantCall(result, src) =
|
||||||
|
initGodotVariant(result, src)
|
||||||
|
|
||||||
|
result = newNimNode(nnkCaseStmt)
|
||||||
|
result.add(numArgsIdent)
|
||||||
|
for i in minArgs..maxArgs:
|
||||||
|
let branch = newNimNode(nnkOfBranch).add(newIntLitNode(i))
|
||||||
|
let branchBody = newStmtList()
|
||||||
|
var invocation = newNimNode(nnkCall)
|
||||||
|
invocation.add(procIdent)
|
||||||
|
invocation.add(objIdent) # self
|
||||||
|
for idx in 0..<i:
|
||||||
|
let argIdent = genSym(nskLet, "arg")
|
||||||
|
let errIdent = genSym(nskLet, "err")
|
||||||
|
let argT = argTypes[idx]
|
||||||
|
branchBody.add(getAst(conv($procIdent, argT,
|
||||||
|
argSeqIdent, idx, argIdent, errIdent)))
|
||||||
|
invocation.add(argIdent)
|
||||||
|
|
||||||
|
if isStaticCall:
|
||||||
|
invocation = newNimNode(nnkCall).add(ident("procCall"), invocation)
|
||||||
|
|
||||||
|
if hasReturnValue:
|
||||||
|
let resultVariant = genSym(nskLet, "ret")
|
||||||
|
branchBody.add(
|
||||||
|
newNimNode(nnkLetSection).add(
|
||||||
|
newIdentDefs(resultVariant, ident("Variant"), newCall("toVariant", invocation))))
|
||||||
|
let theCall = newNimNode(nnkBracketExpr).add(newNimNode(nnkDotExpr).add(
|
||||||
|
resultVariant, ident("godotVariant")))
|
||||||
|
branchBody.add(getAst(initGodotVariantCall(ident("result"), theCall)))
|
||||||
|
else:
|
||||||
|
branchBody.add(invocation)
|
||||||
|
branchBody.add(getAst(initGodotVariantCall(ident("result"))))
|
||||||
|
|
||||||
|
branch.add(branchBody)
|
||||||
|
result.add(branch)
|
||||||
|
template printInvokeErr(procName, minArgs, maxArgs, numArgs) =
|
||||||
|
printError(
|
||||||
|
"Failed to invoke Nim procedure " & procName &
|
||||||
|
": expected " & $minArgs & "-" & $maxArgs &
|
||||||
|
" arguments, but got " & $numArgs)
|
||||||
|
|
||||||
|
result.add(newNimNode(nnkElse).add(getAst(
|
||||||
|
printInvokeErr(procIdent.strVal, minArgs, maxArgs, numArgsIdent))))
|
||||||
|
|
||||||
|
proc typeError(nimType: string, value: string, godotType: VariantType,
|
||||||
|
className: cstring, propertyName: cstring): string =
|
||||||
|
result = "Tried to assign incompatible value " & value & " (" & $godotType &
|
||||||
|
") to field \"" & $propertyName & ": " & $nimType & "\" of " &
|
||||||
|
$className
|
||||||
|
|
||||||
|
proc rangeError(nimType: string, value: string, className: cstring,
|
||||||
|
propertyName: cstring): string =
|
||||||
|
result = "Tried to assign the out-of-range value " & value &
|
||||||
|
" to field \"" & $propertyName & ": " & $nimType & "\" of " &
|
||||||
|
$className
|
||||||
|
|
||||||
|
|
||||||
|
proc nimDestroyFunc(obj: ptr GodotObject, methData: pointer,
|
||||||
|
userData: pointer) {.noconv.} =
|
||||||
|
let nimObj = cast[NimGodotObject](userData)
|
||||||
|
nimObj.removeGodotObject()
|
||||||
|
GC_unref(nimObj)
|
||||||
|
|
||||||
|
proc nimDestroyRefFunc(obj: ptr GodotObject, methData: pointer,
|
||||||
|
userData: pointer) {.noconv.} =
|
||||||
|
# references are destroyed by Godot when they are already destroyed by Nim,
|
||||||
|
# so nothing to do here.
|
||||||
|
discard
|
||||||
|
|
||||||
|
proc refcountIncremented(obj: ptr GodotObject, methodData: pointer,
|
||||||
|
userData: pointer, numArgs: cint,
|
||||||
|
args: var array[MAX_ARG_COUNT, ptr GodotVariant]):
|
||||||
|
GodotVariant {.noconv.} =
|
||||||
|
let nimObj = cast[NimGodotObject](userData)
|
||||||
|
if not nimObj.isFinalized:
|
||||||
|
GC_ref(nimObj)
|
||||||
|
|
||||||
|
proc refcountDecremented(obj: ptr GodotObject, methodData: pointer,
|
||||||
|
userData: pointer, numArgs: cint,
|
||||||
|
args: var array[MAX_ARG_COUNT, ptr GodotVariant]):
|
||||||
|
GodotVariant {.noconv.} =
|
||||||
|
let nimObj = cast[NimGodotObject](userData)
|
||||||
|
if not nimObj.isFinalized:
|
||||||
|
GC_unref(nimObj)
|
||||||
|
initGodotVariant(result, nimObj.isFinalized)
|
||||||
|
|
||||||
|
template registerGodotClass(classNameIdent, classNameLit; isRefClass: bool;
|
||||||
|
baseNameLit, createFuncIdent; isTool: bool) =
|
||||||
|
proc createFuncIdent(obj: ptr GodotObject,
|
||||||
|
methData: pointer): pointer {.noconv.} =
|
||||||
|
var nimObj: classNameIdent
|
||||||
|
new(nimObj, nimGodotObjectFinalizer[classNameIdent])
|
||||||
|
nimObj.setGodotObject(obj)
|
||||||
|
nimObj.isRef = when isRefClass: true else: false
|
||||||
|
nimObj.setNativeObject(asNimGodotObject[NimGodotObject](
|
||||||
|
obj, forceNativeObject = true))
|
||||||
|
GC_ref(nimObj)
|
||||||
|
result = cast[pointer](nimObj)
|
||||||
|
when compiles(nimObj.init()):
|
||||||
|
nimObj.init()
|
||||||
|
|
||||||
|
let createFuncObj = GodotInstanceCreateFunc(
|
||||||
|
createFunc: createFuncIdent
|
||||||
|
)
|
||||||
|
let destroyFuncObj = GodotInstanceDestroyFunc(
|
||||||
|
destroyFunc: when isRefClass: nimDestroyRefFunc else: nimDestroyFunc
|
||||||
|
)
|
||||||
|
registerClass(classNameIdent, classNameLit, false)
|
||||||
|
when isTool:
|
||||||
|
nativeScriptRegisterToolClass(getNativeLibHandle(), classNameLit,
|
||||||
|
baseNameLit, createFuncObj, destroyFuncObj)
|
||||||
|
else:
|
||||||
|
nativeScriptRegisterClass(getNativeLibHandle(), classNameLit,
|
||||||
|
baseNameLit, createFuncObj, destroyFuncObj)
|
||||||
|
|
||||||
|
template registerGodotField(classNameLit, classNameIdent, propNameLit,
|
||||||
|
propNameIdent, propTypeLit, propTypeIdent,
|
||||||
|
setFuncIdent, getFuncIdent, hintStrLit,
|
||||||
|
hintIdent, usageExpr, hasDefaultValue,
|
||||||
|
defaultValueNode) =
|
||||||
|
proc setFuncIdent(obj: ptr GodotObject, methData: pointer,
|
||||||
|
nimPtr: pointer, val: GodotVariant) {.noconv.} =
|
||||||
|
let variant = newVariant(val)
|
||||||
|
variant.markNoDeinit()
|
||||||
|
let (nimVal, err) = godotToNim[propTypeIdent](variant)
|
||||||
|
case err:
|
||||||
|
of ConversionResult.OK:
|
||||||
|
cast[classNameIdent](nimPtr).propNameIdent = nimVal
|
||||||
|
of ConversionResult.TypeError:
|
||||||
|
let errStr = typeError(propTypeLit, $val, val.getType(),
|
||||||
|
classNameLit, astToStr(propNameIdent))
|
||||||
|
printError(errStr)
|
||||||
|
of ConversionResult.RangeError:
|
||||||
|
let errStr = rangeError(propTypeLit, $val,
|
||||||
|
classNameLit, astToStr(propNameIdent))
|
||||||
|
printError(errStr)
|
||||||
|
|
||||||
|
proc getFuncIdent(obj: ptr GodotObject, methData: pointer,
|
||||||
|
nimPtr: pointer): GodotVariant {.noconv.} =
|
||||||
|
let variant = nimToGodot(cast[classNameIdent](nimPtr).propNameIdent)
|
||||||
|
variant.markNoDeinit()
|
||||||
|
result = variant.godotVariant[]
|
||||||
|
|
||||||
|
let setFunc = GodotPropertySetFunc(
|
||||||
|
setFunc: setFuncIdent
|
||||||
|
)
|
||||||
|
let getFunc = GodotPropertyGetFunc(
|
||||||
|
getFunc: getFuncIdent
|
||||||
|
)
|
||||||
|
mixin godotTypeInfo
|
||||||
|
const typeInfo = when compiles(godotTypeInfo(propTypeIdent)):
|
||||||
|
godotTypeInfo(propTypeIdent)
|
||||||
|
else: GodotTypeInfo()
|
||||||
|
const hintStr = when hintStrLit != "NIM":
|
||||||
|
hintStrLit
|
||||||
|
else:
|
||||||
|
typeInfo.hintStr
|
||||||
|
const hint = when astToStr(hintIdent) != "NIM":
|
||||||
|
GodotPropertyHint.hintIdent
|
||||||
|
else:
|
||||||
|
typeInfo.hint
|
||||||
|
const variantType = typeInfo.variantType
|
||||||
|
|
||||||
|
var hintStrGodot = hintStr.toGodotString()
|
||||||
|
{.push warning[ProveInit]: off.} # false warning, Nim bug
|
||||||
|
var attr = GodotPropertyAttributes(
|
||||||
|
typ: ord(variantType),
|
||||||
|
hint: hint,
|
||||||
|
hintString: hintStrGodot,
|
||||||
|
usage: usageExpr
|
||||||
|
)
|
||||||
|
{.push warning[ProveInit]: on.}
|
||||||
|
when hasDefaultValue:
|
||||||
|
attr.defaultValue = (defaultValueNode).toVariant().godotVariant[]
|
||||||
|
nativeScriptRegisterProperty(getNativeLibHandle(), classNameLit, propNameLit,
|
||||||
|
unsafeAddr attr, setFunc, getFunc)
|
||||||
|
hintStrGodot.deinit()
|
||||||
|
|
||||||
|
proc toGodotStyle(s: string): string {.compileTime.} =
|
||||||
|
result = newStringOfCap(s.len + 10)
|
||||||
|
for c in s:
|
||||||
|
if c.isUpperAscii():
|
||||||
|
result.add('_')
|
||||||
|
result.add(c.toLowerAscii())
|
||||||
|
else:
|
||||||
|
result.add(c)
|
||||||
|
|
||||||
|
proc genType(obj: ObjectDecl): NimNode {.compileTime.} =
|
||||||
|
result = newNimNode(nnkStmtList)
|
||||||
|
|
||||||
|
# Nim type definition
|
||||||
|
let typeDef = newNimNode(nnkTypeDef)
|
||||||
|
result.add(newNimNode(nnkTypeSection).add(typeDef))
|
||||||
|
typeDef.add(postfix(ident(obj.name), "*"))
|
||||||
|
typeDef.add(newEmptyNode())
|
||||||
|
let objTy = newNimNode(nnkObjectTy)
|
||||||
|
typeDef.add(newNimNode(nnkRefTy).add(objTy))
|
||||||
|
objTy.add(newEmptyNode())
|
||||||
|
if obj.parentName.len == 0:
|
||||||
|
objTy.add(newEmptyNode())
|
||||||
|
else:
|
||||||
|
objTy.add(newNimNode(nnkOfInherit).add(ident(obj.parentName)))
|
||||||
|
|
||||||
|
let recList = newNimNode(nnkRecList)
|
||||||
|
objTy.add(recList)
|
||||||
|
let initBody = newStmtList()
|
||||||
|
for decl in obj.fields:
|
||||||
|
if not decl.defaultValue.isNil and decl.defaultValue.kind != nnkEmpty:
|
||||||
|
initBody.add(newNimNode(nnkAsgn).add(newDotExpr(ident("self"), decl.name),
|
||||||
|
decl.defaultValue))
|
||||||
|
let name = if not decl.isExported: decl.name
|
||||||
|
else: postfix(decl.name, "*")
|
||||||
|
recList.add(newIdentDefs(name, decl.typ))
|
||||||
|
|
||||||
|
# Add default values and/or super call to init method
|
||||||
|
initBody.insert(0, newNimNode(nnkCommand).add(ident("procCall"),
|
||||||
|
newCall("init", newCall(obj.parentName, ident("self")))))
|
||||||
|
var initMethod: NimNode
|
||||||
|
for meth in obj.methods:
|
||||||
|
if meth.name == "init" and meth.nimNode[3].len == 1:
|
||||||
|
initMethod = meth.nimNode
|
||||||
|
break
|
||||||
|
if initMethod.isNil:
|
||||||
|
obj.methods.add(MethodDecl(
|
||||||
|
name: "init",
|
||||||
|
args: newSeq[VarDecl](),
|
||||||
|
returnType: newEmptyNode(),
|
||||||
|
isVirtual: true,
|
||||||
|
isNoGodot: false,
|
||||||
|
nimNode: newProc(postfix(ident("init"), "*"), body = initBody,
|
||||||
|
procType = nnkMethodDef)
|
||||||
|
))
|
||||||
|
else:
|
||||||
|
initMethod.body.insert(0, initBody)
|
||||||
|
|
||||||
|
when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
|
||||||
|
# {.this: self.} for convenience
|
||||||
|
result.add(newNimNode(nnkPragma).add(newNimNode(nnkExprColonExpr).add(
|
||||||
|
ident("this"), ident("self")
|
||||||
|
)))
|
||||||
|
|
||||||
|
# Nim proc defintions
|
||||||
|
var decls = newSeqOfCap[NimNode](obj.methods.len)
|
||||||
|
for meth in obj.methods:
|
||||||
|
let selfArg = newIdentDefs(ident("self"), ident(obj.name))
|
||||||
|
meth.nimNode.params.insert(1, selfArg)
|
||||||
|
let decl = meth.nimNode.copyNimTree()
|
||||||
|
decl.body = newEmptyNode()
|
||||||
|
decl.addPragma(ident("gcsafe"))
|
||||||
|
decl.addPragma(newNimNode(nnkExprColonExpr).add(ident("locks"),
|
||||||
|
newIntLitNode(0)))
|
||||||
|
decls.add(decl)
|
||||||
|
# add forward declarations first
|
||||||
|
for decl in decls:
|
||||||
|
result.add(decl)
|
||||||
|
for meth in obj.methods:
|
||||||
|
result.add(meth.nimNode)
|
||||||
|
|
||||||
|
# Register Godot object
|
||||||
|
let parentName = if obj.parentName.len == 0: newStrLitNode("Object")
|
||||||
|
else: newStrLitNode(obj.parentName)
|
||||||
|
let classNameLit = newStrLitNode(obj.name)
|
||||||
|
let classNameIdent = ident(obj.name)
|
||||||
|
let isRef: bool = if obj.parentName.len == 0: false
|
||||||
|
else: obj.parentName in refClasses
|
||||||
|
# Wrapping bools with a newLit is required as a temporary workaround for
|
||||||
|
# https://github.com/nim-lang/Nim/issues/7375
|
||||||
|
result.add(getAst(
|
||||||
|
registerGodotClass(classNameIdent, classNameLit, newLit(isRef), parentName,
|
||||||
|
genSym(nskProc, "createFunc"), newLit(obj.isTool))))
|
||||||
|
|
||||||
|
# Register fields (properties)
|
||||||
|
for field in obj.fields:
|
||||||
|
if field.isNoGodot: continue
|
||||||
|
let hintStr = if field.hintStr.isNone: "NIM"
|
||||||
|
else: field.hintStr.get
|
||||||
|
let hint = if field.hint.isNone: "NIM"
|
||||||
|
else: field.hint.get
|
||||||
|
let usage =
|
||||||
|
if field.usage.isNil:
|
||||||
|
newLit(ord(GodotPropertyUsage.Default) or
|
||||||
|
ord(GodotPropertyUsage.ScriptVariable))
|
||||||
|
else: field.usage
|
||||||
|
let hasDefaultValue = not field.defaultValue.isNil and
|
||||||
|
field.defaultValue.kind != nnkEmpty
|
||||||
|
let hintIdent = ident(hint)
|
||||||
|
let nimType = repr field.typ
|
||||||
|
result.add(getAst(
|
||||||
|
registerGodotField(classNameLit, classNameIdent,
|
||||||
|
newCStringLit(toGodotStyle($field.name.basename())),
|
||||||
|
ident(field.name), nimType,
|
||||||
|
field.typ, genSym(nskProc, "setFunc"),
|
||||||
|
genSym(nskProc, "getFunc"),
|
||||||
|
newStrLitNode(hintStr), hintIdent, usage,
|
||||||
|
ident($hasDefaultValue), field.defaultValue)))
|
||||||
|
|
||||||
|
# Register methods
|
||||||
|
template registerGodotMethod(classNameLit, classNameIdent, methodNameIdent,
|
||||||
|
methodNameLit, minArgs, maxArgs,
|
||||||
|
argTypes, methFuncIdent, hasReturnValue) =
|
||||||
|
when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
|
||||||
|
{.emit: """/*TYPESECTION*/
|
||||||
|
N_NOINLINE(void, setStackBottom)(void* thestackbottom);
|
||||||
|
""".}
|
||||||
|
|
||||||
|
proc methFuncIdent(obj: ptr GodotObject, methodData: pointer,
|
||||||
|
userData: pointer, numArgs: cint,
|
||||||
|
args: var array[MAX_ARG_COUNT, ptr GodotVariant]):
|
||||||
|
GodotVariant {.noconv.} =
|
||||||
|
var stackBottom {.volatile.}: pointer
|
||||||
|
stackBottom = addr(stackBottom)
|
||||||
|
when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
|
||||||
|
{.emit: """
|
||||||
|
setStackBottom((void*)(&`stackBottom`));
|
||||||
|
""".}
|
||||||
|
else:
|
||||||
|
nimGC_setStackBottom(stackBottom)
|
||||||
|
let self = cast[classNameIdent](userData)
|
||||||
|
const isStaticCall = methodNameLit == cstring"_ready" or
|
||||||
|
methodNameLit == cstring"_process" or
|
||||||
|
methodNameLit == cstring"_fixed_process" or
|
||||||
|
methodNameLit == cstring"_enter_tree" or
|
||||||
|
methodNameLit == cstring"_exit_tree" or
|
||||||
|
methodNameLit == cstring"_enter_world" or
|
||||||
|
methodNameLit == cstring"_exit_world" or
|
||||||
|
methodNameLit == cstring"_draw"
|
||||||
|
when defined(release):
|
||||||
|
invokeVarArgs(methodNameIdent, self, minArgs, maxArgs, numArgs,
|
||||||
|
args, argTypes, hasReturnValue, isStaticCall)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
invokeVarArgs(methodNameIdent, self, minArgs, maxArgs, numArgs,
|
||||||
|
args, argTypes, hasReturnValue, isStaticCall)
|
||||||
|
except:
|
||||||
|
let ex = getCurrentException()
|
||||||
|
printError("Unhandled Nim exception (" & $ex.name & "): " &
|
||||||
|
ex.msg & "\n" & ex.getStackTrace())
|
||||||
|
|
||||||
|
let meth = GodotInstanceMethod(
|
||||||
|
meth: methFuncIdent
|
||||||
|
)
|
||||||
|
nativeScriptRegisterMethod(getNativeLibHandle(), classNameLit,
|
||||||
|
methodNameLit, GodotMethodAttributes(), meth)
|
||||||
|
|
||||||
|
for meth in obj.methods:
|
||||||
|
if meth.isNoGodot: continue
|
||||||
|
let maxArgs = meth.args.len
|
||||||
|
var minArgs = maxArgs
|
||||||
|
var argTypes = newSeq[NimNode]()
|
||||||
|
for idx, arg in meth.args:
|
||||||
|
if minArgs == maxArgs and not arg.defaultValue.isNil and
|
||||||
|
arg.defaultValue.kind != nnkEmpty:
|
||||||
|
minArgs = idx
|
||||||
|
argTypes.add(arg.typ)
|
||||||
|
|
||||||
|
let godotMethodName = if meth.isVirtual: "_" & toGodotStyle(meth.name)
|
||||||
|
else: toGodotStyle(meth.name)
|
||||||
|
let hasReturnValueBool = not (meth.returnType.isNil or
|
||||||
|
meth.returnType.kind == nnkEmpty or
|
||||||
|
(meth.returnType.kind == nnkIdent and
|
||||||
|
meth.returnType.strVal == "void"))
|
||||||
|
let hasReturnValue = if hasReturnValueBool: ident("true")
|
||||||
|
else: ident("false")
|
||||||
|
result.add(getAst(
|
||||||
|
registerGodotMethod(classNameLit, classNameIdent, ident(meth.name),
|
||||||
|
newCStringLit(godotMethodName), minArgs, maxArgs,
|
||||||
|
argTypes, genSym(nskProc, "methFunc"),
|
||||||
|
hasReturnValue)))
|
||||||
|
|
||||||
|
if isRef:
|
||||||
|
# add ref/unref for types inherited from Reference
|
||||||
|
template registerRefIncDec(classNameLit) =
|
||||||
|
let refInc = GodotInstanceMethod(
|
||||||
|
meth: refcountIncremented
|
||||||
|
)
|
||||||
|
let refDec = GodotInstanceMethod(
|
||||||
|
meth: refcountDecremented
|
||||||
|
)
|
||||||
|
nativeScriptRegisterMethod(getNativeLibHandle(), classNameLit,
|
||||||
|
cstring"_refcount_incremented",
|
||||||
|
GodotMethodAttributes(), refInc)
|
||||||
|
nativeScriptRegisterMethod(getNativeLibHandle(), classNameLit,
|
||||||
|
cstring"_refcount_decremented",
|
||||||
|
GodotMethodAttributes(), refDec)
|
||||||
|
result.add(getAst(registerRefIncDec(classNameLit)))
|
||||||
|
|
||||||
|
macro gdobj*(ast: varargs[untyped]): untyped =
|
||||||
|
## Generates Godot type. Self-documenting example:
|
||||||
|
##
|
||||||
|
## .. code-block:: nim
|
||||||
|
## import godot, node
|
||||||
|
##
|
||||||
|
## gdobj MyObj of Node:
|
||||||
|
## var myField: int
|
||||||
|
## ## Not exported to Godot (i.e. editor and scripts will not see this field).
|
||||||
|
##
|
||||||
|
## var myString* {.gdExport, hint: Length, hintStr: "20".}: string
|
||||||
|
## ## Exported to Godot as ``my_string``.
|
||||||
|
## ## Editor will limit this string to length 20.
|
||||||
|
## ## ``hint` is a value of ``GodotPropertyHint`` enum.
|
||||||
|
## ## ``hintStr`` depends on the value of ``hint``, its format is
|
||||||
|
## ## described in ``GodotPropertyHint`` documentation.
|
||||||
|
##
|
||||||
|
## method ready*() =
|
||||||
|
## ## Exported methods are exported to Godot by default,
|
||||||
|
## ## and their Godot names are prefixed with ``_``
|
||||||
|
## ## (in this case ``_ready``)
|
||||||
|
## print("I am ready! myString is: " & self.myString)
|
||||||
|
##
|
||||||
|
## proc myProc*() {.gdExport.} =
|
||||||
|
## ## Exported to Godot as ``my_proc``
|
||||||
|
## print("myProc is called! Incrementing myField.")
|
||||||
|
## inc self.myField
|
||||||
|
##
|
||||||
|
## If parent type is omitted, the type is inherited from ``Object``.
|
||||||
|
##
|
||||||
|
## ``tool`` specifier can be added to mark the type as an
|
||||||
|
## `editor plugin <https://godot.readthedocs.io/en/stable/development/plugins/making_plugins.html>`_:
|
||||||
|
##
|
||||||
|
## .. code-block:: nim
|
||||||
|
## import godot, editor_plugin
|
||||||
|
##
|
||||||
|
## gdobj(MyTool of EditorPlugin, tool):
|
||||||
|
## method enterTree*() =
|
||||||
|
## print("MyTool initialized!")
|
||||||
|
##
|
||||||
|
## Objects can be instantiated by invoking
|
||||||
|
## `gdnew <godotnim.html#gdnew>`_ or by using
|
||||||
|
## `load <godotapi/resource_loader.html#load,string,string,bool>`_ or any other way
|
||||||
|
## that you can find in `Godot API <index.html#modules-godot-api>`_.
|
||||||
|
let typeDef = parseType(ast)
|
||||||
|
result = genType(typeDef)
|
||||||
957
godot/nim/godotnim.nim
Normal file
957
godot/nim/godotnim.nim
Normal file
|
|
@ -0,0 +1,957 @@
|
||||||
|
# Copyright 2018 Xored Software, Inc.
|
||||||
|
|
||||||
|
import tables, typetraits, macros, unicode, strutils, sets, options
|
||||||
|
import gdnativeapi
|
||||||
|
import core/godotcoretypes, core/godotbase
|
||||||
|
import core/vector2, core/rect2,
|
||||||
|
core/vector3, core/transform2d,
|
||||||
|
core/planes, core/quats, core/aabb,
|
||||||
|
core/basis, core/transforms, core/colors,
|
||||||
|
core/nodepaths, core/rids, core/dictionaries,
|
||||||
|
core/arrays, core/poolarrays, core/variants
|
||||||
|
import godotinternal
|
||||||
|
|
||||||
|
## This module defines ``NimGodotObject`` and ``toVariant``/``fromVariant``
|
||||||
|
## converters for Nim types. The converters are used by
|
||||||
|
## `gdobj <godotmacros.html#gdobj.m,untyped,typed>`_ macro to import/export
|
||||||
|
## values from/to Godot (editor, GDScript).
|
||||||
|
##
|
||||||
|
## You can also allow conversion of any custom type ``MyType`` by implementing:
|
||||||
|
##
|
||||||
|
## .. code-block:: nim
|
||||||
|
## proc godotTypeInfo*(T: typedesc[MyType]): GodotTypeInfo
|
||||||
|
## proc toVariant*(self: MyType): Variant
|
||||||
|
## proc fromVariant*(self: var MyType, val: Variant): ConversionResult
|
||||||
|
##
|
||||||
|
## Implementing ``godotTypeInfo`` is optional and is necessary only if you want
|
||||||
|
## the type to be editable from the editor.
|
||||||
|
|
||||||
|
type
|
||||||
|
NimGodotObject* = ref object of RootObj
|
||||||
|
## The base type all Godot types inherit from.
|
||||||
|
## Manages lifecycle of the wrapped ``GodotObject``.
|
||||||
|
godotObject: ptr GodotObject
|
||||||
|
linkedObjectPtr: pointer
|
||||||
|
## Wrapper around native object that is the container of the Nim "script"
|
||||||
|
## This is needed for `of` checks and `as` conversions to work as
|
||||||
|
## expected. For example, Nim type may inherit from ``Spatial``, but the
|
||||||
|
## script is attached to ``Particles``. In this case conversion to
|
||||||
|
## ``Particles`` is valid, but Nim type system is not aware of that.
|
||||||
|
## This works in both directions - for linked native object this
|
||||||
|
## reference points to Nim object.
|
||||||
|
## This is stored as a raw pointer to avoid reference cycles and therefore
|
||||||
|
## improve GC performance.
|
||||||
|
isRef*: bool
|
||||||
|
isFinalized: bool
|
||||||
|
isNative: bool
|
||||||
|
|
||||||
|
ConversionResult* {.pure.} = enum
|
||||||
|
## Conversion result to return from ``fromVariant`` procedure.
|
||||||
|
OK,
|
||||||
|
TypeError,
|
||||||
|
## Type mismatch
|
||||||
|
RangeError
|
||||||
|
## Types match, but the value is out of range.
|
||||||
|
## Mainly used for numeric (ordinal) types.
|
||||||
|
|
||||||
|
SomeUnsignedInt = uint8 or uint16 or uint32 or uint64 or uint or cuint
|
||||||
|
SomeSignedInt = int8 or int16 or int32 or int64 or int or cint
|
||||||
|
SomeFloat = float32 or float64 or cfloat
|
||||||
|
|
||||||
|
SomeGodot = bool or Vector2 or Rect2 or Vector3 or
|
||||||
|
Transform2D or Plane or Quat or AABB or
|
||||||
|
Basis or Transform or Color or NodePath or
|
||||||
|
RID or GodotObject or Dictionary or Array or
|
||||||
|
PoolByteArray or PoolIntArray or PoolRealArray or
|
||||||
|
PoolStringArray or PoolVector2Array or PoolVector3Array or
|
||||||
|
PoolColorArray or GodotString
|
||||||
|
|
||||||
|
SomeGodotOrNum = SomeGodot or SomeSignedInt or SomeUnsignedInt or SomeFloat
|
||||||
|
|
||||||
|
CallError* = object of Exception
|
||||||
|
## Raised by wrappers in case of an incorrect dynamic invocation.
|
||||||
|
## For example, if incorrect number of arguments were passed or they had
|
||||||
|
## unexpected types.
|
||||||
|
err*: VariantCallError
|
||||||
|
## The error as returned by Godot
|
||||||
|
|
||||||
|
ObjectInfo = object
|
||||||
|
constructor: proc(): NimGodotObject {.gcsafe, nimcall.}
|
||||||
|
baseNativeClass: cstring
|
||||||
|
isNative: bool
|
||||||
|
isRef: bool
|
||||||
|
|
||||||
|
GodotTypeInfo* = object
|
||||||
|
## Type information provided to Godot editor
|
||||||
|
variantType*: VariantType
|
||||||
|
hint*: GodotPropertyHint
|
||||||
|
hintStr*: string
|
||||||
|
## Format depends on the type and the hint.
|
||||||
|
## For example, for Enum ``hint`` this is a comma separated list of
|
||||||
|
## values.
|
||||||
|
## See documentation of ``GodotPropertyHint`` for description of formats.
|
||||||
|
|
||||||
|
FNV1Hash = uint32
|
||||||
|
|
||||||
|
include "internal/backwardcompat.inc.nim"
|
||||||
|
|
||||||
|
proc isFinalized*(obj: NimGodotObject): bool {.inline.} =
|
||||||
|
obj.isFinalized
|
||||||
|
|
||||||
|
var classRegistry {.threadvar.}: TableRef[FNV1Hash, ObjectInfo]
|
||||||
|
var classRegistryStatic* {.compileTime.}: TableRef[FNV1Hash, ObjectInfo]
|
||||||
|
## Compile-time variable used for implementation of several procedures
|
||||||
|
## and macros
|
||||||
|
static:
|
||||||
|
classRegistryStatic = newTable[FNV1Hash, ObjectInfo]()
|
||||||
|
|
||||||
|
var nativeClasses {.compileTime.} = newSeq[string]()
|
||||||
|
var refClasses* {.compileTime.} = newSeq[string]()
|
||||||
|
|
||||||
|
template initFNV1Hash(hash: var FNV1Hash) =
|
||||||
|
hash = 0x811c9dc5'u32
|
||||||
|
|
||||||
|
template appendFNV1Hash(hash: var FNV1Hash, val: uint8) =
|
||||||
|
block:
|
||||||
|
let u64hash = hash.uint64
|
||||||
|
hash = ((
|
||||||
|
u64hash +
|
||||||
|
(u64hash shl 1'u64) +
|
||||||
|
(u64hash shl 4'u64) +
|
||||||
|
(u64hash shl 7'u64) +
|
||||||
|
(u64hash shl 8'u64) +
|
||||||
|
(u64hash shl 24'u64)) and 0xFFFFFFFF'u32).uint32 xor val
|
||||||
|
|
||||||
|
{.push stackTrace:off.}
|
||||||
|
proc lsb(c: ptr cwchar_t): char {.noinit, inline.} =
|
||||||
|
{.emit: [result, " = (char)(", c[]," & 0xFF);"]}
|
||||||
|
{.pop.}
|
||||||
|
|
||||||
|
proc fnv1Hash(godotClassName: GodotString): FNV1Hash =
|
||||||
|
var charsCount = godotClassName.len
|
||||||
|
let charsPtr = godotClassName.dataPtr
|
||||||
|
if charsCount > 2 and
|
||||||
|
charsPtr.offset(charsCount - 2).lsb == 'S' and
|
||||||
|
charsPtr.offset(charsCount - 1).lsb == 'W':
|
||||||
|
charsCount -= 2
|
||||||
|
|
||||||
|
initFNV1Hash(result)
|
||||||
|
for i in 0..<charsCount:
|
||||||
|
let c = charsPtr.offset(i).lsb
|
||||||
|
appendFNV1Hash(result, c.uint8)
|
||||||
|
|
||||||
|
proc fnv1Hash(godotClassName: string): FNV1Hash {.compileTime.} =
|
||||||
|
var charsCount = godotClassName.len
|
||||||
|
if godotClassName.endsWith("SW"):
|
||||||
|
charsCount -= 2
|
||||||
|
|
||||||
|
initFNV1Hash(result)
|
||||||
|
var i = 0
|
||||||
|
for rune in runes(godotClassName):
|
||||||
|
if i >= charsCount:
|
||||||
|
break
|
||||||
|
let firstByte = uint8(rune.uint64 and 0xFF'u64)
|
||||||
|
appendFNV1Hash(result, firstByte)
|
||||||
|
# We don't really need to calculate hash of other bytes,
|
||||||
|
# since we only use hashes of ASCII strings
|
||||||
|
inc i
|
||||||
|
|
||||||
|
proc getClassName*(o: NimGodotObject): string =
|
||||||
|
o.godotObject.getClassName()
|
||||||
|
|
||||||
|
var unreferenceMethodBind {.threadvar.}: ptr GodotMethodBind
|
||||||
|
proc unreference(o: ptr GodotObject): bool =
|
||||||
|
if isNil(unreferenceMethodBind):
|
||||||
|
unreferenceMethodBind = getMethod(cstring"Reference",
|
||||||
|
cstring"unreference")
|
||||||
|
unreferenceMethodBind.ptrCall(o, nil, addr(result))
|
||||||
|
|
||||||
|
var referenceMethodBind {.threadvar.}: ptr GodotMethodBind
|
||||||
|
proc reference(o: ptr GodotObject): bool {.discardable.} =
|
||||||
|
if isNil(referenceMethodBind):
|
||||||
|
referenceMethodBind = getMethod(cstring"Reference",
|
||||||
|
cstring"reference")
|
||||||
|
referenceMethodBind.ptrCall(o, nil, addr result)
|
||||||
|
|
||||||
|
var initRefMethodBind {.threadvar.}: ptr GodotMethodBind
|
||||||
|
proc initRef(o: ptr GodotObject): bool {.discardable.} =
|
||||||
|
if isNil(initRefMethodBind):
|
||||||
|
initRefMethodBind = getMethod(cstring"Reference",
|
||||||
|
cstring"init_ref")
|
||||||
|
initRefMethodBind.ptrCall(o, nil, addr result)
|
||||||
|
|
||||||
|
proc deinit*(obj: NimGodotObject) =
|
||||||
|
## Destroy the object. You only need to call this for objects not inherited
|
||||||
|
## from Reference, where manual lifecycle control is necessary.
|
||||||
|
assert(not obj.godotObject.isNil)
|
||||||
|
obj.godotObject.deinit()
|
||||||
|
obj.godotObject = nil
|
||||||
|
|
||||||
|
proc linkedObject(obj: NimGodotObject): NimGodotObject {.inline.} =
|
||||||
|
cast[NimGodotObject](obj.linkedObjectPtr)
|
||||||
|
|
||||||
|
proc nimGodotObjectFinalizer*[T: NimGodotObject](obj: T) =
|
||||||
|
if obj.godotObject.isNil or obj.isNative: return
|
||||||
|
# important to set it before so that ``unreference`` is aware
|
||||||
|
obj.isFinalized = true
|
||||||
|
if (obj.isRef or not obj.linkedObject.isNil and obj.linkedObject.isRef) and
|
||||||
|
obj.godotObject.unreference():
|
||||||
|
obj.deinit()
|
||||||
|
|
||||||
|
macro baseNativeType(T: typedesc): cstring =
|
||||||
|
var t = getType(getType(T)[1][1])
|
||||||
|
var baseT: string
|
||||||
|
while true:
|
||||||
|
let typeName = ($t[1][1]).split(':')[0]
|
||||||
|
if typeName in nativeClasses:
|
||||||
|
baseT = typeName
|
||||||
|
break
|
||||||
|
if typeName == "NimGodotObject":
|
||||||
|
break
|
||||||
|
t = getType(t[1][1])
|
||||||
|
if baseT.len == 0:
|
||||||
|
result = newNilLit()
|
||||||
|
else:
|
||||||
|
let rStr = newNimNode(nnkRStrLit)
|
||||||
|
rStr.strVal = baseT
|
||||||
|
result = newNimNode(nnkCallStrLit).add(ident("cstring"), rStr)
|
||||||
|
|
||||||
|
proc inherits(t: NimNode, parent: string): bool {.compileTime.} =
|
||||||
|
var curT = t
|
||||||
|
while true:
|
||||||
|
let typeName = ($curT[1][1]).split(':')[0]
|
||||||
|
if typeName == parent:
|
||||||
|
return true
|
||||||
|
if typeName == "NimGodotObject":
|
||||||
|
break
|
||||||
|
curT = getType(curT[1][1])
|
||||||
|
|
||||||
|
macro isReference(T: typedesc): bool =
|
||||||
|
result = if inherits(getType(T), "Reference"): ident("true")
|
||||||
|
else: ident("false")
|
||||||
|
|
||||||
|
macro isResource(T: typedesc): bool =
|
||||||
|
result = if inherits(getType(T), "Resource"): ident("true")
|
||||||
|
else: ident("false")
|
||||||
|
|
||||||
|
template registerClass*(T: typedesc; godotClassName: string or cstring,
|
||||||
|
native: bool) =
|
||||||
|
## Registers the specified Godot type.
|
||||||
|
## Used by ``gdobj`` macro and `godotapigen <godotapigen.html>`_.
|
||||||
|
if classRegistry.isNil:
|
||||||
|
classRegistry = newTable[FNV1Hash, ObjectInfo]()
|
||||||
|
let constructor = proc(): NimGodotObject =
|
||||||
|
var t: T
|
||||||
|
new(t, nimGodotObjectFinalizer[T])
|
||||||
|
result = t
|
||||||
|
|
||||||
|
const base = baseNativeType(T)
|
||||||
|
const isRef: bool = isReference(T)
|
||||||
|
let objInfo = ObjectInfo(
|
||||||
|
constructor: constructor,
|
||||||
|
baseNativeClass: base,
|
||||||
|
isNative: native,
|
||||||
|
isRef: isRef
|
||||||
|
)
|
||||||
|
classRegistry[fnv1Hash($godotClassName)] = objInfo
|
||||||
|
static:
|
||||||
|
let objInfoStatic = ObjectInfo(
|
||||||
|
baseNativeClass: base,
|
||||||
|
isNative: native,
|
||||||
|
isRef: isRef,
|
||||||
|
)
|
||||||
|
let nameHash = fnv1Hash($godotClassName)
|
||||||
|
if not classRegistryStatic.contains(nameHash):
|
||||||
|
classRegistryStatic[nameHash] = objInfoStatic
|
||||||
|
elif not endsWith($godotClassName, "SW"):
|
||||||
|
# For simplicity we assume that all class names must have
|
||||||
|
# different hashes
|
||||||
|
# If this exception is ever raised, I guess, we should
|
||||||
|
# implement a proper collision resolving
|
||||||
|
raise newException(Exception, "Hash collision " & $godotClassName)
|
||||||
|
when isRef:
|
||||||
|
static:
|
||||||
|
refClasses.add(T.name)
|
||||||
|
when native:
|
||||||
|
static:
|
||||||
|
nativeClasses.add(T.name)
|
||||||
|
|
||||||
|
proc newNimGodotObject[T: NimGodotObject](
|
||||||
|
godotObject: ptr GodotObject, godotClassName: GodotString, noRef: bool): T =
|
||||||
|
assert(not classRegistry.isNil)
|
||||||
|
assert(not godotObject.isNil)
|
||||||
|
let objInfo = classRegistry.getOrDefault(fnv1Hash(godotClassName))
|
||||||
|
if objInfo.constructor.isNil:
|
||||||
|
printError("Nim constructor not found for class " & $godotClassName)
|
||||||
|
else:
|
||||||
|
result = T(objInfo.constructor())
|
||||||
|
result.godotObject = godotObject
|
||||||
|
result.isRef = objInfo.isRef
|
||||||
|
if not noRef and objInfo.isRef:
|
||||||
|
result.godotObject.reference()
|
||||||
|
|
||||||
|
proc asNimGodotObject*[T: NimGodotObject](
|
||||||
|
godotObject: ptr GodotObject, forceNativeObject, noRef: bool = false): T =
|
||||||
|
## Wraps ``godotObject`` into Nim type ``T``.
|
||||||
|
## This is used by `godotapigen <godotapigen.html>`_ and should rarely be
|
||||||
|
## used by anything else.
|
||||||
|
if godotObject.isNil: return nil
|
||||||
|
let userDataPtr = godotObject.getUserData()
|
||||||
|
if not userDataPtr.isNil and not forceNativeObject:
|
||||||
|
result = cast[T](userDataPtr)
|
||||||
|
if result.godotObject != godotObject:
|
||||||
|
# Could be data from other bindings
|
||||||
|
result = nil
|
||||||
|
if result.isNil:
|
||||||
|
var classNameStr = godotObject.getClassNameRaw()
|
||||||
|
result = newNimGodotObject[T](
|
||||||
|
godotObject, classNameStr,
|
||||||
|
forceNativeObject or noRef)
|
||||||
|
deinit(classNameStr)
|
||||||
|
|
||||||
|
proc newVariant*(obj: NimGodotObject): Variant {.inline.} =
|
||||||
|
newVariant(obj.godotObject)
|
||||||
|
|
||||||
|
proc asObject*[T: NimGodotObject](v: Variant): T {.inline.} =
|
||||||
|
## Converts ``v`` to object of type ``T``.
|
||||||
|
## Returns ``nil`` if the conversion cannot be performed
|
||||||
|
## (``v``'s type is not an Object or it's an object of an incompatible type)
|
||||||
|
asNimGodotObject[T](v.asGodotObject())
|
||||||
|
|
||||||
|
proc asObject*(v: Variant, T: typedesc[NimGodotObject]): T {.inline.} =
|
||||||
|
## Converts ``v`` to object of type ``T``.
|
||||||
|
## Returns ``nil`` if the conversion cannot be performed
|
||||||
|
## (``v``'s type is not an Object or it's an object of an incompatible type)
|
||||||
|
asNimGodotObject[T](v.asGodotObject())
|
||||||
|
|
||||||
|
proc `as`*[T: NimGodotObject](obj: NimGodotObject, t: typedesc[T]): T =
|
||||||
|
## Converts the ``obj`` into the specified type.
|
||||||
|
## Returns ``nil`` if the conversion cannot be performed
|
||||||
|
## (the ``obj`` is not of the type ``T``)
|
||||||
|
##
|
||||||
|
## This can be used either in dot notation (``node.as(Button)``) or
|
||||||
|
## infix notation (``node as Button``).
|
||||||
|
if obj.isNil: return nil
|
||||||
|
if system.`of`(obj, T):
|
||||||
|
result = T(obj)
|
||||||
|
elif not obj.linkedObject.isNil and system.`of`(obj.linkedObject, T):
|
||||||
|
result = T(obj.linkedObject)
|
||||||
|
else:
|
||||||
|
result = nil
|
||||||
|
|
||||||
|
proc `of`*[T1, T2: NimGodotObject](obj: T1, t: typedesc[T2]): bool {.inline.} =
|
||||||
|
## Godot-specific inheritance check.
|
||||||
|
not obj.isNil and (system.`of`(obj, T2) or system.`of`(obj.linkedObject, T2))
|
||||||
|
|
||||||
|
proc newRStrLit(s: string): NimNode {.compileTime.} =
|
||||||
|
result = newNimNode(nnkRStrLit)
|
||||||
|
result.strVal = s
|
||||||
|
|
||||||
|
macro toGodotName(T: typedesc): untyped =
|
||||||
|
if T is GodotString or T is string:
|
||||||
|
newStrLitNode"String"
|
||||||
|
elif T is SomeFloat:
|
||||||
|
newStrLitNode"float"
|
||||||
|
elif T is SomeUnsignedInt or T is SomeSignedInt:
|
||||||
|
newStrLitNode"int"
|
||||||
|
else:
|
||||||
|
let nameStr = ((T.getType()[1][1].strVal).split(':')[0])
|
||||||
|
case nameStr:
|
||||||
|
of "File", "Directory", "Thread", "Mutex", "Semaphore":
|
||||||
|
newStrLitNode("_" & nameStr)
|
||||||
|
else:
|
||||||
|
newStrLitNode(nameStr)
|
||||||
|
|
||||||
|
macro asCString(s: static[string]): cstring =
|
||||||
|
result = newNimNode(nnkCallStrLit).add(
|
||||||
|
ident("cstring"), newRStrLit(s))
|
||||||
|
|
||||||
|
proc getSingleton*[T: NimGodotObject](): T =
|
||||||
|
## Returns singleton of type ``T``. Normally, this should not be used,
|
||||||
|
## because `godotapigen <godotapigen.html>`_ wraps singleton methods so that
|
||||||
|
## singleton objects don't have to be provided as parameters.
|
||||||
|
const godotName = asCString(toGodotName(T))
|
||||||
|
let singleton = getGodotSingleton(godotName)
|
||||||
|
if singleton.isNil:
|
||||||
|
printError("Tried to get non-existing singleton of type " & $godotName)
|
||||||
|
else:
|
||||||
|
result = asNimGodotObject[T](singleton)
|
||||||
|
|
||||||
|
var gdNativeLibraryObj: ptr GodotObject
|
||||||
|
|
||||||
|
var setClassNameMethod: ptr GodotMethodBind
|
||||||
|
var setLibraryMethod: ptr GodotMethodBind
|
||||||
|
var newMethod: ptr GodotMethodBind
|
||||||
|
type
|
||||||
|
PtrCallArgType = ptr array[MAX_ARG_COUNT, pointer]
|
||||||
|
proc newOwnObj[T: NimGodotObject](name: cstring): T =
|
||||||
|
let newNativeScript = getClassConstructor(cstring"NativeScript")()
|
||||||
|
if setClassNameMethod.isNil:
|
||||||
|
setClassNameMethod =
|
||||||
|
getMethod(cstring"NativeScript", cstring"set_class_name")
|
||||||
|
if setLibraryMethod.isNil:
|
||||||
|
setLibraryMethod =
|
||||||
|
getMethod(cstring"NativeScript", cstring"set_library")
|
||||||
|
if newMethod.isNil:
|
||||||
|
newMethod = getMethod(cstring"NativeScript", cstring"new")
|
||||||
|
var godotStrName = name.toGodotString()
|
||||||
|
var argPtr: pointer = addr godotStrName
|
||||||
|
setClassNameMethod.ptrCall(
|
||||||
|
newNativeScript, cast[PtrCallArgType](addr argPtr), nil)
|
||||||
|
deinit(godotStrName)
|
||||||
|
setLibraryMethod.ptrCall(
|
||||||
|
newNativeScript, cast[PtrCallArgType](addr gdNativeLibraryObj), nil)
|
||||||
|
|
||||||
|
var err: VariantCallError
|
||||||
|
var ret = newMethod.call(newNativeScript, nil, 0, err)
|
||||||
|
if err.error != VariantCallErrorType.OK:
|
||||||
|
printError("Failed to invoke 'new' on NativeScript for " & $name)
|
||||||
|
elif ret.getType() != VariantType.Object:
|
||||||
|
printError("Expected that NativeScript::new returns Object, " &
|
||||||
|
"but it returned: " & $ret.getType())
|
||||||
|
else:
|
||||||
|
result = asNimGodotObject[T](ret.asGodotObject())
|
||||||
|
if result.isRef:
|
||||||
|
result.isFinalized = true
|
||||||
|
result.godotObject.reference()
|
||||||
|
result.isFinalized = false
|
||||||
|
ret.deinit()
|
||||||
|
|
||||||
|
proc gdnew*[T: NimGodotObject](): T =
|
||||||
|
## Instantiates new object of type ``T``.
|
||||||
|
const godotName = toGodotName(T)
|
||||||
|
const cGodotName = asCString(godotName)
|
||||||
|
const objInfo = classRegistryStatic[fnv1Hash(godotName)]
|
||||||
|
when objInfo.isNative:
|
||||||
|
let godotObject = getClassConstructor(cGodotName)()
|
||||||
|
new(result, nimGodotObjectFinalizer[T])
|
||||||
|
result.godotObject = godotObject
|
||||||
|
when objInfo.isRef:
|
||||||
|
godotObject.initRef()
|
||||||
|
result.isRef = true
|
||||||
|
else:
|
||||||
|
result = newOwnObj[T](cGodotName)
|
||||||
|
|
||||||
|
proc newCallError*(err: VariantCallError): ref CallError =
|
||||||
|
## Instantiates ``CallError`` from Godot ``err``.
|
||||||
|
let msg = case err.error:
|
||||||
|
of VariantCallErrorType.OK,
|
||||||
|
VariantCallErrorType.InvalidMethod,
|
||||||
|
VariantCallErrorType.TooManyArguments,
|
||||||
|
VariantCallErrorType.TooFewArguments,
|
||||||
|
VariantCallErrorType.InstanceIsNull:
|
||||||
|
$err.error
|
||||||
|
of VariantCallErrorType.InvalidArgument:
|
||||||
|
"invalid argument at position " & $err.argument & ": expected " &
|
||||||
|
$err.expected
|
||||||
|
|
||||||
|
result = newException(CallError, msg)
|
||||||
|
result.err = err
|
||||||
|
|
||||||
|
proc newConversionError*(err: ConversionResult): ref ValueError =
|
||||||
|
## Instantiates error raised by `godotapigen <godotapigen.html>`_
|
||||||
|
## generated code in case of a conversion error.
|
||||||
|
let msg = case err:
|
||||||
|
of ConversionResult.TypeError:
|
||||||
|
"Failed to convert the return value into Nim type"
|
||||||
|
of ConversionResult.RangeError:
|
||||||
|
"The returned value was out of bounds"
|
||||||
|
of ConversionResult.OK:
|
||||||
|
"OK"
|
||||||
|
|
||||||
|
result = newException(ValueError, msg)
|
||||||
|
|
||||||
|
proc setGodotObject*(nimObj: NimGodotObject, obj: ptr GodotObject) {.inline.} =
|
||||||
|
## Used from Godot constructor produced by ``gdobj`` macro. Do not call.
|
||||||
|
assert(not obj.isNil)
|
||||||
|
assert(nimObj.godotObject.isNil) # reassignment is not allowed
|
||||||
|
nimObj.godotObject = obj
|
||||||
|
|
||||||
|
proc setNativeObject*(nimObj: NimGodotObject,
|
||||||
|
nativeObj: NimGodotObject) {.inline.} =
|
||||||
|
## Used from Godot constructor produced by ``gdobj`` macro. Do not call.
|
||||||
|
GC_ref(nativeObj)
|
||||||
|
nimObj.linkedObjectPtr = cast[pointer](nativeObj)
|
||||||
|
nativeObj.linkedObjectPtr = cast[pointer](nimObj)
|
||||||
|
nativeObj.isNative = true
|
||||||
|
|
||||||
|
proc removeGodotObject*(nimObj: NimGodotObject) {.inline.} =
|
||||||
|
## Used from Godot destructor produced by ``gdobj`` macro. Do not call.
|
||||||
|
GC_unref(nimObj.linkedObject)
|
||||||
|
nimObj.godotObject = nil
|
||||||
|
nimObj.linkedObject.godotObject = nil
|
||||||
|
nimObj.linkedObjectPtr = nil
|
||||||
|
|
||||||
|
proc `==`*(self, other: NimGodotObject): bool {.inline.} =
|
||||||
|
## Compares objects by referential equality.
|
||||||
|
if self.isNil and other.isNil: return true
|
||||||
|
if self.isNil != other.isNil: return false
|
||||||
|
result = (self.godotObject == other.godotObject)
|
||||||
|
|
||||||
|
proc godotObject*(nimObj: NimGodotObject): ptr GodotObject {.inline.} =
|
||||||
|
## Returns raw poitner to ``GodotObject``. Use only if you know what
|
||||||
|
## you are doing.
|
||||||
|
nimObj.godotObject
|
||||||
|
|
||||||
|
proc godotTypeInfo*(T: typedesc[NimGodotObject]): GodotTypeInfo {.inline.} =
|
||||||
|
GodotTypeInfo(
|
||||||
|
variantType: VariantType.Object,
|
||||||
|
hint: when isResource(T): GodotPropertyHint.ResourceType
|
||||||
|
else: GodotPropertyHint.None,
|
||||||
|
hintStr: toGodotName(T)
|
||||||
|
)
|
||||||
|
|
||||||
|
proc toVariant*(self: NimGodotObject): Variant {.inline.} =
|
||||||
|
if self.isNil:
|
||||||
|
newVariant()
|
||||||
|
else:
|
||||||
|
newVariant(self.godotObject)
|
||||||
|
|
||||||
|
proc fromVariant*[T: NimGodotObject](self: var T,
|
||||||
|
val: Variant): ConversionResult =
|
||||||
|
if val.getType() == VariantType.Object:
|
||||||
|
let objPtr = val.asGodotObject()
|
||||||
|
self = asNimGodotObject[T](objPtr)
|
||||||
|
if self.isNil:
|
||||||
|
result = ConversionResult.TypeError
|
||||||
|
elif val.getType() == VariantType.Nil:
|
||||||
|
self = nil
|
||||||
|
else:
|
||||||
|
result = ConversionResult.TypeError
|
||||||
|
|
||||||
|
proc toVariant*(self: Variant): Variant {.inline.} =
|
||||||
|
if self.isNil:
|
||||||
|
newVariant()
|
||||||
|
else:
|
||||||
|
newVariant(self)
|
||||||
|
|
||||||
|
proc fromVariant*(self: var Variant,
|
||||||
|
val: Variant): ConversionResult {.inline.} =
|
||||||
|
self = newVariant(val)
|
||||||
|
|
||||||
|
proc godotTypeInfo*(T: typedesc[SomeGodotOrNum]): GodotTypeInfo {.inline.} =
|
||||||
|
result.variantType =
|
||||||
|
when T is SomeSignedInt or T is SomeUnsignedInt:
|
||||||
|
VariantType.Int
|
||||||
|
elif T is bool:
|
||||||
|
VariantType.Bool
|
||||||
|
elif T is SomeFloat:
|
||||||
|
VariantType.Real
|
||||||
|
elif T is string or T is GodotString:
|
||||||
|
VariantType.String
|
||||||
|
elif T is Vector2:
|
||||||
|
VariantType.Vector2
|
||||||
|
elif T is Rect2:
|
||||||
|
VariantType.Rect2
|
||||||
|
elif T is Vector3:
|
||||||
|
VariantType.Vector3
|
||||||
|
elif T is Transform2D:
|
||||||
|
VariantType.Transform2D
|
||||||
|
elif T is Plane:
|
||||||
|
VariantType.Plane
|
||||||
|
elif T is Quat:
|
||||||
|
VariantType.Quat
|
||||||
|
elif T is AABB:
|
||||||
|
VariantType.AABB
|
||||||
|
elif T is Basis:
|
||||||
|
VariantType.Basis
|
||||||
|
elif T is Transform:
|
||||||
|
VariantType.Transform
|
||||||
|
elif T is Color:
|
||||||
|
VariantType.Color
|
||||||
|
elif T is RID:
|
||||||
|
VariantType.RID
|
||||||
|
elif T is ptr GodotObject:
|
||||||
|
VariantType.Object
|
||||||
|
elif T is NodePath:
|
||||||
|
VariantType.NodePath
|
||||||
|
elif T is Dictionary:
|
||||||
|
VariantType.Dictionary
|
||||||
|
elif T is Array:
|
||||||
|
VariantType.Array
|
||||||
|
elif T is PoolByteArray:
|
||||||
|
VariantType.PoolByteArray
|
||||||
|
elif T is PoolIntArray:
|
||||||
|
VariantType.PoolIntArray
|
||||||
|
elif T is PoolRealArray:
|
||||||
|
VariantType.PoolRealArray
|
||||||
|
elif T is PoolStringArray:
|
||||||
|
VariantType.PoolStringArray
|
||||||
|
elif T is PoolVector2Array:
|
||||||
|
VariantType.PoolVector2Array
|
||||||
|
elif T is PoolVector3Array:
|
||||||
|
VariantType.PoolVector3Array
|
||||||
|
elif T is PoolColorArray:
|
||||||
|
VariantType.PoolColorArray
|
||||||
|
else:
|
||||||
|
VariantType.Nil
|
||||||
|
|
||||||
|
proc godotTypeInfo*(T: typedesc[range]): VariantType {.inline.} =
|
||||||
|
GodotTypeInfo(
|
||||||
|
variantType: VariantType.Int,
|
||||||
|
hint: GodotPropertyHint.Range,
|
||||||
|
hintStr: $low(T) & "," & $high(T) & ",1"
|
||||||
|
)
|
||||||
|
|
||||||
|
proc toVariant*[T: SomeGodotOrNum](val: T): Variant {.inline.} =
|
||||||
|
when val is ref:
|
||||||
|
if val.isNil:
|
||||||
|
newVariant()
|
||||||
|
else:
|
||||||
|
newVariant(val)
|
||||||
|
else:
|
||||||
|
newVariant(val)
|
||||||
|
|
||||||
|
proc fromVariant*[T: SomeSignedInt or SomeUnsignedInt](
|
||||||
|
self: var T, val: Variant): ConversionResult =
|
||||||
|
if val.getType() == VariantType.Nil:
|
||||||
|
self = 0
|
||||||
|
elif val.getType() == VariantType.Int or val.getType() == VariantType.Real:
|
||||||
|
# Real is allowed, because that's what the editor sets for Int values
|
||||||
|
var intVal: (when T is SomeSignedInt: int64
|
||||||
|
else: uint64)
|
||||||
|
intVal = when T is SomeSignedInt: val.asInt()
|
||||||
|
else: val.asUint()
|
||||||
|
const highT = when T is SomeSignedInt: high(T).int64
|
||||||
|
else: high(T).uint64
|
||||||
|
const lowT = when T is SomeSignedInt: low(T).int64
|
||||||
|
else: low(T).uint64
|
||||||
|
if intVal > highT or intVal < lowT:
|
||||||
|
result = ConversionResult.RangeError
|
||||||
|
else:
|
||||||
|
self = T(intVal)
|
||||||
|
else:
|
||||||
|
result = ConversionResult.TypeError
|
||||||
|
|
||||||
|
proc godotTypeInfo*(T: typedesc[enum]): GodotTypeInfo =
|
||||||
|
result = GodotTypeInfo(
|
||||||
|
variantType: VariantType.Int,
|
||||||
|
hint: GodotPropertyHint.Enum,
|
||||||
|
hintStr: ""
|
||||||
|
)
|
||||||
|
for val in T:
|
||||||
|
if result.hintStr.len > 0:
|
||||||
|
result.hintStr.add(',')
|
||||||
|
result.hintStr.add($val)
|
||||||
|
|
||||||
|
proc toVariant*[T: enum](self: T): Variant {.inline.} =
|
||||||
|
newVariant(int64(ord(self)))
|
||||||
|
|
||||||
|
proc fromVariant*[T: enum](self: var T,
|
||||||
|
val: Variant): ConversionResult {.inline.} =
|
||||||
|
var intConv: int64
|
||||||
|
result = fromVariant(intConv, val)
|
||||||
|
if result == ConversionResult.OK:
|
||||||
|
self = T(intConv)
|
||||||
|
|
||||||
|
proc fromVariant*[T: SomeFloat](self: var T, val: Variant): ConversionResult =
|
||||||
|
if val.getType() == VariantType.Nil:
|
||||||
|
self = 0
|
||||||
|
elif val.getType() == VariantType.Real or val.getType() == VariantType.Int:
|
||||||
|
self = T(val.asReal())
|
||||||
|
else:
|
||||||
|
result = ConversionResult.TypeError
|
||||||
|
|
||||||
|
proc fromVariant*[T: SomeGodot](self: var T, val: Variant): ConversionResult =
|
||||||
|
if val.getType() == VariantType.Nil:
|
||||||
|
return
|
||||||
|
const typeInfo = godotTypeInfo(T)
|
||||||
|
if typeInfo.variantType != val.getType():
|
||||||
|
return ConversionResult.TypeError
|
||||||
|
when self is bool:
|
||||||
|
self = val.asBool()
|
||||||
|
elif self is Vector2:
|
||||||
|
self = val.asVector2()
|
||||||
|
elif self is Rect2:
|
||||||
|
self = val.asRect2()
|
||||||
|
elif self is Vector3:
|
||||||
|
self = val.asVector3()
|
||||||
|
elif self is Transform2D:
|
||||||
|
self = val.asTransform2D()
|
||||||
|
elif self is Plane:
|
||||||
|
self = val.asPlane()
|
||||||
|
elif self is Quat:
|
||||||
|
self = val.asQuat()
|
||||||
|
elif self is AABB:
|
||||||
|
self = val.asAABB()
|
||||||
|
elif self is Basis:
|
||||||
|
self = val.asBasis()
|
||||||
|
elif self is Transform:
|
||||||
|
self = val.asTransform()
|
||||||
|
elif self is Color:
|
||||||
|
self = val.asColor()
|
||||||
|
elif self is NodePath:
|
||||||
|
self = val.asNodePath()
|
||||||
|
elif self is RID:
|
||||||
|
self = val.asRID()
|
||||||
|
elif self is ptr GodotObject:
|
||||||
|
self = val.asObject()
|
||||||
|
elif self is Dictionary:
|
||||||
|
self = val.asDictionary()
|
||||||
|
elif self is Array:
|
||||||
|
self = val.asArray()
|
||||||
|
elif self is PoolByteArray:
|
||||||
|
self = val.asPoolByteArray()
|
||||||
|
elif self is PoolIntArray:
|
||||||
|
self = val.asPoolIntArray()
|
||||||
|
elif self is PoolRealArray:
|
||||||
|
self = val.asPoolRealArray()
|
||||||
|
elif self is PoolStringArray:
|
||||||
|
self = val.asPoolStringArray()
|
||||||
|
elif self is PoolVector2Array:
|
||||||
|
self = val.asPoolVector2Array()
|
||||||
|
elif self is PoolVector3Array:
|
||||||
|
self = val.asPoolVector3Array()
|
||||||
|
elif self is PoolColorArray:
|
||||||
|
self = val.asPoolColorArray()
|
||||||
|
elif self is GodotString:
|
||||||
|
self = val.asGodotString()
|
||||||
|
else:
|
||||||
|
# mustn't reach this
|
||||||
|
result = ConversionError.TypeError
|
||||||
|
|
||||||
|
proc godotTypeInfo*(T: typedesc[string]): GodotTypeInfo {.inline.} =
|
||||||
|
result.variantType = VariantType.String
|
||||||
|
|
||||||
|
proc toVariant*(s: string): Variant {.inline.} =
|
||||||
|
newVariant(s)
|
||||||
|
|
||||||
|
proc fromVariant*(s: var string, val: Variant): ConversionResult =
|
||||||
|
if val.getType() == VariantType.String:
|
||||||
|
s = val.asString()
|
||||||
|
elif val.getType() == VariantType.Nil:
|
||||||
|
when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
|
||||||
|
s = nil
|
||||||
|
else:
|
||||||
|
s = ""
|
||||||
|
else:
|
||||||
|
result = ConversionResult.TypeError
|
||||||
|
|
||||||
|
template arrTypeInfo(T) =
|
||||||
|
result.variantType = VariantType.Array
|
||||||
|
mixin godotTypeInfo
|
||||||
|
type ItemT = type((
|
||||||
|
block:
|
||||||
|
var s: T;
|
||||||
|
when T is seq: s[0] else: s[low(s)]))
|
||||||
|
when compiles(godotTypeInfo(ItemT)):
|
||||||
|
let itemTypeInfo = godotTypeInfo(ItemT)
|
||||||
|
result.hintStr = $ord(itemTypeInfo.variantType)
|
||||||
|
result.hintStr.add('/')
|
||||||
|
result.hintStr.add($ord(itemTypeInfo.hint))
|
||||||
|
result.hintStr.add(':')
|
||||||
|
if not itemTypeInfo.hintStr.isNil:
|
||||||
|
result.hintStr.add(itemTypeInfo.hintStr)
|
||||||
|
|
||||||
|
proc godotTypeInfo*(T: typedesc[seq]): GodotTypeInfo =
|
||||||
|
arrTypeInfo(T)
|
||||||
|
|
||||||
|
proc godotTypeInfo*(T: typedesc[array]): GodotTypeInfo =
|
||||||
|
arrTypeInfo(T)
|
||||||
|
|
||||||
|
template arrayToVariant(s: untyped): Variant =
|
||||||
|
var arr = newArray()
|
||||||
|
mixin toVariant
|
||||||
|
for item in s:
|
||||||
|
arr.add(toVariant(item))
|
||||||
|
newVariant(arr)
|
||||||
|
|
||||||
|
proc toVariant*[T](s: seq[T]): Variant =
|
||||||
|
if s.isNil:
|
||||||
|
return newVariant()
|
||||||
|
result = arrayToVariant(s)
|
||||||
|
|
||||||
|
proc toVariant*[I, T](s: array[I, T]): Variant =
|
||||||
|
result = arrayToVariant(s)
|
||||||
|
|
||||||
|
proc fromVariant*[T](s: var seq[T], val: Variant): ConversionResult =
|
||||||
|
if val.getType() == VariantType.Nil:
|
||||||
|
s = nil
|
||||||
|
elif val.getType() == VariantType.Array:
|
||||||
|
let arr = val.asArray()
|
||||||
|
var newS = newSeq[T](arr.len)
|
||||||
|
for idx, item in arr:
|
||||||
|
mixin fromVariant
|
||||||
|
let convResult = fromVariant(newS[idx], item)
|
||||||
|
if convResult != ConversionResult.OK:
|
||||||
|
return convResult
|
||||||
|
shallowCopy(s, newS)
|
||||||
|
else:
|
||||||
|
result = ConversionResult.TypeError
|
||||||
|
|
||||||
|
proc fromVariant*[T: array](s: var T, val: Variant): ConversionResult =
|
||||||
|
if val.getType() == VariantType.Nil:
|
||||||
|
discard
|
||||||
|
elif val.getType() == VariantType.Array:
|
||||||
|
let arr = val.asArray()
|
||||||
|
if s.len != arr.len:
|
||||||
|
return ConversionResult.TypeError
|
||||||
|
var nimIdx = low(s) # may not start from 0 and may even be an enum
|
||||||
|
for item in arr:
|
||||||
|
mixin fromVariant
|
||||||
|
let convResult = fromVariant(s[nimIdx], item)
|
||||||
|
if convResult != ConversionResult.OK:
|
||||||
|
return convResult
|
||||||
|
if nimIdx != high(s):
|
||||||
|
inc nimIdx
|
||||||
|
else:
|
||||||
|
result = ConversionResult.TypeError
|
||||||
|
|
||||||
|
proc godotTypeInfo*[T](OptT: typedesc[Option[T]]): GodotTypeInfo =
|
||||||
|
when compiles(godotTypeInfo(T)):
|
||||||
|
result.variantType = godotTypeInfo(T)
|
||||||
|
else:
|
||||||
|
result.variantType = VariantType.Nil
|
||||||
|
|
||||||
|
proc toVariant*[T](option: Option[T]): Variant =
|
||||||
|
if option.isSome():
|
||||||
|
result = toVariant(option.unsafeGet())
|
||||||
|
else:
|
||||||
|
result = newVariant()
|
||||||
|
|
||||||
|
proc fromVariant*[T](option: var Option[T], val: Variant): ConversionResult =
|
||||||
|
if val.getType() == VariantType.Nil:
|
||||||
|
option = none(T)
|
||||||
|
else:
|
||||||
|
var v: T
|
||||||
|
result = fromVariant(v, val)
|
||||||
|
if result == ConversionResult.OK:
|
||||||
|
option = some(result)
|
||||||
|
|
||||||
|
proc godotTypeInfo*(T: typedesc[Table|TableRef|OrderedTable|OrderedTableRef]): GodotTypeInfo {.inline.} =
|
||||||
|
result.variantType = VariantType.Dictionary
|
||||||
|
|
||||||
|
proc toVariant*[T: Table or TableRef or OrderedTable or OrderedTableRef](t: T): Variant =
|
||||||
|
when t is ref:
|
||||||
|
if t.isNil:
|
||||||
|
return newVariant()
|
||||||
|
var dict = newDictionary()
|
||||||
|
mixin toVariant
|
||||||
|
for k, v in t.pairs():
|
||||||
|
dict[toVariant(k)] = toVariant(v)
|
||||||
|
result = newVariant(dict)
|
||||||
|
|
||||||
|
proc fromVariant*[T: Table or TableRef or OrderedTable or OrderedTableRef](t: var T,
|
||||||
|
val: Variant): ConversionResult =
|
||||||
|
if val.getType() == VariantType.Nil:
|
||||||
|
when t is ref:
|
||||||
|
t = nil
|
||||||
|
elif val.getType() == VariantType.Dictionary:
|
||||||
|
let dict = val.asDictionary()
|
||||||
|
mixin fromVariant
|
||||||
|
when t is Table:
|
||||||
|
t = initTable[type(t.keys()), type(t.values())]()
|
||||||
|
elif t is TableRef:
|
||||||
|
t = newTable[type(t.keys()), type(t.values())]()
|
||||||
|
elif t is OrderedTable:
|
||||||
|
t = initOrderedTable[type(t.keys()), type(t.values())]()
|
||||||
|
else:
|
||||||
|
t = newOrderedTable[type(t.keys()), type(t.values())]()
|
||||||
|
for k, v in dict:
|
||||||
|
var nimKey: type(t.keys())
|
||||||
|
var nimVal: type(t.values())
|
||||||
|
let keyResult = fromVariant(nimKey, k)
|
||||||
|
if keyResult != ConversionResult.OK:
|
||||||
|
when t is ref:
|
||||||
|
t = nil
|
||||||
|
return keyResult
|
||||||
|
let valResult = fromVariant(nimVal, v)
|
||||||
|
if valResult != ConversionResult.OK:
|
||||||
|
when t is ref:
|
||||||
|
t = nil
|
||||||
|
return valResult
|
||||||
|
t[nimKey] = nimVal
|
||||||
|
else:
|
||||||
|
result = ConversionResult.TypeError
|
||||||
|
|
||||||
|
when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
|
||||||
|
{.emit: """/*TYPESECTION*/
|
||||||
|
N_LIB_EXPORT N_CDECL(void, NimMain)(void);
|
||||||
|
N_NOINLINE(void, setStackBottom)(void* thestackbottom);
|
||||||
|
""".}
|
||||||
|
|
||||||
|
var nativeLibHandle: pointer
|
||||||
|
proc getNativeLibHandle*(): pointer =
|
||||||
|
## Returns NativeScript library handle used to register type information
|
||||||
|
## in Godot.
|
||||||
|
return nativeLibHandle
|
||||||
|
|
||||||
|
proc godot_nativescript_init(handle: pointer) {.
|
||||||
|
cdecl, exportc, dynlib.} =
|
||||||
|
nativeLibHandle = handle
|
||||||
|
|
||||||
|
var stackBottom {.volatile.}: pointer
|
||||||
|
stackBottom = addr(stackBottom)
|
||||||
|
{.emit: """
|
||||||
|
NimMain();
|
||||||
|
""".}
|
||||||
|
when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
|
||||||
|
{.emit: """
|
||||||
|
setStackBottom((void*)(&`stackBottom`));
|
||||||
|
""".}
|
||||||
|
else:
|
||||||
|
nimGC_setStackBottom(stackBottom)
|
||||||
|
GC_fullCollect()
|
||||||
|
GC_disable()
|
||||||
|
|
||||||
|
proc godot_gdnative_init(options: ptr GDNativeInitOptions) {.
|
||||||
|
cdecl, exportc, dynlib.} =
|
||||||
|
gdNativeLibraryObj = options.gdNativeLibrary
|
||||||
|
setGDNativeAPI(options.gdNativeAPIStruct, options)
|
||||||
|
|
||||||
|
proc godot_gdnative_terminate(options: ptr GDNativeTerminateOptions) {.
|
||||||
|
cdecl, exportc, dynlib.} =
|
||||||
|
if not options[].inEditor or not compileOption("threads"):
|
||||||
|
deallocHeap(runFinalizers = not options[].inEditor, allowGcAfterwards = false)
|
||||||
|
|
||||||
|
const nimGcStepLengthUs {.intdefine.} = 2000
|
||||||
|
|
||||||
|
var idleCallbacks {.threadvar.}: seq[proc () {.closure.}]
|
||||||
|
idleCallbacks = newSeq[proc () {.closure.}]()
|
||||||
|
|
||||||
|
var isMainThread {.threadvar.}: bool
|
||||||
|
isMainThread = true
|
||||||
|
|
||||||
|
proc registerFrameCallback*(cb: proc () {.closure.}) =
|
||||||
|
# Registers a callback to be called on the main thread at the end
|
||||||
|
# of each frame.
|
||||||
|
if not isMainThread:
|
||||||
|
const err = cstring"registerFrameIdleCallback is called from non-main thread. Ignoring."
|
||||||
|
godotPrintError(err, cstring"registerFrameCallback",
|
||||||
|
cstring"godotnim.nim", 0)
|
||||||
|
else:
|
||||||
|
idleCallbacks.add(cb)
|
||||||
|
|
||||||
|
{.push stackTrace: off.}
|
||||||
|
|
||||||
|
proc godot_nativescript_frame() {.cdecl, exportc, dynlib.} =
|
||||||
|
var stackBottom {.volatile.}: pointer
|
||||||
|
stackBottom = addr(stackBottom)
|
||||||
|
when (NimMajor, NimMinor, NimPatch) < (0, 19, 0):
|
||||||
|
{.emit: """
|
||||||
|
setStackBottom((void*)(&`stackBottom`));
|
||||||
|
""".}
|
||||||
|
else:
|
||||||
|
nimGC_setStackBottom(stackBottom)
|
||||||
|
for cb in idleCallbacks:
|
||||||
|
cb()
|
||||||
|
GC_step(nimGcStepLengthUs, true, 0)
|
||||||
|
|
||||||
|
when not defined(release):
|
||||||
|
onUnhandledException = proc(errorMsg: string) =
|
||||||
|
printError("Unhandled Nim exception: " & errorMsg)
|
||||||
|
|
||||||
|
proc godot_nativescript_thread_enter() {.cdecl, exportc, dynlib.} =
|
||||||
|
when compileOption("threads"):
|
||||||
|
setupForeignThreadGc()
|
||||||
|
else:
|
||||||
|
const err = cstring"A foreign thread is created, but app is compiled without --threads:on. Bad things will happen if Nim code is invoked from this thread. If you see this warning when running the editor and you don't actually use threads, ignore it."
|
||||||
|
var s = err.toGodotString()
|
||||||
|
godotPrint(s)
|
||||||
|
s.deinit()
|
||||||
|
|
||||||
|
proc godot_nativescript_thread_exit() {.cdecl, exportc, dynlib.} =
|
||||||
|
when compileOption("threads"):
|
||||||
|
teardownForeignThreadGc()
|
||||||
|
|
||||||
|
{.pop.} # stackTrace: off
|
||||||
2
godot/nim/nim.cfg
Normal file
2
godot/nim/nim.cfg
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
--path:"$projectdir/../"
|
||||||
|
-d:useRealtimeGc
|
||||||
5
godot/nimdoc.cfg
Normal file
5
godot/nimdoc.cfg
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
doc.item.seesrc = """ <a
|
||||||
|
href="${url}/tree/${commit}/${path}#L${line}"
|
||||||
|
class="link-seesrc" target="_blank">Source</a>
|
||||||
|
<a href="${url}/edit/master/${path}#L${line}" class="link-seesrc" target="_blank" >Edit</a>
|
||||||
|
"""
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
<html>
|
|
||||||
<head><title>godot-nim docs index</title></head>
|
|
||||||
<body>
|
|
||||||
<h1>Documentation of Nim bindings for Godot Engine (<a href="https://github.com/pragmagic/godot-nim">GitHub</a>)</h1><br/>
|
|
||||||
<a href='master/index.html'>master</a><br/><a href='v0.5.0/index.html'>v0.5.0</a><br/><a href='v0.5.1/index.html'>v0.5.1</a><br/><a href='v0.5.2/index.html'>v0.5.2</a><br/><a href='v0.5.3/index.html'>v0.5.3</a><br/><a href='v0.5.4/index.html'>v0.5.4</a><br/><a href='v0.5.5/index.html'>v0.5.5</a><br/><a href='v0.7.2/index.html'>v0.7.2</a><br/><a href='v0.7.4/index.html'>v0.7.4</a><br/><a href='v0.7.5/index.html'>v0.7.5</a><br/><a href='v0.7.6/index.html'>v0.7.6</a><br/><a href='v0.7.8/index.html'>v0.7.8</a><br/>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
1544
master/aabb.html
1544
master/aabb.html
File diff suppressed because it is too large
Load diff
1733
master/arrays.html
1733
master/arrays.html
File diff suppressed because it is too large
Load diff
1956
master/basis.html
1956
master/basis.html
File diff suppressed because it is too large
Load diff
1455
master/colors.html
1455
master/colors.html
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
1268
master/godot.html
1268
master/godot.html
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue