Your first TTX Godot project
This walkthrough builds a small Godot application with a counter implemented in its own C++ library. Godot loads the TTX extension, the extension discovers the counter's interface, and a GDScript button calls it. The completed application carries the libraries it needs with it.
Downloading the tools
Install Godot 4.7 or later, Python 3 and Bazel. The example uses the standard Godot editor and a Linux x86-64 build. Bazel acquires the C++ compiler selected by the example's build configuration.
From the Godot extension release, download the Linux x86-64 SDK bundle. It contains the extension, public headers and matching TTX and Perimortem runtimes. The image lab is a separate source example, not part of this bundle.
Create an empty project in Godot's Project Manager and close the editor while installing native libraries. In that project's directory, extract the runtime files and notices:
unzip /path/to/godot-ttx-sdk-linux-x86_64.zip 'addons/*' 'licenses/*'
Building your library
Download the example's C++ source into your project:
curl -L https://raw.githubusercontent.com/tetrodotoxin-dev/Godot/v0.1.0/demo/counter/counter.cpp -o counter.cpp
Create MODULE.bazel with the published compiler toolchain and extension bundle:
module(name = "counter")
bazel_dep(name = "rules_cc", version = "0.2.17")
bazel_dep(name = "platforms", version = "1.0.0")
bazel_dep(name = "tetro_toolchain", version = "0.2.1")
archive_override(
module_name = "tetro_toolchain",
sha256 = "eea7461fb783d2b87a638c4ce1c8d9cbee73e54c90259516ca73cd7e850bdc0f",
urls = ["https://github.com/tetrodotoxin-dev/Toolchain/releases/download/v0.2.1/tetro_toolchain-0.2.1-source.tar.gz"],
)
register_toolchains("@tetro_toolchain//:cc_toolchain_for_linux_x86_64")
http_archive = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "godot_ttx",
urls = ["https://github.com/tetrodotoxin-dev/Godot/releases/download/v0.1.0/godot-ttx-sdk-linux-x86_64.zip"],
# Copy the bundle's SHA256SUMS entry from the release here.
sha256 = "SDK_SHA256",
)
Create BUILD.bazel. The counter has one SDK dependency:
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_cc//cc:cc_shared_library.bzl", "cc_shared_library")
cc_library(
name = "implementation",
srcs = ["counter.cpp"],
copts = ["-fvisibility=hidden"],
deps = ["@godot_ttx"],
)
cc_shared_library(
name = "counter",
shared_lib_name = "libcounter.so",
deps = [":implementation"],
user_link_flags = ["-Wl,-z,defs", "-Wl,-rpath,$ORIGIN"],
)
Create .bazelrc with build --symlink_prefix=.bin/ to keep generated files
out of Godot's resource scan. Then build and install your provider:
bazel build //:counter -c opt
cp .bin/bin/libcounter.so addons/godot_ttx/
Bazel downloads the bundle and builds only counter.cpp. Your project needs
neither Godot's C++ bindings nor the extension's implementation sources.
The public field contracts describe how parameters and results project into
Godot values. TTX checks the representations used to call each method.
Connecting it to Godot
Add these settings to your project's project.godot:
[ttx]
imports={
"counter": "res://addons/godot_ttx/libcounter.so"
}
classes=[{
"module": "counter",
"export": "Counter",
"name": "TtxCounter",
"base": "Node"
}]
imports assigns a project name to the library. The class entry selects its
Counter route and exposes it as TtxCounter, derived from Godot's Node.
Nested routes can use an array, such as "export": ["Tools", "Counter"].
Import project.godot in Godot's Project Manager and open the project. Under
Project > Project Settings > Plugins, enable TTX providers. The native
bridge loads through its .gdextension file; the editor plugin supplies the
provider-library export step.
Create a scene with a VBoxContainer root, a Label named Value, and a
Button named Advance. Set the button's text to "Advance", attach this
script to the root and save the scene as main.tscn:
extends VBoxContainer
var counter = TtxCounter.new()
func _ready() -> void:
add_child(counter)
$Value.text = "0"
$Advance.pressed.connect(_advance)
func _advance() -> void:
$Value.text = str(counter.advance(1))
Run with F5 and select main.tscn as the main scene when prompted.
Press Advance and the displayed count increases.
The scene owns the node after add_child. A second TtxCounter has independent
state. Restart the editor after rebuilding and replacing native libraries so
new instances use the new code.
Exporting the application
Open Project > Export, add a Linux preset and install the matching Godot export templates when prompted. Export the project into an empty directory outside the source tree.
The extension's manifest supplies its runtime dependencies. The TTX providers
plugin copies the libraries selected by ttx/imports, preserving their paths in
the exported application. The counter is handled by that configuration in the
same way as another provider.
Run the exported executable and press Advance. Then copy the entire export
directory to another location and run it again. Copy the SDK's licenses/ directory into the export and distribute the directory as a
whole, including its shared libraries and license notices. The recipient needs
a compatible Linux system, but does not need Bazel, the SDK headers or the
Godot editor.
Adding another provider
Build the provider as another library, add it to ttx/imports, and select the
interfaces you want to register in ttx/classes. A missing route or incompatible
method produces a registration error in Godot's output. Its C++ implementation
can use a different internal model while fulfilling the same published contract.
The image lab supplies a larger example with GDScript and CUDA providers. Its image operations remain application code rather than requirements of the generic extension SDK.