Norx is a highly automated Nim wrapper of the ORX 2.5D game engine library. ORX is written in C99, highly performant and cross platform. Norx makes it quite easy to make ORX based game in Nim.
The wrapper consists of two parts:
wrapper.nim created by Futhark from the ORX headers. It uses "C types" and is fully automatically generated from the C header files. This represents all the functionality in the ORX dynamic library.basics.nim, vector.nim, objects.nim, and the small subsystem modules are created by hand to use Nim style and Nim types and introduce useful overloads, templates, converters, and macros. These are kept up to date manually with new versions of ORX, but an annotation mechanism makes it easier to detect if changes need to be made.The norx.nim module is the one you should import in your Nim code, it exports the other modules including the low level wrapper.nim for direct access to ORX functions and types.
The only things you need to compile a Nim ORX game is this Nimble module and the ORX dynamic library files (liborx[p|d].so|dll) in a proper library path. However, for debugging etc it's more practical to also have the full ORX clone with ORX C sources etc.
First checkout the ORX submodule and build ORX as dynamic libraries (liborx, liborxd and liborxp).
If this is a fresh clone, run:
git submodule update --init
This works on Ubuntu 64 bit (after installing normal C tools with sudo apt-get install gcc g++ make):
./setup.sh inside orx/. On a clean Ubuntu you will be asked to install some libraries: sudo apt install libgl1-mesa-dev libsndfile1-dev libopenal-dev libxrandr-dev. Restart your shell (or logout/login) afterwards to get the $ORX variable set!cd orx/code/build/linux/gmake
make config=debug64
make config=profile64 # optional, only needed for -d:profile builds
make config=release64
On macOS use orx/code/build/mac instead, and the corresponding build directory on Windows.For other platforms, or if you get into trouble, follow the official ORX instructions that give much more detail!
Everything inside this repository — the tests and every sample — links and runs directly against orx/code/lib/dynamic. Each config.nims adds that directory to the linker search path and, on Linux and macOS, embeds an rpath so the resulting binaries also find the libraries at runtime. No sudo cp or ldconfig is required to work inside this repo.
If you develop applications outside this repository you have two choices:
config.nims at the repo libraries the same way this repo does (see below), orsudo cp -a $ORX/lib/dynamic/liborx* /usr/local/lib/
sudo ldconfig
NOTE for newer macOS versions: dylib files in /usr/local/lib are not searched by macOS when running a Norx app (system integrity protection sanitizes the environment). The rpath approach above sidesteps this; alternatively copy the dylibs next to your app executable. See https://developer.apple.com/forums/thread/736719 and https://briandfoy.github.io/macos-s-system-integrity-protection-sanitizes-your-environment/.
Easiest is to use Choosenim curl https://nim-lang.org/choosenim/init.sh -sSf | sh or see Official download.
Install the Norx wrapper by running nimble install in this directory.
Norx uses a build-time linking approach through config.nims files. Each Norx project (including samples) contains a config.nims file that adds the repository's local ORX library directory to the linker search path, embeds an rpath for runtime loading, and selects the appropriate ORX library version based on your build configuration:
import std/os
let rootDir = currentSourcePath().parentDir / "../.."
let orxLibraryDir = normalizedPath(rootDir / "orx/code/lib/dynamic")
switch("passL", "-L" & orxLibraryDir)
when defined(linux) or defined(macosx):
switch("passL", "-Wl,-rpath," & orxLibraryDir)
when defined(release):
switch("passL", "-lorx") # Release version
elif defined(profile):
switch("passL", "-lorxp") # Profile version
else:
switch("passL", "-lorxd") # Debug version (default)
Adjust the rootDir relative path so that orxLibraryDir points at a directory containing the ORX dynamic libraries.
liborxd - includes debug symbols and assertions-d:release): Links to liborx - optimized for performance-d:profile): Links to liborxp - optimized with profiling supportThe system linker automatically handles platform-specific library extensions:
liborx.so, liborxd.so, liborxp.soliborx.dylib, liborxd.dylib, liborxp.dylibliborx.dll, liborxd.dll, liborxp.dllSee samples directory (including samples/official, the official ORX tutorials ported by @jseb) or norxsample. The samples should run fine in at least Linux and OSX. The android-native sample can also be built for Android.
These are the "differences" that you should be aware of when you read ORX documentation/tutorials and apply it to Norx:
orxObject_SetSpeed but in Norx it's setSpeed, first character lower case.orxObject_CreateFromConfig is in Norx objectCreateFromConfig and orxObject_Create is objectCreate. Same goes for Setup, Init, Exit and Get in basically all modules. You can see the list of protectedNames in create_wrapper.nim.orxCHAR * has been mapped to cstring. Common APIs also have string overloads that convert only for the duration of the ORX call, so dynamic Nim strings can be passed without warnings. A raw cstring pointer must not outlive the Nim string that backs it.cstring from ORX you can either keep it as such, but then beware that ORX decides when to deallocate it, or convert it to a Nim string using $ but that will cause a copy of course. The positive is that you are then safe.orxBOOL is kept as a distinct C-sized type for ABI compatibility, with converters in both directions. Use normal Nim booleans in application code: if isActive("Quit"): and object.enable(true).orxSTATUS remains an ORX enum because failure can represent control flow as well as an error. Use status.isSuccess and status.isFailure when a boolean predicate reads more naturally than comparing with STATUS_SUCCESS or STATUS_FAILURE.ptr orxBLABLA and not wrapped by Norx. If you keep such around, remember that they may disappear on you when ORX deallocates!{.cdecl.}, this can be seen in the examples where the update, run, exit, update procs are marked that way.norx.nim so you could quite easily make your own loop instead of creating callbacks and calling execute. See sample2 which does that. Note that this style is NOT the recommended ORX style, since that loop varies depending on platform (Android has some special parts) and normally that loop is in the ORX codebase so if ORX evolves it may change how it is supposed to work.position + velocity * deltaTime and direction.normalize.object.setPosition(addr position) and the more idiomatic object.setPosition(position) remain valid.config.nims files. See the "Library Linking Configuration" section above for details.There is a bash script build.sh that will regenerate the wrapper and the contents of the docs directory.
The documentation is unfortunately not searchable when viewed through the local filesystem, but you can reach the current docs via GitHub Pages:
To enable GitHub Pages: Go to repository Settings → Pages → Source: Deploy from branch → Branch: master, Folder: /docs
This wrapper is kept up to date through the following steps:
git submodule update --init to get the ORX submodule.setup.sh to get all dependencies and to generate orxBuild.h:
cd orx
git fetch
git checkout 1.17
./setup.sh
build.sh in the top-level directory to regenerate and validate the wrapper:
./build.sh
Pass --docs to regenerate the API documentation as well.vector.nim for example. We use annotation.nim to detect via hash if specific parts of the ORX
codebase has changed. Futhark captures everything in the library, but inline functions and C defines and macros are not
captured this way and that is why we use annotation.nim. If the build fails you need to analyze and update Nim code
and update the hashes.Nim
99.3%
Norx is a highly automated Nim wrapper of the ORX 2.5D game engine library. ORX is written in C99, highly performant and cross platform. Norx makes it quite easy to make ORX based game in Nim.
The wrapper consists of two parts:
wrapper.nim created by Futhark from the ORX headers. It uses "C types" and is fully automatically generated from the C header files. This represents all the functionality in the ORX dynamic library.basics.nim, vector.nim, objects.nim, and the small subsystem modules are created by hand to use Nim style and Nim types and introduce useful overloads, templates, converters, and macros. These are kept up to date manually with new versions of ORX, but an annotation mechanism makes it easier to detect if changes need to be made.The norx.nim module is the one you should import in your Nim code, it exports the other modules including the low level wrapper.nim for direct access to ORX functions and types.
The only things you need to compile a Nim ORX game is this Nimble module and the ORX dynamic library files (liborx[p|d].so|dll) in a proper library path. However, for debugging etc it's more practical to also have the full ORX clone with ORX C sources etc.
First checkout the ORX submodule and build ORX as dynamic libraries (liborx, liborxd and liborxp).
If this is a fresh clone, run:
git submodule update --init
This works on Ubuntu 64 bit (after installing normal C tools with sudo apt-get install gcc g++ make):
./setup.sh inside orx/. On a clean Ubuntu you will be asked to install some libraries: sudo apt install libgl1-mesa-dev libsndfile1-dev libopenal-dev libxrandr-dev. Restart your shell (or logout/login) afterwards to get the $ORX variable set!cd orx/code/build/linux/gmake
make config=debug64
make config=profile64 # optional, only needed for -d:profile builds
make config=release64
On macOS use orx/code/build/mac instead, and the corresponding build directory on Windows.For other platforms, or if you get into trouble, follow the official ORX instructions that give much more detail!
Everything inside this repository — the tests and every sample — links and runs directly against orx/code/lib/dynamic. Each config.nims adds that directory to the linker search path and, on Linux and macOS, embeds an rpath so the resulting binaries also find the libraries at runtime. No sudo cp or ldconfig is required to work inside this repo.
If you develop applications outside this repository you have two choices:
config.nims at the repo libraries the same way this repo does (see below), orsudo cp -a $ORX/lib/dynamic/liborx* /usr/local/lib/
sudo ldconfig
NOTE for newer macOS versions: dylib files in /usr/local/lib are not searched by macOS when running a Norx app (system integrity protection sanitizes the environment). The rpath approach above sidesteps this; alternatively copy the dylibs next to your app executable. See https://developer.apple.com/forums/thread/736719 and https://briandfoy.github.io/macos-s-system-integrity-protection-sanitizes-your-environment/.
Easiest is to use Choosenim curl https://nim-lang.org/choosenim/init.sh -sSf | sh or see Official download.
Install the Norx wrapper by running nimble install in this directory.
Norx uses a build-time linking approach through config.nims files. Each Norx project (including samples) contains a config.nims file that adds the repository's local ORX library directory to the linker search path, embeds an rpath for runtime loading, and selects the appropriate ORX library version based on your build configuration:
import std/os
let rootDir = currentSourcePath().parentDir / "../.."
let orxLibraryDir = normalizedPath(rootDir / "orx/code/lib/dynamic")
switch("passL", "-L" & orxLibraryDir)
when defined(linux) or defined(macosx):
switch("passL", "-Wl,-rpath," & orxLibraryDir)
when defined(release):
switch("passL", "-lorx") # Release version
elif defined(profile):
switch("passL", "-lorxp") # Profile version
else:
switch("passL", "-lorxd") # Debug version (default)
Adjust the rootDir relative path so that orxLibraryDir points at a directory containing the ORX dynamic libraries.
liborxd - includes debug symbols and assertions-d:release): Links to liborx - optimized for performance-d:profile): Links to liborxp - optimized with profiling supportThe system linker automatically handles platform-specific library extensions:
liborx.so, liborxd.so, liborxp.soliborx.dylib, liborxd.dylib, liborxp.dylibliborx.dll, liborxd.dll, liborxp.dllSee samples directory (including samples/official, the official ORX tutorials ported by @jseb) or norxsample. The samples should run fine in at least Linux and OSX. The android-native sample can also be built for Android.
These are the "differences" that you should be aware of when you read ORX documentation/tutorials and apply it to Norx:
orxObject_SetSpeed but in Norx it's setSpeed, first character lower case.orxObject_CreateFromConfig is in Norx objectCreateFromConfig and orxObject_Create is objectCreate. Same goes for Setup, Init, Exit and Get in basically all modules. You can see the list of protectedNames in create_wrapper.nim.orxCHAR * has been mapped to cstring. Common APIs also have string overloads that convert only for the duration of the ORX call, so dynamic Nim strings can be passed without warnings. A raw cstring pointer must not outlive the Nim string that backs it.cstring from ORX you can either keep it as such, but then beware that ORX decides when to deallocate it, or convert it to a Nim string using $ but that will cause a copy of course. The positive is that you are then safe.orxBOOL is kept as a distinct C-sized type for ABI compatibility, with converters in both directions. Use normal Nim booleans in application code: if isActive("Quit"): and object.enable(true).orxSTATUS remains an ORX enum because failure can represent control flow as well as an error. Use status.isSuccess and status.isFailure when a boolean predicate reads more naturally than comparing with STATUS_SUCCESS or STATUS_FAILURE.ptr orxBLABLA and not wrapped by Norx. If you keep such around, remember that they may disappear on you when ORX deallocates!{.cdecl.}, this can be seen in the examples where the update, run, exit, update procs are marked that way.norx.nim so you could quite easily make your own loop instead of creating callbacks and calling execute. See sample2 which does that. Note that this style is NOT the recommended ORX style, since that loop varies depending on platform (Android has some special parts) and normally that loop is in the ORX codebase so if ORX evolves it may change how it is supposed to work.position + velocity * deltaTime and direction.normalize.object.setPosition(addr position) and the more idiomatic object.setPosition(position) remain valid.config.nims files. See the "Library Linking Configuration" section above for details.There is a bash script build.sh that will regenerate the wrapper and the contents of the docs directory.
The documentation is unfortunately not searchable when viewed through the local filesystem, but you can reach the current docs via GitHub Pages:
To enable GitHub Pages: Go to repository Settings → Pages → Source: Deploy from branch → Branch: master, Folder: /docs
This wrapper is kept up to date through the following steps:
git submodule update --init to get the ORX submodule.setup.sh to get all dependencies and to generate orxBuild.h:
cd orx
git fetch
git checkout 1.17
./setup.sh
build.sh in the top-level directory to regenerate and validate the wrapper:
./build.sh
Pass --docs to regenerate the API documentation as well.vector.nim for example. We use annotation.nim to detect via hash if specific parts of the ORX
codebase has changed. Futhark captures everything in the library, but inline functions and C defines and macros are not
captured this way and that is why we use annotation.nim. If the build fails you need to analyze and update Nim code
and update the hashes.Nim
99.3%