Documentation & Travis & Refactoring
This commit is contained in:
parent
ec707ea776
commit
988b9e1f11
27 changed files with 772 additions and 123 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -5,4 +5,10 @@ nimcache/
|
||||||
/godot/godotapigen
|
/godot/godotapigen
|
||||||
/godot/godotapigen.exe
|
/godot/godotapigen.exe
|
||||||
|
|
||||||
|
/docgen
|
||||||
|
/docs/docbuild
|
||||||
|
/docs/docbuild.exe
|
||||||
|
/docs/docpublish
|
||||||
|
/docs/docpublish.exe
|
||||||
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
54
.travis.yml
Normal file
54
.travis.yml
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
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 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
|
||||||
|
- nimble install -y
|
||||||
|
- nim c -c godotapi/godotall.nim
|
||||||
|
- nim c -d:release -r docs/docpublish.nim
|
||||||
159
docs/docbuild.nim
Normal file
159
docs/docbuild.nim
Normal file
|
|
@ -0,0 +1,159 @@
|
||||||
|
# Copyright 2017 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 not result.isNil and 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 -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 " & quoted(file))
|
||||||
|
|
||||||
|
sync()
|
||||||
|
|
||||||
|
var gitHash: string
|
||||||
|
withDir(godotBinAbs.parentDir()):
|
||||||
|
gitHash = getGitHash()
|
||||||
|
if gitHash.isNil or 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)
|
||||||
94
docs/docpublish.nim
Normal file
94
docs/docpublish.nim
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
# Copyright 2017 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)
|
||||||
|
|
||||||
|
if getEnv("TRAVIS_PULL_REQUEST").len > 0:
|
||||||
|
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+ $"):
|
||||||
|
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
|
||||||
198
docs/index.rst
Normal file
198
docs/index.rst
Normal file
|
|
@ -0,0 +1,198 @@
|
||||||
|
=============================
|
||||||
|
Nim bindings for Godot Engine
|
||||||
|
=============================
|
||||||
|
|
||||||
|
:Author: Ruslan Mustakov
|
||||||
|
:Version: |godotnimversion|
|
||||||
|
:GitHub: `$GODOTNIM_GITHUB_URL <$GODOTNIM_GITHUB_URL>`_
|
||||||
|
|
||||||
|
.. 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
|
||||||
|
===============
|
||||||
|
|
||||||
|
Building Godot
|
||||||
|
--------------
|
||||||
|
|
||||||
|
The library requires a not yet released Godot version 3.0, which you can
|
||||||
|
build yourself by running the commands below (requires
|
||||||
|
`Git <https://git-scm.com/downloads>`_,
|
||||||
|
`Python 2.7 <https://www.python.org/downloads/>`_,
|
||||||
|
`SCons <http://www.scons.org/>`_):
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
git clone https://github.com/godotengine/godot.git
|
||||||
|
cd godot
|
||||||
|
scons platform=<your_platform>
|
||||||
|
|
||||||
|
where ``<your_platform>`` can be ``windows``, ``osx``, ``x11``. After build
|
||||||
|
is finished, Godot binaries will be under the ``bin`` folder. More details
|
||||||
|
about compiling Godot can be found in `Godot documentation
|
||||||
|
<https://godot.readthedocs.io/en/stable/development/compiling/index.html>`_.
|
||||||
|
|
||||||
|
|
||||||
|
Building Nim
|
||||||
|
-------------
|
||||||
|
|
||||||
|
The library requires a not yet released Nim version 0.17.1, which you can
|
||||||
|
build yourself by following instructions in the
|
||||||
|
`Nim repository <https://github.com/nim-lang/Nim>`_. Make sure to also run
|
||||||
|
``./koch tools -d:release`` after the steps described there to build ``nimble``
|
||||||
|
(package manager) and ``nimsuggest`` (IDE helper tool,
|
||||||
|
used by VSCode Nim plugin)
|
||||||
|
|
||||||
|
|
||||||
|
Creating Project
|
||||||
|
----------------
|
||||||
|
|
||||||
|
The fastest way to set up a Godot-Nim project is to use an 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 ``project/nimlib.tres`` to your Godot project folder. It is a
|
||||||
|
GDNative library resource that contains paths to dynamic libraries
|
||||||
|
compiled by Nim.
|
||||||
|
|
||||||
|
3. Add ``NimRuntime`` as an `AutoLoad singleton <https://godot.readthedocs.io/en/stable/learning/step_by_step/singletons_autoload.html>`_
|
||||||
|
to your project. To do this, copy ``project/scripts/NimRuntime.gdns`` into
|
||||||
|
your project and add these lines to ``project.godot``, adjusting path to
|
||||||
|
``NimRuntime.gdns`` as necessary:
|
||||||
|
.. code-block:: cfg
|
||||||
|
[autoload]
|
||||||
|
NimRuntime="*res://scripts/NimRuntime.gdns"
|
||||||
|
|
||||||
|
|
||||||
|
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.
|
||||||
|
* `rect3 <rect3.html>`_ Defines ``Rect3`` - 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
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
version = "0.3.0"
|
version = "0.4.0"
|
||||||
author = "Xored Software, Inc."
|
author = "Xored Software, Inc."
|
||||||
description = "Godot Engine bindings"
|
description = "Godot Engine bindings"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
{.warning: "'apigen.apigen' module is deprecated and will be removed in v0.4.0. Use 'godotapigen' instead.".}
|
|
||||||
|
|
||||||
include "../godotapigen.nim"
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
# Copyright 2017 Xored Software, Inc.
|
# Copyright 2017 Xored Software, Inc.
|
||||||
|
|
||||||
import hashes
|
import hashes
|
||||||
import internal / [godotstrings, godotdictionaries, godotvariants]
|
import internal.godotstrings, internal.godotdictionaries,
|
||||||
|
internal.godotvariants
|
||||||
|
|
||||||
type
|
type
|
||||||
Dictionary* = ref object
|
Dictionary* = ref object
|
||||||
|
|
|
||||||
1
godot/core/nim.cfg
Normal file
1
godot/core/nim.cfg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
--path:"$projectdir/../"
|
||||||
|
|
@ -2,7 +2,7 @@ import internal.godotobjects
|
||||||
|
|
||||||
type
|
type
|
||||||
RID* {.byref.} = object
|
RID* {.byref.} = object
|
||||||
p: pointer
|
data: array[sizeof(int), byte]
|
||||||
|
|
||||||
proc initRID(dest: var RID) {.
|
proc initRID(dest: var RID) {.
|
||||||
importc: "godot_rid_new".}
|
importc: "godot_rid_new".}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import tables
|
import tables
|
||||||
|
|
||||||
import internal / [godotobjects, godotvariants, godotpoolarrays, godotstrings,
|
import internal.godotobjects, internal.godotvariants, internal.godotpoolarrays,
|
||||||
godotnodepaths]
|
internal.godotstrings, internal.godotnodepaths
|
||||||
|
|
||||||
type
|
type
|
||||||
Variant* = ref object
|
Variant* = ref object
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,17 @@
|
||||||
# Copyright 2017 Xored Software, Inc.
|
# Copyright 2017 Xored Software, Inc.
|
||||||
|
|
||||||
import core.godotbase, godotinternal
|
import core.godotbase, godotinternal
|
||||||
import core / [vector2, rect2, vector3, transform2d, planes, quats]
|
import core.vector2, core.rect2, core.vector3, core.transform2d, core.planes,
|
||||||
import core / [rect3, basis, transforms, colors, nodepaths, rids]
|
core.quats
|
||||||
import core / [dictionaries, arrays, poolarrays, variants]
|
import core.rect3, core.basis, core.transforms, core.colors, core.nodepaths,
|
||||||
|
core.rids
|
||||||
|
import core.dictionaries, core.arrays, core.poolarrays, core.variants
|
||||||
|
|
||||||
import nim / [godotmacros, godotnim]
|
import nim.godotmacros, nim.godotnim
|
||||||
|
|
||||||
export godotbase, vector2, rect2, vector3, transform2d, planes, quats,
|
export godotbase, vector2, rect2, vector3, transform2d, planes, quats,
|
||||||
rect3, basis, transforms, colors, nodepaths, rids, dictionaries, arrays,
|
rect3, basis, transforms, colors, nodepaths, rids, dictionaries, arrays,
|
||||||
poolarrays, variants
|
poolarrays, variants
|
||||||
export godotmacros, godotnim
|
export godotmacros, godotnim
|
||||||
|
|
||||||
|
export GodotPropertyHint, GodotPropertyUsageFlags
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Copyright 2017 Xored Software, Inc.
|
# Copyright 2017 Xored Software, Inc.
|
||||||
|
|
||||||
import streams, json, ospaths, strutils, times, sets, tables
|
import streams, json, os, strutils, times, sets, tables
|
||||||
import sequtils, algorithm
|
import sequtils, algorithm
|
||||||
import compiler / [ast, renderer, idents, astalgo]
|
import compiler / [ast, renderer, idents, astalgo]
|
||||||
|
|
||||||
|
|
@ -261,8 +261,8 @@ const standardTypes = toSet(
|
||||||
"PoolByteArray", "PoolIntArray", "PoolRealArray", "PoolStringArray",
|
"PoolByteArray", "PoolIntArray", "PoolRealArray", "PoolStringArray",
|
||||||
"PoolVector2Array", "PoolVector3Array", "PoolColorArray"])
|
"PoolVector2Array", "PoolVector3Array", "PoolColorArray"])
|
||||||
|
|
||||||
const smallIntTypes = toSet(["uint8", "int8", "uint16", "int16", "uint32", "int32",
|
const smallIntTypes = toSet(["uint8", "int8", "uint16", "int16", "uint32",
|
||||||
"cint", "int", "Error"])
|
"int32", "cint", "int", "Error"])
|
||||||
const int64Types = toSet(["uint64", "int64"])
|
const int64Types = toSet(["uint64", "int64"])
|
||||||
const intTypes = union(smallIntTypes, int64Types)
|
const intTypes = union(smallIntTypes, int64Types)
|
||||||
const float64Types = toSet(["float64", "cdouble"])
|
const float64Types = toSet(["float64", "cdouble"])
|
||||||
|
|
@ -339,6 +339,11 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
|
||||||
var body: PNode
|
var body: PNode
|
||||||
if not withImplementation:
|
if not withImplementation:
|
||||||
body = newNode(nkEmpty)
|
body = newNode(nkEmpty)
|
||||||
|
elif godotMethodName == "_init" and typ.godotName == "Object":
|
||||||
|
# It's not real (calling it crashes) and will be removed later,
|
||||||
|
# but we use init() convention in Nim, so it needs to work.
|
||||||
|
body = newNode(nkStmtList).addChain(
|
||||||
|
newNode(nkDiscardStmt).addChain(newNode(nkEmpty)))
|
||||||
else:
|
else:
|
||||||
var methodBindName = toNimStyle(
|
var methodBindName = toNimStyle(
|
||||||
typ.name & "_" & godotMethodName & "_method_bind")
|
typ.name & "_" & godotMethodName & "_method_bind")
|
||||||
|
|
@ -410,7 +415,7 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
|
||||||
let isStandardType = arg.typ in standardTypes
|
let isStandardType = arg.typ in standardTypes
|
||||||
let isWrappedType = arg.typ in wrapperTypes
|
let isWrappedType = arg.typ in wrapperTypes
|
||||||
let convArg = if not varargsName.isNil:
|
let convArg = if not varargsName.isNil:
|
||||||
getInternalPtr(newCall("toGodot", argName), "Variant")
|
getInternalPtr(newCall("toVariant", argName), "Variant")
|
||||||
elif isWrappedType: getInternalPtr(argName, arg.typ)
|
elif isWrappedType: getInternalPtr(argName, arg.typ)
|
||||||
elif isStandardType: newCall("unsafeAddr", argName)
|
elif isStandardType: newCall("unsafeAddr", argName)
|
||||||
elif arg.typ == "string": newCall("unsafeAddr",
|
elif arg.typ == "string": newCall("unsafeAddr",
|
||||||
|
|
@ -440,7 +445,8 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
argConversions.add(newNode(nkVarSection).addChain(
|
argConversions.add(newNode(nkVarSection).addChain(
|
||||||
newIdentDefs(ident("idx"), newNode(nkEmpty), newIntLit(staticArgsLen))))
|
newIdentDefs(ident("idx"), newNode(nkEmpty),
|
||||||
|
newIntLit(staticArgsLen))))
|
||||||
let argLoop = newNode(nkWhileStmt)
|
let argLoop = newNode(nkWhileStmt)
|
||||||
argConversions.add(argLoop)
|
argConversions.add(argLoop)
|
||||||
argLoop.add(newInfix(ident("idx"), ident("<"), argLenNode)
|
argLoop.add(newInfix(ident("idx"), ident("<"), argLenNode)
|
||||||
|
|
@ -544,7 +550,8 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
|
||||||
if isVariantRet:
|
if isVariantRet:
|
||||||
let convErrDef = newNode(nkLetSection).addChain(
|
let convErrDef = newNode(nkLetSection).addChain(
|
||||||
newIdentDefs(ident("convErr"), newNode(nkEmpty),
|
newIdentDefs(ident("convErr"), newNode(nkEmpty),
|
||||||
newCall("fromGodot", ident("result"), newCall("newVariant", retValIdent))))
|
newCall("fromVariant", ident("result"),
|
||||||
|
newCall("newVariant", retValIdent))))
|
||||||
let convCheck = newIfStmt(
|
let convCheck = newIfStmt(
|
||||||
newInfix(ident("convErr"), ident("!="),
|
newInfix(ident("convErr"), ident("!="),
|
||||||
newDotExpr(ident("ConversionResult"), ident("OK"))),
|
newDotExpr(ident("ConversionResult"), ident("OK"))),
|
||||||
|
|
@ -726,7 +733,7 @@ proc shouldExport(typ: GodotType, types: Table[string, GodotType]): bool =
|
||||||
curTyp = types.getOrDefault(curTyp.baseName)
|
curTyp = types.getOrDefault(curTyp.baseName)
|
||||||
result = curTyp.isNil
|
result = curTyp.isNil
|
||||||
|
|
||||||
proc genTypeFile*(types: var Table[string, GodotType], targetDir: string) =
|
proc genTypeFile(types: var Table[string, GodotType], targetDir: string) =
|
||||||
for typ in types.values():
|
for typ in types.values():
|
||||||
types.incDerivedCount(typ.baseName)
|
types.incDerivedCount(typ.baseName)
|
||||||
|
|
||||||
|
|
@ -755,6 +762,9 @@ proc genTypeFile*(types: var Table[string, GodotType], targetDir: string) =
|
||||||
renderModule(godotApiTypesTree, targetDir / "godottypes.nim")
|
renderModule(godotApiTypesTree, targetDir / "godottypes.nim")
|
||||||
|
|
||||||
proc genApi*(targetDir: string, apiJsonFile: string) =
|
proc genApi*(targetDir: string, apiJsonFile: string) =
|
||||||
|
## Generates .nim files in the ``targetDir`` based on the ``apiJsonFile``.
|
||||||
|
## The JSON file can be generated by executing Godot with
|
||||||
|
## ``--gdnative-generate-json-api <target_filename>`` parameters.
|
||||||
let apiJson = parseJson(newFileStream(apiJsonFile),
|
let apiJson = parseJson(newFileStream(apiJsonFile),
|
||||||
apiJsonFile.extractFilename())
|
apiJsonFile.extractFilename())
|
||||||
var megaImport = newStringOfCap(64 * 1024)
|
var megaImport = newStringOfCap(64 * 1024)
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
# Copyright 2017 Xored Software, Inc.
|
# Copyright 2017 Xored Software, Inc.
|
||||||
|
|
||||||
import internal / [
|
import internal.godotobjects, internal.godotarrays, internal.godotnodepaths,
|
||||||
godotobjects, godotarrays, godotnodepaths, godotpoolarrays,
|
internal.godotpoolarrays, internal.godotstrings, internal.godotvariants,
|
||||||
godotstrings, godotvariants, godotdictionaries]
|
internal.godotdictionaries
|
||||||
|
|
||||||
export godotobjects, godotarrays, godotnodepaths, godotpoolarrays,
|
export godotobjects, godotarrays, godotnodepaths, godotpoolarrays,
|
||||||
godotstrings, godotvariants, godotdictionaries
|
godotstrings, godotvariants, godotdictionaries
|
||||||
|
|
@ -206,7 +206,7 @@ type
|
||||||
|
|
||||||
proc godotScriptRegisterProperty*(libHandle: pointer;
|
proc godotScriptRegisterProperty*(libHandle: pointer;
|
||||||
name: cstring; path: cstring;
|
name: cstring; path: cstring;
|
||||||
attr: var GodotPropertyAttributes;
|
attr: ptr GodotPropertyAttributes;
|
||||||
setFunc: GodotPropertySetFunc;
|
setFunc: GodotPropertySetFunc;
|
||||||
getFunc: GodotPropertyGetFunc) {.
|
getFunc: GodotPropertyGetFunc) {.
|
||||||
importc: "godot_nativescript_register_property".}
|
importc: "godot_nativescript_register_property".}
|
||||||
|
|
@ -270,6 +270,9 @@ proc getClassName*(o: ptr GodotObject): string =
|
||||||
# There are physics type not known by ClassDB
|
# There are physics type not known by ClassDB
|
||||||
result = result[0..result.len-3]
|
result = result[0..result.len-3]
|
||||||
|
|
||||||
|
proc getGodotSingleton*(name: cstring): ptr GodotObject {.
|
||||||
|
importc: "godot_global_get_singleton".}
|
||||||
|
|
||||||
# System Functions
|
# System Functions
|
||||||
|
|
||||||
proc godotAlloc*(bytes: cint): pointer {.
|
proc godotAlloc*(bytes: cint): pointer {.
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
type
|
type
|
||||||
GodotArray* {.byref.} = object
|
GodotArray* {.byref.} = object
|
||||||
p: pointer
|
data: array[sizeof(int), byte]
|
||||||
|
|
||||||
import hashes
|
import hashes
|
||||||
import godotobjects, godotpoolarrays, godotvariants, godotstrings
|
import godotobjects, godotpoolarrays, godotvariants, godotstrings
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
type
|
type
|
||||||
GodotDictionary* {.byref.} = object
|
GodotDictionary* {.byref.} = object
|
||||||
p: pointer
|
data: array[sizeof(int), byte]
|
||||||
|
|
||||||
import godotarrays, godotvariants, godotstrings
|
import godotarrays, godotvariants, godotstrings
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import godotstrings
|
||||||
|
|
||||||
type
|
type
|
||||||
GodotNodePath* {.byref.} = object
|
GodotNodePath* {.byref.} = object
|
||||||
p: pointer
|
data: array[sizeof(int), byte]
|
||||||
|
|
||||||
proc initGodotNodePath*(dest: var GodotNodePath; s: GodotString) {.
|
proc initGodotNodePath*(dest: var GodotNodePath; s: GodotString) {.
|
||||||
importc: "godot_node_path_new".}
|
importc: "godot_node_path_new".}
|
||||||
|
|
|
||||||
|
|
@ -2,22 +2,22 @@
|
||||||
|
|
||||||
type
|
type
|
||||||
GodotPoolByteArray* {.byref.} = object
|
GodotPoolByteArray* {.byref.} = object
|
||||||
p: pointer
|
data: array[sizeof(int), byte]
|
||||||
GodotPoolIntArray* {.byref.} = object
|
GodotPoolIntArray* {.byref.} = object
|
||||||
p: pointer
|
data: array[sizeof(int), byte]
|
||||||
GodotPoolRealArray* {.byref.} = object
|
GodotPoolRealArray* {.byref.} = object
|
||||||
p: pointer
|
data: array[sizeof(int), byte]
|
||||||
GodotPoolStringArray* {.byref.} = object
|
GodotPoolStringArray* {.byref.} = object
|
||||||
p: pointer
|
data: array[sizeof(int), byte]
|
||||||
GodotPoolVector2Array* {.byref.} = object
|
GodotPoolVector2Array* {.byref.} = object
|
||||||
p: pointer
|
data: array[sizeof(int), byte]
|
||||||
GodotPoolVector3Array* {.byref.} = object
|
GodotPoolVector3Array* {.byref.} = object
|
||||||
p: pointer
|
data: array[sizeof(int), byte]
|
||||||
GodotPoolColorArray* {.byref.} = object
|
GodotPoolColorArray* {.byref.} = object
|
||||||
p: pointer
|
data: array[sizeof(int), byte]
|
||||||
|
|
||||||
import godotstrings, godotarrays
|
import godotstrings, godotarrays
|
||||||
import core / [godotbase, colors, vector2, vector3]
|
import core.godotbase, core.colors, core.vector2, core.vector3
|
||||||
|
|
||||||
# byte
|
# byte
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
type
|
type
|
||||||
GodotString* {.byref.} = object
|
GodotString* {.byref.} = object
|
||||||
p: pointer
|
data: array[sizeof(int), byte]
|
||||||
|
|
||||||
proc initGodotString(dest: var GodotString) {.
|
proc initGodotString(dest: var GodotString) {.
|
||||||
importc: "godot_string_new".}
|
importc: "godot_string_new".}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ type
|
||||||
expected*: VariantType
|
expected*: VariantType
|
||||||
|
|
||||||
GodotVariant* {.byref.} = object
|
GodotVariant* {.byref.} = object
|
||||||
data: array[16 + sizeof(int), byte]
|
data: array[4 + sizeof(int) div 4, float32]
|
||||||
|
|
||||||
import godotobjects, godotarrays, godotpoolarrays,
|
import godotobjects, godotarrays, godotpoolarrays,
|
||||||
godotstrings, godotnodepaths, godotdictionaries
|
godotstrings, godotnodepaths, godotdictionaries
|
||||||
|
|
|
||||||
1
godot/internal/nim.cfg
Normal file
1
godot/internal/nim.cfg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
--path:"$projectdir/../"
|
||||||
|
|
@ -32,6 +32,19 @@ type
|
||||||
|
|
||||||
ParseError = object of Exception
|
ParseError = object of Exception
|
||||||
|
|
||||||
|
proc godotToNim[T](val: Variant): (T, ConversionResult) =
|
||||||
|
mixin fromVariant
|
||||||
|
result[1] = fromVariant(result[0], val)
|
||||||
|
|
||||||
|
proc nimToGodot[T](val: T): Variant =
|
||||||
|
mixin toVariant
|
||||||
|
when compiles(toVariant(val)):
|
||||||
|
result = toVariant(val)
|
||||||
|
else:
|
||||||
|
printError("Failed to convert Nim value of type " & T.name &
|
||||||
|
" into Variant")
|
||||||
|
initNilVariant(result)
|
||||||
|
|
||||||
template parseError(node: NimNode, msg: string) =
|
template parseError(node: NimNode, msg: string) =
|
||||||
raise newException(ParseError, lineinfo(node) & ": " & msg)
|
raise newException(ParseError, lineinfo(node) & ": " & msg)
|
||||||
|
|
||||||
|
|
@ -249,7 +262,7 @@ macro invokeVarArgs(procIdent, objIdent;
|
||||||
|
|
||||||
if hasReturnValue:
|
if hasReturnValue:
|
||||||
let theCall = newNimNode(nnkBracketExpr).add(newNimNode(nnkDotExpr).add(
|
let theCall = newNimNode(nnkBracketExpr).add(newNimNode(nnkDotExpr).add(
|
||||||
newCall("toGodot", invocation), ident("godotVariant")))
|
newCall("toVariant", invocation), ident("godotVariant")))
|
||||||
branchBody.add(getAst(initGodotVariantCall(ident("result"), theCall)))
|
branchBody.add(getAst(initGodotVariantCall(ident("result"), theCall)))
|
||||||
else:
|
else:
|
||||||
branchBody.add(invocation)
|
branchBody.add(invocation)
|
||||||
|
|
@ -291,11 +304,18 @@ proc nimDestroyRefFunc(obj: ptr GodotObject, methData: pointer,
|
||||||
# so nothing to do here.
|
# so nothing to do here.
|
||||||
discard
|
discard
|
||||||
|
|
||||||
proc refcountIncremented*(obj: NimGodotObject) =
|
proc refcountIncremented(obj: ptr GodotObject, methodData: pointer,
|
||||||
GC_ref(obj)
|
userData: pointer, numArgs: cint,
|
||||||
|
args: var array[MAX_ARG_COUNT, ptr GodotVariant]):
|
||||||
|
GodotVariant {.noconv.} =
|
||||||
|
GC_ref(cast[NimGodotObject](userData))
|
||||||
|
|
||||||
proc refcountDecremented*(obj: NimGodotObject): bool =
|
proc refcountDecremented(obj: ptr GodotObject, methodData: pointer,
|
||||||
GC_unref(obj)
|
userData: pointer, numArgs: cint,
|
||||||
|
args: var array[MAX_ARG_COUNT, ptr GodotVariant]):
|
||||||
|
GodotVariant {.noconv.} =
|
||||||
|
GC_unref(cast[NimGodotObject](userData))
|
||||||
|
initGodotVariant(result, false) # destroy when Nim decides
|
||||||
|
|
||||||
template registerGodotClass(classNameIdent, classNameLit, isRef,
|
template registerGodotClass(classNameIdent, classNameLit, isRef,
|
||||||
baseNameLit, createFuncIdent; isTool: bool) =
|
baseNameLit, createFuncIdent; isTool: bool) =
|
||||||
|
|
@ -306,6 +326,8 @@ template registerGodotClass(classNameIdent, classNameLit, isRef,
|
||||||
nimObj.setGodotObject(obj)
|
nimObj.setGodotObject(obj)
|
||||||
GC_ref(nimObj)
|
GC_ref(nimObj)
|
||||||
result = cast[pointer](nimObj)
|
result = cast[pointer](nimObj)
|
||||||
|
when compiles(nimObj.init()):
|
||||||
|
nimObj.init()
|
||||||
|
|
||||||
let createFuncObj = GodotInstanceCreateFunc(
|
let createFuncObj = GodotInstanceCreateFunc(
|
||||||
createFunc: createFuncIdent
|
createFunc: createFuncIdent
|
||||||
|
|
@ -356,19 +378,23 @@ template registerGodotField(classNameLit, classNameIdent, propNameLit,
|
||||||
getFunc: getFuncIdent
|
getFunc: getFuncIdent
|
||||||
)
|
)
|
||||||
{.push warning[ProveInit]: off.} # false warning, Nim bug
|
{.push warning[ProveInit]: off.} # false warning, Nim bug
|
||||||
var attr = GodotPropertyAttributes(
|
var hintStr = hintTipLit.toGodotString()
|
||||||
typ: ord(godotVariantType(propTypeIdent)),
|
let attr = GodotPropertyAttributes(
|
||||||
hintString: hintTipLit.toGodotString(),
|
typ: ord(variantType(propTypeIdent)),
|
||||||
|
hintString: hintStr,
|
||||||
hint: GodotPropertyHint.hintIdent,
|
hint: GodotPropertyHint.hintIdent,
|
||||||
usage: GodotPropertyUsageFlags.usageIdent
|
usage: GodotPropertyUsageFlags.usageIdent
|
||||||
)
|
)
|
||||||
{.push warning[ProveInit]: on.}
|
{.push warning[ProveInit]: on.}
|
||||||
when hasDefaultValue:
|
when hasDefaultValue:
|
||||||
attr.defaultValue = (defaultValueNode).toGodot()
|
attr.defaultValue = (defaultValueNode).toVariant().godotVariant[]
|
||||||
godotScriptRegisterProperty(getNativeLibHandle(), classNameLit, propNameLit,
|
godotScriptRegisterProperty(getNativeLibHandle(), classNameLit, propNameLit,
|
||||||
attr, setFunc, getFunc)
|
unsafeAddr attr, setFunc, getFunc)
|
||||||
|
hintStr.deinit()
|
||||||
|
|
||||||
static:
|
static:
|
||||||
import strutils, sets
|
import strutils, sets, sequtils
|
||||||
|
|
||||||
proc toGodotStyle(s: string): string {.compileTime.} =
|
proc toGodotStyle(s: string): string {.compileTime.} =
|
||||||
result = newStringOfCap(s.len + 10)
|
result = newStringOfCap(s.len + 10)
|
||||||
for c in s:
|
for c in s:
|
||||||
|
|
@ -469,7 +495,6 @@ proc genType(obj: ObjectDecl): NimNode {.compileTime.} =
|
||||||
GodotVariant {.noconv.} =
|
GodotVariant {.noconv.} =
|
||||||
let self = cast[classNameIdent](userData)
|
let self = cast[classNameIdent](userData)
|
||||||
const isStaticCall = methodNameLit == cstring"_ready" or
|
const isStaticCall = methodNameLit == cstring"_ready" or
|
||||||
methodNameLit == cstring"_init" or
|
|
||||||
methodNameLit == cstring"_enter_tree" or
|
methodNameLit == cstring"_enter_tree" or
|
||||||
methodNameLit == cstring"_exit_tree" or
|
methodNameLit == cstring"_exit_tree" or
|
||||||
methodNameLit == cstring"_enter_world" or
|
methodNameLit == cstring"_enter_world" or
|
||||||
|
|
@ -520,25 +545,70 @@ proc genType(obj: ObjectDecl): NimNode {.compileTime.} =
|
||||||
|
|
||||||
if isRef:
|
if isRef:
|
||||||
# add ref/unref for types inherited from Reference
|
# add ref/unref for types inherited from Reference
|
||||||
let noArgs = newSeq[NimNode]()
|
template registerRefIncDec(classNameLit) =
|
||||||
result.add(getAst(
|
let refInc = GodotInstanceMethod(
|
||||||
registerGodotMethod(classNameLit, classNameIdent, ident("refcountIncremented"),
|
meth: refcountIncremented
|
||||||
cstring"_refcount_incremented", 0, 0,
|
)
|
||||||
noArgs, genSym(nskProc, "refcount_incremented"),
|
let refDec = GodotInstanceMethod(
|
||||||
ident("false"))))
|
meth: refcountDecremented
|
||||||
result.add(getAst(
|
)
|
||||||
registerGodotMethod(classNameLit, classNameIdent, ident("refcountDecremented"),
|
godotScriptRegisterMethod(getNativeLibHandle(), classNameLit,
|
||||||
cstring"_refcount_decremented", 0, 0,
|
cstring"_refcount_incremented",
|
||||||
noArgs, genSym(nskProc, "refcount_decremented"),
|
GodotMethodAttributes(), refInc)
|
||||||
ident("true"))))
|
godotScriptRegisterMethod(getNativeLibHandle(), classNameLit,
|
||||||
|
cstring"_refcount_decremented",
|
||||||
|
GodotMethodAttributes(), refDec)
|
||||||
|
result.add(getAst(registerRefIncDec(classNameLit)))
|
||||||
|
|
||||||
{.push warning[Deprecated]: off.}
|
{.push warning[Deprecated]: off.}
|
||||||
# immediate macros are deprecated, but `untyped` doesnt make it immediate,
|
# immediate macros are deprecated, but `untyped` doesn't make it immediate,
|
||||||
# as the warning and the documentation claim.
|
# as the warning and the documentation claim.
|
||||||
|
|
||||||
macro gdobj*(definition: untyped, body: typed): typed {.immediate.} =
|
macro gdobj*(definition: untyped, body: typed): typed {.immediate.} =
|
||||||
|
## Generates Godot type. Self-documenting example:
|
||||||
|
##
|
||||||
|
## .. code-block:: nim
|
||||||
|
## import godot, node
|
||||||
|
##
|
||||||
|
## gdobj MyObj of Node:
|
||||||
|
## var myField: int
|
||||||
|
## ## Not exported to Godot (i.e. editor will not see this field).
|
||||||
|
##
|
||||||
|
## var myString* {.gdExport, hint: Length, tip: "20".}: string
|
||||||
|
## ## Exported to Godot as ``my_string``.
|
||||||
|
## ## Editor will limit this string to length 20.
|
||||||
|
## ## ``hint` is a value of ``GodotPropertyHint`` enum.
|
||||||
|
## ## ``tip`` depends on the value of ``hint``, its format is described
|
||||||
|
## ## in ``GodotPropertyHint`` documentation.
|
||||||
|
##
|
||||||
|
## method ready*() =
|
||||||
|
## ## Exported methods are exported to Godot by default,
|
||||||
|
## ## and their Godot names are prefixed with ``_``
|
||||||
|
## ## (in this case ``_ready``)
|
||||||
|
## print("I am ready! myString is: " & myString)
|
||||||
|
##
|
||||||
|
## proc myProc*() {.gdExport.} =
|
||||||
|
## ## Exported to Godot as ``my_proc``
|
||||||
|
## print("myProc is called! Incrementing myField.")
|
||||||
|
## inc myField
|
||||||
|
##
|
||||||
|
## If parent type is omitted, the type is inherited from ``Object``.
|
||||||
|
##
|
||||||
|
## ``tool`` specifier can be added to mark the type as an
|
||||||
|
## `editor plugin <https://godot.readthedocs.io/en/stable/development/plugins/making_plugins.html>`_:
|
||||||
|
##
|
||||||
|
## .. code-block:: nim
|
||||||
|
## import godot, editor_plugin
|
||||||
|
##
|
||||||
|
## gdobj(MyTool of EditorPlugin, tool):
|
||||||
|
## method enterTree*() =
|
||||||
|
## print("MyTool initialized!")
|
||||||
|
##
|
||||||
|
## Objects can be instantiated by invoking
|
||||||
|
## `gdnew <godotnim.html#gdnew>`_ or by using
|
||||||
|
## `load <godotapi/resource_loader.html#load,string,string,bool>`_ or any other way
|
||||||
|
## that you can find in `Godot API <index.html#modules-godot-api>`_.
|
||||||
let typeDef = parseType(definition, callsite())
|
let typeDef = parseType(definition, callsite())
|
||||||
result = genType(typeDef)
|
result = genType(typeDef)
|
||||||
|
|
||||||
{.push warning[Deprecated]: on.}
|
{.push warning[Deprecated]: on.}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,15 +10,28 @@ import core.vector2, core.rect2,
|
||||||
core.arrays, core.poolarrays, core.variants
|
core.arrays, core.poolarrays, core.variants
|
||||||
import godotinternal
|
import godotinternal
|
||||||
|
|
||||||
## Definition of NimGodotObject and converters for built-in types.
|
## This module defines ``NimGodotObject`` and ``toVariant``/``fromVariant``
|
||||||
|
## converters for Nim types. The converters are used by
|
||||||
|
## `gdobj <godotmacros.html#gdobj.m,untyped,typed>`_ macro to import/export
|
||||||
|
## values from/to Godot (editor, GDScript).
|
||||||
|
##
|
||||||
|
## You can also allow conversion of any custom type ``MyType`` by implementing:
|
||||||
|
##
|
||||||
|
## .. code-block:: nim
|
||||||
|
## proc variantType*(T: typedesc[MyType]): VariantType
|
||||||
|
## proc toVariant*(self: MyType): Variant
|
||||||
|
## proc fromVariant*(self: var MyType, val: Variant): ConversionResult
|
||||||
|
|
||||||
type
|
type
|
||||||
NimGodotObject* = ref object of RootObj
|
NimGodotObject* = ref object of RootObj
|
||||||
|
## The base type all Godot types inherit from.
|
||||||
|
## Manages lifecycle of the wrapped GodotObject.
|
||||||
godotObject: ptr GodotObject
|
godotObject: ptr GodotObject
|
||||||
isExternalRef: bool
|
isExternalRef: bool
|
||||||
isOwn: bool
|
isOwn: bool
|
||||||
|
|
||||||
ConversionResult* {.pure.} = enum
|
ConversionResult* {.pure.} = enum
|
||||||
|
## Conversion result to return from ``fromVariant`` procedure.
|
||||||
OK,
|
OK,
|
||||||
TypeError,
|
TypeError,
|
||||||
## Type mismatch
|
## Type mismatch
|
||||||
|
|
@ -41,7 +54,11 @@ type
|
||||||
SomeGodotOrNum = SomeGodot or SomeSignedInt or SomeUnsignedInt or SomeFloat
|
SomeGodotOrNum = SomeGodot or SomeSignedInt or SomeUnsignedInt or SomeFloat
|
||||||
|
|
||||||
CallError* = object of Exception
|
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
|
err*: VariantCallError
|
||||||
|
## The error as returned by Godot
|
||||||
|
|
||||||
ObjectInfo = object
|
ObjectInfo = object
|
||||||
constructor: proc(): NimGodotObject {.gcsafe, nimcall.}
|
constructor: proc(): NimGodotObject {.gcsafe, nimcall.}
|
||||||
|
|
@ -49,20 +66,24 @@ type
|
||||||
isNative: bool
|
isNative: bool
|
||||||
isRef: bool
|
isRef: bool
|
||||||
|
|
||||||
template printWarning*(warn: typed) =
|
template printWarning*(warning: typed) =
|
||||||
|
## Prints ``warning`` to Godot log, adding filename and line information.
|
||||||
let (filename, line) = instantiationInfo()
|
let (filename, line) = instantiationInfo()
|
||||||
godotPrintWarning(cstring($warn), nil, cstring(filename), line.cint)
|
godotPrintWarning(cstring($warning), nil, cstring(filename), line.cint)
|
||||||
|
|
||||||
template printError*(err: typed) =
|
template printError*(error: typed) =
|
||||||
|
## Prints ``error`` to Godot log, adding filename and line information.
|
||||||
let (filename, line) = instantiationInfo()
|
let (filename, line) = instantiationInfo()
|
||||||
godotPrintError(cstring($err), nil, cstring(filename), line.cint)
|
godotPrintError(cstring($error), nil, cstring(filename), line.cint)
|
||||||
|
|
||||||
proc print*(message: string) {.inline.} =
|
proc print*(message: string) {.inline.} =
|
||||||
|
## Prints ``message`` to Godot log.
|
||||||
var s = message.toGodotString()
|
var s = message.toGodotString()
|
||||||
godotPrint(s)
|
godotPrint(s)
|
||||||
s.deinit()
|
s.deinit()
|
||||||
|
|
||||||
proc print*(message: cstring) {.inline.} =
|
proc print*(message: cstring) {.inline.} =
|
||||||
|
## Prints ``message`` to Godot log.
|
||||||
var s = message.toGodotString()
|
var s = message.toGodotString()
|
||||||
godotPrint(s)
|
godotPrint(s)
|
||||||
s.deinit()
|
s.deinit()
|
||||||
|
|
@ -141,7 +162,9 @@ macro isReference(T: typedesc): bool =
|
||||||
else: ident("false")
|
else: ident("false")
|
||||||
|
|
||||||
template registerClass*(T: typedesc; godotClassName: cstring,
|
template registerClass*(T: typedesc; godotClassName: cstring,
|
||||||
isNativeParam: bool) =
|
native: bool) =
|
||||||
|
## Registers the specified Godot type.
|
||||||
|
## Used by ``gdobj`` macro and `godotapigen <godotapigen.html>`_.
|
||||||
if classRegistry.isNil:
|
if classRegistry.isNil:
|
||||||
classRegistry = newTable[cstring, ObjectInfo]()
|
classRegistry = newTable[cstring, ObjectInfo]()
|
||||||
let constructor = proc(): NimGodotObject =
|
let constructor = proc(): NimGodotObject =
|
||||||
|
|
@ -154,21 +177,21 @@ template registerClass*(T: typedesc; godotClassName: cstring,
|
||||||
let objInfo = ObjectInfo(
|
let objInfo = ObjectInfo(
|
||||||
constructor: constructor,
|
constructor: constructor,
|
||||||
baseNativeClass: base,
|
baseNativeClass: base,
|
||||||
isNative: isNativeParam,
|
isNative: native,
|
||||||
isRef: isRef
|
isRef: isRef
|
||||||
)
|
)
|
||||||
classRegistry[godotClassName] = objInfo
|
classRegistry[godotClassName] = objInfo
|
||||||
static:
|
static:
|
||||||
let objInfoStatic = ObjectInfo(
|
let objInfoStatic = ObjectInfo(
|
||||||
baseNativeClass: base,
|
baseNativeClass: base,
|
||||||
isNative: isNativeParam,
|
isNative: native,
|
||||||
isRef: isRef
|
isRef: isRef,
|
||||||
)
|
)
|
||||||
classRegistryStatic[godotClassName] = objInfoStatic
|
classRegistryStatic[godotClassName] = objInfoStatic
|
||||||
when isRef:
|
when isRef:
|
||||||
static:
|
static:
|
||||||
refClasses.add(T.name)
|
refClasses.add(T.name)
|
||||||
when isNativeParam:
|
when native:
|
||||||
static:
|
static:
|
||||||
nativeClasses.add(T.name)
|
nativeClasses.add(T.name)
|
||||||
|
|
||||||
|
|
@ -187,6 +210,9 @@ proc newNimGodotObject[T: NimGodotObject](
|
||||||
result.godotObject.reference()
|
result.godotObject.reference()
|
||||||
|
|
||||||
proc asNimGodotObject*[T: NimGodotObject](godotObject: ptr GodotObject): T =
|
proc asNimGodotObject*[T: NimGodotObject](godotObject: ptr GodotObject): T =
|
||||||
|
## Wraps ``godotObject`` into Nim type ``T``.
|
||||||
|
## This is used by `godotapigen <godotapigen.html>`_ and should rarely be
|
||||||
|
## used by anything else.
|
||||||
if godotObject.isNil: return nil
|
if godotObject.isNil: return nil
|
||||||
let userDataPtr = godotObject.getUserData()
|
let userDataPtr = godotObject.getUserData()
|
||||||
if not userDataPtr.isNil:
|
if not userDataPtr.isNil:
|
||||||
|
|
@ -202,15 +228,24 @@ proc newVariant*(obj: NimGodotObject): Variant {.inline.} =
|
||||||
newVariant(obj.godotObject)
|
newVariant(obj.godotObject)
|
||||||
|
|
||||||
proc asObject*[T: NimGodotObject](v: Variant): T {.inline.} =
|
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())
|
asNimGodotObject[T](v.asGodotObject())
|
||||||
|
|
||||||
proc asObject*(v: Variant, T: typedesc[NimGodotObject]): T {.inline.} =
|
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())
|
asNimGodotObject[T](v.asGodotObject())
|
||||||
|
|
||||||
proc `as`*[T: NimGodotObject](obj: NimGodotObject, t: typedesc[T]): T =
|
proc `as`*[T: NimGodotObject](obj: NimGodotObject, t: typedesc[T]): T =
|
||||||
## Converts the ``obj`` into the specified type.
|
## Converts the ``obj`` into the specified type.
|
||||||
## Returns ``nil`` if the conversion cannot be performed
|
## Returns ``nil`` if the conversion cannot be performed
|
||||||
## (the ``obj`` is not of the type ``T``)
|
## (the ``obj`` is not of the type ``T``)
|
||||||
|
##
|
||||||
|
## This can be used either in dot notation (``node.as(Button)``) or
|
||||||
|
## infix notation (``node as Button``).
|
||||||
if obj.isNil or not (obj of T):
|
if obj.isNil or not (obj of T):
|
||||||
when not defined(release):
|
when not defined(release):
|
||||||
if not obj.isNil:
|
if not obj.isNil:
|
||||||
|
|
@ -220,9 +255,6 @@ proc `as`*[T: NimGodotObject](obj: NimGodotObject, t: typedesc[T]): T =
|
||||||
else:
|
else:
|
||||||
result = T(obj)
|
result = T(obj)
|
||||||
|
|
||||||
proc getSingletonGodot*(name: cstring): ptr GodotObject {.
|
|
||||||
importc: "godot_global_get_singleton".}
|
|
||||||
|
|
||||||
proc newRStrLit(s: string): NimNode {.compileTime.} =
|
proc newRStrLit(s: string): NimNode {.compileTime.} =
|
||||||
result = newNimNode(nnkRStrLit)
|
result = newNimNode(nnkRStrLit)
|
||||||
result.strVal = s
|
result.strVal = s
|
||||||
|
|
@ -241,8 +273,11 @@ macro toGodotName(T: typedesc): cstring =
|
||||||
ident("cstring"), newRStrLit(godotName))
|
ident("cstring"), newRStrLit(godotName))
|
||||||
|
|
||||||
proc getSingleton*[T: NimGodotObject](): T =
|
proc getSingleton*[T: NimGodotObject](): T =
|
||||||
|
## Returns singleton of type ``T``. Normally, this should not be used,
|
||||||
|
## because `godotapigen <godotapigen.html>`_ wraps singleton methods so that
|
||||||
|
## singleton objects don't have to be provided as parameters.
|
||||||
const godotName = toGodotName(T)
|
const godotName = toGodotName(T)
|
||||||
let singleton = getSingletonGodot(godotName)
|
let singleton = getGodotSingleton(godotName)
|
||||||
if singleton.isNil:
|
if singleton.isNil:
|
||||||
printError("Tried to get non-existing singleton of type " & $godotName)
|
printError("Tried to get non-existing singleton of type " & $godotName)
|
||||||
else:
|
else:
|
||||||
|
|
@ -285,6 +320,7 @@ proc newOwnObj[T: NimGodotObject](name: cstring): T =
|
||||||
ret.deinit()
|
ret.deinit()
|
||||||
|
|
||||||
proc gdnew*[T: NimGodotObject](): T =
|
proc gdnew*[T: NimGodotObject](): T =
|
||||||
|
## Instantiates new object of type ``T``.
|
||||||
const godotName = toGodotName(T)
|
const godotName = toGodotName(T)
|
||||||
const objInfo = classRegistryStatic[godotName]
|
const objInfo = classRegistryStatic[godotName]
|
||||||
result = when objInfo.isNative:
|
result = when objInfo.isNative:
|
||||||
|
|
@ -292,6 +328,7 @@ proc gdnew*[T: NimGodotObject](): T =
|
||||||
else: newOwnObj[T](godotName)
|
else: newOwnObj[T](godotName)
|
||||||
|
|
||||||
proc newCallError*(err: VariantCallError): ref CallError =
|
proc newCallError*(err: VariantCallError): ref CallError =
|
||||||
|
## Instantiates ``CallError`` from Godot ``err``.
|
||||||
let msg = case err.error:
|
let msg = case err.error:
|
||||||
of VariantCallErrorType.OK,
|
of VariantCallErrorType.OK,
|
||||||
VariantCallErrorType.InvalidMethod,
|
VariantCallErrorType.InvalidMethod,
|
||||||
|
|
@ -307,6 +344,8 @@ proc newCallError*(err: VariantCallError): ref CallError =
|
||||||
result.err = err
|
result.err = err
|
||||||
|
|
||||||
proc newConversionError*(err: ConversionResult): ref ValueError =
|
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:
|
let msg = case err:
|
||||||
of ConversionResult.TypeError:
|
of ConversionResult.TypeError:
|
||||||
"Failed to convert the return value into Nim type"
|
"Failed to convert the return value into Nim type"
|
||||||
|
|
@ -317,28 +356,32 @@ proc newConversionError*(err: ConversionResult): ref ValueError =
|
||||||
|
|
||||||
result = newException(ValueError, msg)
|
result = newException(ValueError, msg)
|
||||||
|
|
||||||
proc removeGodotObject*(nimObj: NimGodotObject) {.inline.} =
|
|
||||||
## Used from destructor
|
|
||||||
nimObj.godotObject = nil
|
|
||||||
|
|
||||||
proc setGodotObject*(nimObj: NimGodotObject, obj: ptr GodotObject) {.inline.} =
|
proc setGodotObject*(nimObj: NimGodotObject, obj: ptr GodotObject) {.inline.} =
|
||||||
|
## Used from Godot constructor. Don't call this.
|
||||||
assert(not obj.isNil)
|
assert(not obj.isNil)
|
||||||
assert(nimObj.godotObject.isNil) # reassignment is not allowed
|
assert(nimObj.godotObject.isNil) # reassignment is not allowed
|
||||||
nimObj.godotObject = obj
|
nimObj.godotObject = obj
|
||||||
|
|
||||||
proc setOwn*(nimObj: NimGodotObject) {.inline.} =
|
proc setOwn*(nimObj: NimGodotObject) {.inline.} =
|
||||||
|
## Used from Godot constructor. Don't call this.
|
||||||
nimObj.isOwn = true
|
nimObj.isOwn = true
|
||||||
|
|
||||||
|
proc removeGodotObject*(nimObj: NimGodotObject) {.inline.} =
|
||||||
|
## Used from Godot destructor. Don't call this.
|
||||||
|
nimObj.godotObject = nil
|
||||||
|
|
||||||
proc godotObject*(nimObj: NimGodotObject): ptr GodotObject {.inline.} =
|
proc godotObject*(nimObj: NimGodotObject): ptr GodotObject {.inline.} =
|
||||||
|
## Returns internal poitner to ``GodotObject``. Use only if you know what
|
||||||
|
## you are doing.
|
||||||
nimObj.godotObject
|
nimObj.godotObject
|
||||||
|
|
||||||
proc godotVariantType*(T: typedesc[NimGodotObject]): VariantType {.inline.} =
|
proc variantType*(T: typedesc[NimGodotObject]): VariantType {.inline.} =
|
||||||
VariantType.Object
|
VariantType.Object
|
||||||
|
|
||||||
proc toGodot*(self: NimGodotObject): Variant {.inline.} =
|
proc toVariant*(self: NimGodotObject): Variant {.inline.} =
|
||||||
newVariant(self.godotObject)
|
newVariant(self.godotObject)
|
||||||
|
|
||||||
proc fromGodot*[T: NimGodotObject](self: var T,
|
proc fromVariant*[T: NimGodotObject](self: var T,
|
||||||
val: Variant): ConversionResult =
|
val: Variant): ConversionResult =
|
||||||
if val.getType() == VariantType.Object:
|
if val.getType() == VariantType.Object:
|
||||||
let objPtr = val.asGodotObject()
|
let objPtr = val.asGodotObject()
|
||||||
|
|
@ -350,27 +393,27 @@ proc fromGodot*[T: NimGodotObject](self: var T,
|
||||||
else:
|
else:
|
||||||
result = ConversionResult.TypeError
|
result = ConversionResult.TypeError
|
||||||
|
|
||||||
proc godotVariantType*(T: typedesc[enum]): VariantType {.inline.} =
|
proc variantType*(T: typedesc[enum]): VariantType {.inline.} =
|
||||||
VariantType.Int
|
VariantType.Int
|
||||||
|
|
||||||
proc toGodot*[T: enum](self: T): Variant {.inline.} =
|
proc toVariant*[T: enum](self: T): Variant {.inline.} =
|
||||||
newVariant(int64(ord(self)))
|
newVariant(int64(ord(self)))
|
||||||
|
|
||||||
proc fromGodot*[T: enum](self: var T,
|
proc fromVariant*[T: enum](self: var T,
|
||||||
val: Variant): ConversionResult {.inline.} =
|
val: Variant): ConversionResult {.inline.} =
|
||||||
if val.getType() == VariantType.Int:
|
if val.getType() == VariantType.Int:
|
||||||
self = T(val.asInt())
|
self = T(val.asInt())
|
||||||
else:
|
else:
|
||||||
result = ConversionResult.TypeError
|
result = ConversionResult.TypeError
|
||||||
|
|
||||||
proc toGodot*(self: Variant): Variant {.inline.} =
|
proc toVariant*(self: Variant): Variant {.inline.} =
|
||||||
self
|
self
|
||||||
|
|
||||||
proc fromGodot*(self: var Variant,
|
proc fromVariant*(self: var Variant,
|
||||||
val: Variant): ConversionResult {.inline.} =
|
val: Variant): ConversionResult {.inline.} =
|
||||||
self = newVariant(val)
|
self = newVariant(val)
|
||||||
|
|
||||||
proc godotVariantType*(T: typedesc[SomeGodotOrNum]): VariantType {.inline.} =
|
proc variantType*(T: typedesc[SomeGodotOrNum]): VariantType {.inline.} =
|
||||||
when T is SomeSignedInt or T is SomeUnsignedInt:
|
when T is SomeSignedInt or T is SomeUnsignedInt:
|
||||||
VariantType.Int
|
VariantType.Int
|
||||||
elif T is bool:
|
elif T is bool:
|
||||||
|
|
@ -426,10 +469,10 @@ proc godotVariantType*(T: typedesc[SomeGodotOrNum]): VariantType {.inline.} =
|
||||||
else:
|
else:
|
||||||
VariantType.Nil
|
VariantType.Nil
|
||||||
|
|
||||||
proc toGodot*[T: SomeGodotOrNum](val: T): Variant {.inline.} =
|
proc toVariant*[T: SomeGodotOrNum](val: T): Variant {.inline.} =
|
||||||
newVariant(val)
|
newVariant(val)
|
||||||
|
|
||||||
proc fromGodot*[T: SomeSignedInt or SomeUnsignedInt](
|
proc fromVariant*[T: SomeSignedInt or SomeUnsignedInt](
|
||||||
self: var T, val: Variant): ConversionResult =
|
self: var T, val: Variant): ConversionResult =
|
||||||
if val.getType() != VariantType.Int:
|
if val.getType() != VariantType.Int:
|
||||||
result = ConversionResult.TypeError
|
result = ConversionResult.TypeError
|
||||||
|
|
@ -443,7 +486,7 @@ proc fromGodot*[T: SomeSignedInt or SomeUnsignedInt](
|
||||||
else:
|
else:
|
||||||
self = T(intVal)
|
self = T(intVal)
|
||||||
|
|
||||||
proc fromGodot*[T: SomeFloat](self: var T, val: Variant): ConversionResult =
|
proc fromVariant*[T: SomeFloat](self: var T, val: Variant): ConversionResult =
|
||||||
if val.getType() == VariantType.Real:
|
if val.getType() == VariantType.Real:
|
||||||
self = T(val.asReal())
|
self = T(val.asReal())
|
||||||
elif val.getType() == VariantType.Int:
|
elif val.getType() == VariantType.Int:
|
||||||
|
|
@ -451,8 +494,8 @@ proc fromGodot*[T: SomeFloat](self: var T, val: Variant): ConversionResult =
|
||||||
else:
|
else:
|
||||||
result = ConversionResult.TypeError
|
result = ConversionResult.TypeError
|
||||||
|
|
||||||
proc fromGodot*[T: SomeGodot](self: var T, val: Variant): ConversionResult =
|
proc fromVariant*[T: SomeGodot](self: var T, val: Variant): ConversionResult =
|
||||||
if godotVariantType(T) != val.getType():
|
if variantType(T) != val.getType():
|
||||||
return ConversionResult.TypeError
|
return ConversionResult.TypeError
|
||||||
when self is bool:
|
when self is bool:
|
||||||
self = val.asBool()
|
self = val.asBool()
|
||||||
|
|
@ -506,13 +549,13 @@ proc fromGodot*[T: SomeGodot](self: var T, val: Variant): ConversionResult =
|
||||||
# mustn't reach this
|
# mustn't reach this
|
||||||
result = ConversionError.TypeError
|
result = ConversionError.TypeError
|
||||||
|
|
||||||
proc godotVariantType*(T: typedesc[string]): VariantType {.inline.} =
|
proc variantType*(T: typedesc[string]): VariantType {.inline.} =
|
||||||
VariantType.String
|
VariantType.String
|
||||||
|
|
||||||
proc toGodot*(s: string): Variant {.inline.} =
|
proc toVariant*(s: string): Variant {.inline.} =
|
||||||
newVariant(s)
|
newVariant(s)
|
||||||
|
|
||||||
proc fromGodot*(s: var string, val: Variant): ConversionResult =
|
proc fromVariant*(s: var string, val: Variant): ConversionResult =
|
||||||
if val.getType() == VariantType.String:
|
if val.getType() == VariantType.String:
|
||||||
s = val.asString()
|
s = val.asString()
|
||||||
elif val.getType() == VariantType.Nil:
|
elif val.getType() == VariantType.Nil:
|
||||||
|
|
@ -520,20 +563,20 @@ proc fromGodot*(s: var string, val: Variant): ConversionResult =
|
||||||
else:
|
else:
|
||||||
result = ConversionResult.TypeError
|
result = ConversionResult.TypeError
|
||||||
|
|
||||||
proc godotVariantType*(T: typedesc[seq]): VariantType =
|
proc variantType*(T: typedesc[seq]): VariantType =
|
||||||
VariantType.Array
|
VariantType.Array
|
||||||
|
|
||||||
proc godotVariantType*(T: typedesc[array]): VariantType =
|
proc variantType*(T: typedesc[array]): VariantType =
|
||||||
VariantType.Array
|
VariantType.Array
|
||||||
|
|
||||||
proc toGodot*[T](s: openarray[T]): Variant =
|
proc toVariant*[T](s: openarray[T]): Variant =
|
||||||
var arr = newArray()
|
var arr = newArray()
|
||||||
mixin toGodot
|
mixin toGodot
|
||||||
for item in s:
|
for item in s:
|
||||||
arr.add(toGodot(item))
|
arr.add(toVariant(item))
|
||||||
result = newVariant(arr)
|
result = newVariant(arr)
|
||||||
|
|
||||||
proc fromGodot*[T](s: var seq[T], val: Variant): ConversionResult =
|
proc fromVariant*[T](s: var seq[T], val: Variant): ConversionResult =
|
||||||
if val.getType() != VariantType.Array:
|
if val.getType() != VariantType.Array:
|
||||||
result = ConversionResult.TypeError
|
result = ConversionResult.TypeError
|
||||||
else:
|
else:
|
||||||
|
|
@ -541,12 +584,12 @@ proc fromGodot*[T](s: var seq[T], val: Variant): ConversionResult =
|
||||||
s = newSeq[T](arr.len)
|
s = newSeq[T](arr.len)
|
||||||
for idx, item in arr:
|
for idx, item in arr:
|
||||||
mixin fromGodot
|
mixin fromGodot
|
||||||
let convResult = fromGodot(s[idx], item)
|
let convResult = fromVariant(s[idx], item)
|
||||||
if convResult != ConversionResult.OK:
|
if convResult != ConversionResult.OK:
|
||||||
s = nil
|
s = nil
|
||||||
return convResult
|
return convResult
|
||||||
|
|
||||||
proc fromGodot*[T: array](s: var T, val: Variant): ConversionResult =
|
proc fromVariant*[T: array](s: var T, val: Variant): ConversionResult =
|
||||||
if val.getType() != VariantType.Array:
|
if val.getType() != VariantType.Array:
|
||||||
result = ConversionResult.TypeError
|
result = ConversionResult.TypeError
|
||||||
else:
|
else:
|
||||||
|
|
@ -555,21 +598,21 @@ proc fromGodot*[T: array](s: var T, val: Variant): ConversionResult =
|
||||||
return ConversionResult.TypeError
|
return ConversionResult.TypeError
|
||||||
for idx, item in arr:
|
for idx, item in arr:
|
||||||
mixin fromGodot
|
mixin fromGodot
|
||||||
let convResult = fromGodot(s[idx], item)
|
let convResult = fromVariant(s[idx], item)
|
||||||
if convResult != ConversionResult.OK:
|
if convResult != ConversionResult.OK:
|
||||||
return convResult
|
return convResult
|
||||||
|
|
||||||
proc godotVariantType*(T: typedesc[Table|TableRef]): VariantType {.inline.} =
|
proc variantType*(T: typedesc[Table|TableRef]): VariantType {.inline.} =
|
||||||
VariantType.Dictionary
|
VariantType.Dictionary
|
||||||
|
|
||||||
proc toGodot*[T: Table or TableRef](t: T): Variant =
|
proc toVariant*[T: Table or TableRef](t: T): Variant =
|
||||||
var dict = newDictionary()
|
var dict = newDictionary()
|
||||||
mixin toGodot
|
mixin toGodot
|
||||||
for k, v in t.pairs():
|
for k, v in t.pairs():
|
||||||
dict[toGodot(k)] = toGodot(v)
|
dict[toVariant(k)] = toVariant(v)
|
||||||
result = newVariant(dict)
|
result = newVariant(dict)
|
||||||
|
|
||||||
proc fromGodot*[T: Table or TableRef](t: var T, val: Variant): ConversionResult =
|
proc fromVariant*[T: Table or TableRef](t: var T, val: Variant): ConversionResult =
|
||||||
if val.getType() != VariantType.Dictionary:
|
if val.getType() != VariantType.Dictionary:
|
||||||
result = ConversionResult.TypeError
|
result = ConversionResult.TypeError
|
||||||
else:
|
else:
|
||||||
|
|
@ -582,31 +625,18 @@ proc fromGodot*[T: Table or TableRef](t: var T, val: Variant): ConversionResult
|
||||||
for k, v in dict:
|
for k, v in dict:
|
||||||
var nimKey: type(t.keys())
|
var nimKey: type(t.keys())
|
||||||
var nimVal: type(t.values())
|
var nimVal: type(t.values())
|
||||||
let keyResult = fromGodot(nimKey, k)
|
let keyResult = fromVariant(nimKey, k)
|
||||||
if keyResult != ConversionResult.OK:
|
if keyResult != ConversionResult.OK:
|
||||||
when t is ref:
|
when t is ref:
|
||||||
t = nil
|
t = nil
|
||||||
return keyResult
|
return keyResult
|
||||||
let valResult = fromGodot(nimVal, v)
|
let valResult = fromVariant(nimVal, v)
|
||||||
if valResult != ConversionResult.OK:
|
if valResult != ConversionResult.OK:
|
||||||
when t is ref:
|
when t is ref:
|
||||||
t = nil
|
t = nil
|
||||||
return valResult
|
return valResult
|
||||||
t[nimKey] = nimVal
|
t[nimKey] = nimVal
|
||||||
|
|
||||||
proc godotToNim*[T](val: Variant): (T, ConversionResult) =
|
|
||||||
mixin fromGodot
|
|
||||||
result[1] = fromGodot(result[0], val)
|
|
||||||
|
|
||||||
proc nimToGodot*[T](val: T): Variant =
|
|
||||||
mixin toGodot
|
|
||||||
when compiles(toGodot(val)):
|
|
||||||
result = toGodot(val)
|
|
||||||
else:
|
|
||||||
printError("Failed to convert Nim value of type " & T.name &
|
|
||||||
" into Variant")
|
|
||||||
initNilVariant(result)
|
|
||||||
|
|
||||||
{.emit: """/*TYPESECTION*/
|
{.emit: """/*TYPESECTION*/
|
||||||
void NimMain(void);
|
void NimMain(void);
|
||||||
N_NOINLINE(void, setStackBottom)(void* thestackbottom);
|
N_NOINLINE(void, setStackBottom)(void* thestackbottom);
|
||||||
|
|
@ -614,6 +644,8 @@ N_NOINLINE(void, setStackBottom)(void* thestackbottom);
|
||||||
|
|
||||||
var nativeLibHandle: pointer
|
var nativeLibHandle: pointer
|
||||||
proc getNativeLibHandle*(): pointer =
|
proc getNativeLibHandle*(): pointer =
|
||||||
|
## Returns NativeScript library handle used to register type information
|
||||||
|
## in Godot. Use only if you know what you are doing.
|
||||||
return nativeLibHandle
|
return nativeLibHandle
|
||||||
|
|
||||||
proc godot_nativescript_init(handle: pointer) {.
|
proc godot_nativescript_init(handle: pointer) {.
|
||||||
|
|
|
||||||
1
godot/nim/nim.cfg
Normal file
1
godot/nim/nim.cfg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
--path:"$projectdir/../"
|
||||||
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>
|
||||||
|
"""
|
||||||
Loading…
Add table
Add a link
Reference in a new issue