*SPACEBOX* is a C++ framework that makes creating cross-platform games and other interactive applications easier and faster by providing an added layer of abstraction between SDL + OpenGL and the project.
Users can start a project by extending only a single function, the Game class's update function. Using a standard Makefile that can be taken from the examples, the framework can export the same code to multiple platforms such as, in order of current stability, Linux, Web, Android, OS X, Windows, and Raspberry Pi.
The repository includes some external libraries in lib/ that the default Makefile included with the demo shows how to compile, but there are other requirements, including external libraries that must be linked to a project in order to compile it.
libSDL2, libSDL2-image, libSDL2-ttf, and libSDL2-mixer must be available to link with your project, so you can try your package manager's libSDL2 dev packages or build from source. The included sdl2-config utility program can be used to generate flags for linking to SDL2 when it is installed outside of your platform's usual library location.
* Install GL/GLES according to your platform and link to it during compilation. GLEW is included in the lib/ folder of this framework and should find GL on your platform (excluding Raspberry Pi and Android) if it is installed.
Building a SPACEBOX project is currently best accomplished by duplicating and adapting the fill_screen demo included in this repository or an in-progress game like [Gunkiss][] or [Pepy][]. The library requirements described above (SDL and OpenGL), a copy of this repository, and a Makefile based on the one in the project being duplicated are necessary for compilation.
This is the platform SPACEBOX is built on, so it has the most straightforward build process. Copy the Makefile from the fill_screen demo, which demonstrates how to compile SPACEBOX and link to required libraries, adapt it to fit a new project, and build a Linux executable with GNU make.
Exporting a browser build with [Emscripten][] and its built-in version of SDL has worked well on a few projects. The general process is to create a separate make target that uses Emscripten's C++ to WebAssembly compiler. See the browser webcam demo below for an example.
Raspberry Pi builds, like Android and Emscripten, require using OpenGL ES. The build process is similar to standard desktop Linux with the `-D __PI__` compiler flag used to activate some Pi-specific code in the framework. GLEW is not available for OpenGL ES, so GLES headers are included directly from the expected system directories.
Otherwise, SDL can be installed in the same way [described above](#libSDL2).
#### KMS
If using the Raspberry Pi without X-windows, SDL will run in KMS mode. The config for the latest versions of the Raspberry Pi OS Lite should be setup correctly by default, and the installation of SDL from source should enable KMS by default if the necessary packages above have been installed. However, it is good to verify that `/boot/config.txt` is setup correctly and that SDL is built with KMS video output enabled.
To verify `/boot/config.txt`, make sure the line `dtoverlay=vc4-kms-v3d` is included in the file. This activates KMS mode for the console instead of either Fake KMS or the older framebuffer modes.
#### Build the `testgles2.c` SDL test
In the SDL source downloaded in the previous step, there is a `test/testgles2.c` program that draws a rotating cube using GLES. This can be used to verify that the SDL installation is working on the Pi.
The [fill_screen demo][] has a working example of how to build for Android. It may be worthwhile to read the [SDL wiki Android page][] and [SDL docs Android README][] and compile an SDL example for Linux before doing a SPACEBOX Android build. The source distributions for SDL, SDL image, SDL ttf, and SDL mixer, and the Android SDK are required.
* Download [Android command line tools][] to that folder, extract them, and install an NDK (the gradle tool included with SDL defaults to NDK 21.4.7075529). Note that the gradle tool may download Android tools, but this step seems to be necessary for signing the license, which gets created in `licenses`
* The APK should be output to `app/build/outputs/apk/debug/app-debug.apk`. It can be uploaded to the phone for testing or run on an emulator. To create an emulator, use the Android SDK's tools. For example, to create an Android emulator for API level 31 (Android 12.0) with ABI x86_64.
# Install a version of command line tools with support for later versions of Java
The [fill_screen demo][] has a Makefile that should work for building for Android if the paths in the file are adjusted to match the project. Edit the Makefile and run `make build/android/[org.my.app]`. If that isn't working, see below for notes on how the build was originally done manually.
These steps were taken to build the fill_screen demo for Android. The Android SDK is assumed to be installed as explained above in the SDL test example. The instructions are based on SDL 2.24.0. There is also a Makefile target that scripts this process in `[demo/fill_screen/Makefile][]`.
* Copy the included Android project in the SDL source into the root of the fill_screen project folder.
$ sed -i 's/^LOCAL_SHARED_LIBRARIES.*/& SDL2_image SDL2_mixer SDL2_ttf/' app/jni/src/Android.mk
* Add SPACEBOX lib/ and src/ to include search path. In this command, the paths are relative to the path of Android.mk and based on the location of fill_screen as included in the SPACEBOX repository, but they can be edited to other paths if necessary.
$ sed -i 's#^LOCAL_C_INCLUDES.*#& $(LOCAL_PATH)/../../../../../../lib $(LOCAL_PATH)/../../../../../../src#' \
app/jni/src/Android.mk
* Add SPACEBOX source files from lib/ src/ and source files for fill_screen
$ sed -i 's#YourSourceHere.c#$(LOCAL_PATH)/../../../../fill_screen.cpp#' app/jni/src/Android.mk
$ sed -i 's#^LOCAL_SRC_FILES.*#& $(wildcard $(LOCAL_PATH)/../../../../../../src/*.cpp)#' app/jni/src/Android.mk
$ sed -i 's#^LOCAL_SRC_FILES.*#& $(wildcard $(LOCAL_PATH)/../../../../../../lib/sdl2-gfx/*.c)#' app/jni/src/Android.mk
* Create a file at `app/src/main/java/ooo/shampoo/fill_screen/FillScreen.java` with the following contents
package ooo.shampoo.fill_screen;
import org.libsdl.app.SDLActivity;
public class FillScreen extends SDLActivity {
protected String getMainFunction() {
return "main";
}
}
* Edit the manifest to point to that class
$ sed -i 's/\(name=\)"SDLActivity"/\1"FillScreen"/' app/src/main/AndroidManifest.xml
Note that `SDL_WINDOW_RESIZABLE` is [required for screen rotation](https://discourse.libsdl.org/t/screen-orientation-not-changing-when-rotating-android-device/26676) to work
*`std::filesystem::exists` will not work with files stored in the Android APK
### Windows
Windows builds are made with MinGW. The box demo contains a make target for building a Windows 32-bit executable from a Linux system. To build from Windows itself, the make target will have to be modified. The SDL MinGW releases and MinGW itself must be downloaded separately.
Download SDL's MinGW libraries from the SDL releases page. Download the libraries for SDL image, SDL mixer, and SDL ttf as well.
Install MinGW. The simplest way to install is through the package manager. On Debian the command is
apt install mingw-w64
See the Windows section of `demo/box/Makefile` for the necessary flags and build process.
#### Cross compilation considerations
*`std::filesystem::path::c_str` returns a `const wchar_t*` instead of `const char*`. To make a platform generic call, convert the path to a string, then use `std::filesystem::path::string::c_str` instead.
* In order to use `std::thread` with MinGW, you must use the POSIX version of the compiler, for example `x86_64-w64-mingw32-g++-posix` and add `-lpthread` to the linker flags.
### OS X
Builds for OS X have only passed the proof of concept phase. An early version of SPACEBOX was compiled for it, but none of the demos have been compiled in their current form, so there is only some broken code available in the box demo's `Makefile`.
The `demo/` folder contains programs that demonstrate and test the capabilities of the framework. In order to compile each, you should edit the definitions in the Makefile.
This is intended to be a bare minimum test of the framework which loads the framework and fills the screen with a new color each frame. It currently builds to Linux and Android.
An example for using a C++ program to display a webcam stream in the browser using Emscripten to translate the code from C++ to WebAssembly. Get the frame pixel data from a canvas element, read it into a SPACEBOX object, write the pixel data to an OpenGL texture, and use Emscripten to display the video.
Map an image from a rectangle to a circle or from a circle to a rectangle using a shader program. Based on a [blog post about elliptical grid mapping equations][].
The specific modules needed may vary depending on the project. See [detailed instructions for building OpenCV on Linux](https://docs.opencv.org/4.6.0/d7/d9f/tutorial_linux_install.html) for more advanced installation. There are also contributed modules available, which can be downloaded separately and compiled with the core modules. For example, this command builds all the modules in `../../opencv_contrib-4.x/modules`, except `python3`, along with the core modules.
To build the WASM libraries necessary to include OpenCV in an Emscripten build of a SPACEBOX project, set up the Emscripten environment and run OpenCV's `build_js.py` script with the WASM output option. Note that OpenCV's `cv::VideoCapture` object will not be available in the libraries built this way because OpenCV emulates that object in its JS implementation.
There is a detailed explanation of this process at [https://docs.opencv.org/4.6.0/d4/da1/tutorial_js_setup.html]. And useful information for getting around the absence of `cv::VideoCapture` at [https://docs.opencv.org/4.6.0/dd/d00/tutorial_js_video_display.html]. Check out a minimal example of using OpenCV with C++ and Emscripten at [https://github.com/mpizenberg/emscripten-opencv]. There is also information on how to build the contributed modules as WASM libraries in the first link.
At the time of writing this, the contributed module for barcode scanning needs `-DBUILD_PROTOBUF=ON` added to the `build_js.py` script and needs `js` added to its list of wrapper languages in its `CMakeLists.txt` file to compile successfully.
To link to the WASM libraries, add the `*.a` files from the build directory to Emscripten's linker flags. Add both `lib/*.a` and `3rdparty/lib/*.a`. For GNU Make, this might look like the following.
Follow the steps at [Building an SDL example for Linux](#building-an-sdl-example-for-linux) up to the NDK installation steps, using 24.0.8215888 as the NDK version. This version or higher is necessary for using cv::VideoCapture.
To build the OpenCV Android SDK, including shared object files, one for each Android ABI, run the `build_sdk.py` script packaged with the OpenCV source.
This builds the local, WASM, and Android libraries by downloading OpenCV 4.7.0 and the contributed modules source packages. See [Gunkiss][] for an example of using these libraries in a project with multiple target platforms.
Use Emscripten's [Fetch API](https://emscripten.org/docs/api_reference/fetch.html) instead of curl
#### Android
There are instructions on how to [build for Android](https://curl.se/docs/install.html#android) in the curl documentation. There is also a project [libcurl-android](https://github.com/ibaoger/libcurl-android) that facilitates the build process.
See how the OpenCV libraries are included in an Android NDK project in the [camera demo](demo/camera) for an example of how to use pre-built shared libraries.
Download from http://zbar.sourceforge.net/download.html and configure to only use image processing features (requires the imagemagickwand library, available from, for example `apt get libmagickwand-dev`) and choose your installation directory:
To build a WASM library that can be used to build an Emscripten version of a SPACEBOX project, set up the Emscripten environment and configure using `emconfigure` with the same disable flags as above.
When initializing a Game object, the framework will attempt to load the font file `BPmono.ttf` from the project root (where the compiled executable is located). If this file isn't found, the program can still run successfully, but the repository contains `BPmono.ttf` if you want to create a symlink to the file in the project root.