spacebox/README.md

754 lines
40 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

![logo](icon/static.png)
```
🌊 S P A C E 🪐 🅱 O X 💫
/\ +-------------------------------------------------------+
____/ \____ /| Open source game framework licensed to freely use, |
\ / / | copy, and modify, created for dank.game |
+--\ ^__^ /--+ | |
| ~/ \~ | | Download at https://open.shampoo.ooo/shampoo/spacebox |
| ~~~~~~~~~~~~ | +-------------------------------------------------------+
| SPACE ~~~~~ | /
| ~~~~~~~ BOX |/
+--------------+
```
*SPACE🪐BOX* 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, macOS, Windows, and Raspberry Pi.
It is in an early, untested state. It comes with a few simple examples that demonstrate how to use it.
Requirements
------------
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 (currently tested against 2.26.3)
* libSDL2-image
* libSDL2-ttf
* libSDL2-mixer
* OpenGL/GLES/GLES2
* compiler that supports C++17
Installing Requirements
-----------------------
libSDL2, libSDL2-image, libSDL2-ttf, and libSDL2-mixer must be available to link with your project. Use 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.
### libSDL2
* Download the [SDL source package][]
* Run `./configure --prefix=[YOUR LIBRARIES PATH]` (for example, `$HOME/local/sdl`)
* Run `make && make install`
### libSDL2-image, libSDL2-ttf, libSDL2-mixer
* Download from:
+ https://github.com/libsdl-org/SDL_image
+ https://github.com/libsdl-org/SDL_ttf
+ https://github.com/libsdl-org/SDL_mixer
* Run `./configure --prefix=[YOUR LIB PATH] --with-sdl-prefix=[YOUR SDL PATH]`
* For example, prefix and SDL prefix might be `$HOME/local/sdl`
### OpenGL/GLES/GLES2
* 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.
Builds
------
Building a SPACE🪐BOX project is currently best started 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.
SPACE🪐BOX itself currently needs to be compiled along with the project's source, since there aren't any library builds of it.
### Linux
This is the platform SPACE🪐BOX is built on, so it has the most straightforward build process. Copy the Makefile from the fill_screen demo, which demonstrates how to compile SPACE🪐BOX and link to required libraries, adapt it to fit a new project, and build a Linux executable with GNU make.
#### Linux Distributable
[Stack Overflow thread](https://stackoverflow.com/q/2856438)
There are few techniques that can be used to increase compatibility among Linux versions for the resulting binary.
##### Checking dependencies
Use `readelf` to see which libraries a binary uses and what the extra search path is
$ readelf -d build/x86_64/Cakefoot-linux.x86_64
Dynamic section at offset 0x1a2c10 contains 36 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libSDL2-2.0.so.0]
0x0000000000000001 (NEEDED) Shared library: [libGL.so.1]
0x0000000000000001 (NEEDED) Shared library: [libGLESv2.so.2]
0x0000000000000001 (NEEDED) Shared library: [libSDL2_image-2.0.so.0]
0x0000000000000001 (NEEDED) Shared library: [libSDL2_ttf-2.0.so.0]
0x0000000000000001 (NEEDED) Shared library: [libSDL2_mixer-2.0.so.0]
0x0000000000000001 (NEEDED) Shared library: [libstdc++.so.6]
0x0000000000000001 (NEEDED) Shared library: [libm.so.6]
0x0000000000000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
...
Use `objdump` to see which symbols a binary uses. In this case `ios_base` is needed from `GLIBCXX_3.4.32` (an older version of GLIBCXX couldn't be used for the `ios_base_library_init` symbol during compilation).
$ objdump -x build/x64/Cakefoot-linux.x64 | grep GLIBCXX_3.4.32 | c++filt
0x0297f842 0x00 23 GLIBCXX_3.4.32
0000000000000000 F *UND* 0000000000000000 std::ios_base_library_init()@GLIBCXX_3.4.32
##### Static flags
Adding `-static-libgcc` and `-static-libstdc++` to the linker flags will remove the dependencies on `libstdc++` and `libgcc_s`.
##### Older compiler
Using an older version of GCC to compile can lower the version of some symbols.
##### Packaging shared libraries
The `rpath` property can be used to add a local library search path to the linker, and any libraries to package with the distributable can be added to the local path. For example, this is how SDL is packaged with Cakefoot.
This flag is used to add a relative library lookup path
-Wl,-rpath $(X64_BUILD_LIB_DIR)
This block is used to copy the SDL libraries into the local library folder
cp $$(ldd $(X64_BUILD_DIR)/$@ | grep libSDL2-2.0 | cut -d" " -f3) \
$$(ldd $(X64_BUILD_DIR)/$@ | grep libSDL2_image | cut -d" " -f3) \
$$(ldd $(X64_BUILD_DIR)/$@ | grep libSDL2_ttf | cut -d" " -f3) \
$$(ldd $(X64_BUILD_DIR)/$@ | grep libSDL2_mixer | cut -d" " -f3) ${basename $@}/$(X64_BUILD_LIB_DIR)
##### Virtualization using Docker
Docker can be used to compile for a target platform with a desired baseline compatibility profile, for example, Ubuntu 16.04.
apt install docker.io
Make sure your user has sudo permissions to use `/usr/bin/docker` by editing either `/etc/sudoers/` or a file in `/etc/sudoers.d/`. Then pull the Ubuntu 16.04 image.
sudo docker pull ubuntu:16.04
### Emscripten
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
Raspberry Pi builds, like Android and Emscripten, require using OpenGL ES. The build process is similar to standard desktop Linux.
GLEW is not available for OpenGL ES, so GLES headers are included directly from the expected system directories.
The flag `-DGLEW_NO_GLU` may also be necessary since there may not be a `glu.h` file on Raspberry Pi installations. This flag can also just be used by default because GLU is deprecated.
#### SDL
SDL should be built with `--enable-video-kmsdrm`. This will require the installation of external packages. OpenGL ES will also need to be installed.
sudo apt install libgbm-dev libdrm-dev libegl-dev libgles2-mesa-dev
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/firmware/config.txt` is setup correctly and that SDL is built with KMS video output enabled.
To verify `/boot/firmware/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.
cd [SDL_source]/test/
gcc $(sdl-config --cflags --libs) -LSDL_test -o testgles
./testgles
#### Raspberry Pi Model 3B+
This model only supports up to Open GL ES 2.0.
#### Raspberry Pi Model 4
This model supports up to Open GL ES 3.2.
#### External demos
Try these non-SPACEBOX demos for verifying the Raspberry Pi OpenGL ES setup with KMS.
* [kmscube](https://gitlab.freedesktop.org/mesa/kmscube)
* [KMS GLSL](https://github.com/astefanutti/kms-glsl)
### Android
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.
After building the demo, see the following for further information on using SDL on Android.
* [SDL wiki](https://wiki.libsdl.org/Android)
* [SDL Android README](https://github.com/libsdl-org/SDL/blob/main/docs/README-android.md)
* In the SDL source package, `SDL_android.h` and the Android section of `SDL_system.h`
#### Building an SDL example for Linux
* Install Java packages
apt install openjdk-17-jdk ant
* Make a folder for Android to store the SDK, NDK, emulator, tools, etc.
mkdir -p ~/local/Android/
* 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`
$ cd ~/local/Android/
$ unzip commandlinetools-linux-8512546_latest.zip
$ cmdline-tools/bin/sdkmanager --sdk_root=$HOME/local/Android/ "ndk;21.4.7075529"
* Download and extract [SDL source][]
$ wget "https://github.com/libsdl-org/SDL/releases/download/release-2.24.0/SDL2-2.24.0.tar.gz"
$ tar -xf SDL2-2.24.0.tar.gz
$ cd SDL2-2.24.0/
* Copy `android-project/` to another folder, symlink the SDL source,
$ cp -r android-project org.my.testgles
$ cd org.my.testgles/app/jni
$ ln -s ../../.. SDL
* Edit the line with `YourSourcehere.c` in `org.my.testgles/app/jni/src/Android.mk` to point to an SDL example
$ cd src/ && sed -i s#YourSourceHere.c#../SDL/test/testgles.c# Android.mk
* Build with `gradlew` in the root of the project, specifying where to find the Android folder
$ ANDROID_SDK_ROOT=$HOME/local/Android ./gradlew build
* 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
$ cmdline-tools/bin/sdkmanager --sdk_root=$HOME/local/Android "cmdline-tools;latest"
# Install a system image
$ cmdline-tools/bin/sdkmanager --sdk_root=$HOME/local/Android "system-images;android-31;default;x86_64"
# Create emulator
$ cmdline-tools/latest/bin/avdmanager create avd -n android_31_x86_64 -k "system-images;android-31;default;x86_64"
# Launch in the background
$ ~/local/Android/tools/emulator -avd android_31_x86_64 &
# Install the APK to the running emulator
$ ~/local/Android/platform-tools/adb -e install -r app/build/outputs/apk/debug/app-debug.apk
# Start the log viewer
$ ~/local/Android/platform-tools/adb [-s device_name] logcat
#### fill_screen demo
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.
#### Custom assets
Assets can be copied to `app/src/main/assets`. The [box demo](demo/box) has an example of how to include custom assets like config JSON and shaders.
##### Creating the fill_screen Android build
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.
$ cp -r path/to/SDL2-2.24.0/android-project [fill_screen root]/ooo.shampoo.fill_screen
$ cd [fill_screen root]/ooo.shampoo.fill_screen
* Edit the application ID
$ sed -i s/org.libsdl.app/ooo.shampoo.fill_screen/ app/build.gradle app/src/main/AndroidManifest.xml
* Enable C++ STL
$ sed -i "s/^#.*\(APP_STL\)/\1/" app/jni/Application.mk
* Enable C++ 17 features and exceptions
$ echo "APP_CPPFLAGS := -std=c++17 -fexceptions -frtti" >> app/jni/Application.mk
* Modify rules to allow OpenGL ES 3.0 (necessary for example for using GL_RGBA8)
$ sed -i -e 's/^LOCAL_LDLIBS.*/& -lGLESv3/' app/jni/src/Android.mk
$ sed -i 's/0x0002/0x0003/' app/src/main/AndroidManifest.xml
$ sed -i 's/\(minSdkVersion\).*16/\1 18/' app/build.gradle
$ sed -i 's/\(android\)-16/\1-18/' app/build.gradle app/jni/Application.mk
* `std::filesystem` is only available in NDK 22+, so install NDK version 22 and set the project to use it
$ ~/local/Android/cmdline-tools/bin/sdkmanager --sdk_root=$HOME/local/Android --install "ndk;22.1.7171670"
$ sed -i '11i\ ndkVersion "22.1.7171670"' app/build.gradle
* Link to SDL source packages (versions other than the listed ones may work)
$ ln -s path/to/SDL2-2.24.0 app/jni/SDL
$ ln -s path/to/SDL2_image-2.6.2 app/jni/SDL2_image
$ ln -s path/to/SDL2_mixer-2.6.2 app/jni/SDL2_mixer
$ ln -s path/to/SDL2_ttf-2.20.1 app/jni/SDL2_ttf
* Add SDL packages as libraries in the Makefile
$ 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
* Run gradle
$ ANDROID_SDK_ROOT=$HOME/local/Android ./gradlew build
#### Screen rotation
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
#### Cross compilation considerations
* `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.
mkdir SDL2-mingw
cd SDL2-mingw
wget "https://github.com/libsdl-org/SDL/releases/download/release-2.24.2/SDL2-devel-2.24.2-mingw.zip"
unzip SDL2-devel-2.24.2-mingw.zip
wget "https://github.com/libsdl-org/SDL_image/releases/download/prerelease-2.5.2/SDL2_image-devel-2.5.2-mingw.tar.gz"
tar -xf SDL2_image-devel-2.5.2-mingw.tar.gz
wget "https://github.com/libsdl-org/SDL_ttf/releases/download/release-2.0.15/SDL2_ttf-devel-2.0.15-mingw.tar.gz"
tar -xf SDL2_ttf-devel-2.0.15-mingw.tar.gz
wget "https://github.com/libsdl-org/SDL_mixer/releases/download/prerelease-2.5.2/SDL2_mixer-devel-2.5.2-mingw.tar.gz"
tar -xf SDL2_mixer-devel-2.5.2-mingw.tar.gz
Install MinGW. The simplest way to install is through the package manager. On Debian the command is
apt install mingw-w64
Add `-DGLEW_STATIC` to compile the GLEW library into a [SPACE BOX] project using MinGW.
Add `-static-libgcc` and `-static-libstdc++` to the linker flags to compile GCC and C++ STD runtime DLLs into the executable instead of distributing the DLL file with the executable.
Add `-mwindows` to the linker flags to prevent Windows from opening a console window in the background when launching the game.
See the Windows section of `demo/box/Makefile` for a complete list of 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.
### macOS
[SDL Wiki - macOS](https://wiki.libsdl.org/SDL2/Installation#macos)
To fully support macOS, both Intel `x86_64-macos` and ARM `aarch64-macos` architecture versions must be compiled.
Make sure the version of macOS on the build host system is supported by the version of SDL being used. There is information in the documentation in the SDL source at `SDL2-2.X.X/docs/README-macos.md`. If necessary, upgrade the macOS operating system, using the [official Apple support links](https://support.apple.com/en-us/102662), or downgrade SDL by [downloading a lower version](https://github.com/libsdl-org/SDL/releases/).
To begin compiling for macOS, clone the cross compilation toolkit [osxcross tool](https://github.com/tpoechtrager/osxcross)
git clone https://github.com/tpoechtrager/osxcross
Install necessary packages
apt install clang make libssl-dev lzma-dev libxml2-dev xz-utils bzip2 cpio zlib1g-dev
Download the [Xcode XIP archive](https://developer.apple.com/download/all/?q=xcode) to the root of the repository and use the toolkit to generate the SDK as a TAR archive
./tools/gen_sdk_package_pbzx.sh <xcode>.xip
Move the SDK TAR archive into `tarballs/` and run the build script at the root of the repository
./build.sh
Add the `bin/` directory to `PATH`
PATH=$PATH:/media/gdrive/osxcross/target/bin/
Get the target value from `osxcross-conf`. In this case it's `darwin20.4`
$ target/bin/osxcross-conf
export OSXCROSS_VERSION=1.5
export OSXCROSS_OSX_VERSION_MIN=10.9
export OSXCROSS_TARGET=darwin20.4
...
Update references to OpenGL for macOS if necessary. See this [thread about alternatives to OpenGL on Mac](https://stackoverflow.com/a/65806319/) for future concerns about OpenGL on macOS. This is currently handled in SPACE🪐BOX with the following pre-processor directive.
#if defined(__MACOS__)
#define GL_SILENCE_DEPRECATION
#include <OpenGL/gl3.h>
#endif
Get the SDL Framework DMG releases so SDL can be included in the project. The following is a build target for creating a signed and notarized app bundle and DMG of Cakefoot for macOS. There are some important parts to be expanded on in a future update, including linking to frameworks, using an rpath, compiling with a deployment target and universal architecture, and creating an app bundle along with its Info.plist. The signing and notarization process is explained in the next section.
MACOS_CROSS_ROOT = /media/gdrive/osxcross
MACOS_CROSS_FW = $(MACOS_CROSS_ROOT)/local/Frameworks
MACOS_CFLAGS = -Wall -Wextra -O3 -c -I$(SB_LIB_DIR) -I$(SB_SRC_DIR) -DGLEW_STATIC -DGLEW_NO_GLU -F$(MACOS_CROSS_FW) \
-I$(MACOS_CROSS_FW)/SDL2.framework/Headers -I$(MACOS_CROSS_FW)/SDL2_image.framework/Headers \
-I$(MACOS_CROSS_FW)/SDL2_ttf.framework/Headers -I$(MACOS_CROSS_FW)/SDL2_mixer.framework/Headers -D__MACOS__ -D__APPLE__
MACOS_CXXFLAGS = $(CFLAGS) --std=c++17
MACOS_LFLAGS = -Wl,-rpath,@executable_path/../Frameworks -pthread -F$(MACOS_CROSS_FW) -framework SDL2 \
-framework SDL2_image -framework SDL2_ttf -framework SDL2_mixer -framework OpenGL
MACOS_OBJ = $(addprefix $(MACOS_BUILD_DIR)/, glew.o SDL2_rotozoom.o SDL2_gfxPrimitives.o $(SB_O_FILES) $(SRC_O_FILES))
MACOS_BUNDLE = $(MACOS_BUILD_DIR)/dmg/$@
MACOS_BUNDLE_CONTENTS = $(MACOS_BUILD_DIR)/dmg/$@/Contents
MACOS_CROSS_BIN = $(MACOS_CROSS_ROOT)/target/bin
MACOS_CERTIFICATE = local/Cakefoot_MacOS_DeveloperID_Application.pem
MACOS_RCODESIGN = ~/ext/software/apple-codesign-0.27.0/rcodesign
Cakefoot.app : CC = MACOSX_DEPLOYMENT_TARGET=11.3 PATH=$(PATH):$(MACOS_CROSS_BIN) o64-clang -arch arm64 -arch x86_64
Cakefoot.app : CXX = MACOSX_DEPLOYMENT_TARGET=11.3 PATH=$(PATH):$(MACOS_CROSS_BIN) o64-clang++ -arch arm64 -arch x86_64
Cakefoot.app : CFLAGS = $(MACOS_CFLAGS)
Cakefoot.app : CXXFLAGS = $(MACOS_CXXFLAGS)
Cakefoot.app : LFLAGS = $(MACOS_LFLAGS)
Cakefoot.app : $(MACOS_OBJ)
mkdir -p $(MACOS_BUNDLE_CONTENTS)/MacOS $(MACOS_BUNDLE_CONTENTS)/Frameworks $(MACOS_BUNDLE_CONTENTS)/Resources
cp src/Info.plist $(MACOS_BUNDLE_CONTENTS)
cp -r $(MACOS_CROSS_FW)/SDL2*.framework $(MACOS_BUNDLE_CONTENTS)/Frameworks
$(CXX) $^ $(LFLAGS) -o $(MACOS_BUNDLE_CONTENTS)/MacOS/$(basename $@)
rsync -arRL resource/ src/shaders/ config.json $(MACOS_BUNDLE_CONTENTS)/Resources
$(MACOS_RCODESIGN) sign --for-notarization --code-signature-flags runtime --pem-file $(MACOS_CERTIFICATE) $(MACOS_BUNDLE)
notarize :
$(MACOS_RCODESIGN) notary-submit --api-key-file local/Cakefoot_App_Store_Connect_API_key.json --staple \
$(MACOS_BUILD_DIR)/dmg/Cakefoot.app
cd $(MACOS_BUILD_DIR) && genisoimage -V Cakefoot -D -R -apple -no-pad -hide-rr-moved -o Cakefoot.dmg dmg && cd -
#### Signing a DMG
Download [Apple Codesign Tools](https://gregoryszorc.com/docs/apple-codesign/0.27.0/apple_codesign_getting_started.html)
wget https://github.com/indygreg/apple-platform-rs/releases/download/apple-codesign/0.27.0/apple-codesign-0.27.0-x86_64-unknown-linux-musl.tar.gz
Generate a Certificate Signing Request
openssl genrsa -out local/Cakefoot_CSR_key.pem 2048
rcodesign generate-certificate-signing-request --pem-file local/Cakefoot_CSR_key.pem --csr-pem-file \
local/Cakefoot_Certificate_Signing_Request.pem
Or [generate certificates using Xcode on MacOS](https://help.apple.com/xcode/mac/current/#/dev154b28f09)
Exchange the Certificate Signing Request (CSR) for a Code Signing Certificate (CSC)
1. Go to https://developer.apple.com/account/resources/certificates/add (you must be logged into Apples website)
2. Select the certificate flavor you want to issue.
3. Click Continue to advance to the next form.
4. Select the G2 Sub-CA (Xcode 11.4.1 or later) Profile Type (we support it).
5. Choose the file containing your CSR.
6. Click Continue.
7. If all goes according to plan, you should see a page saying Download Your Certificate.
8. Click the Download button.
9. Save the certificate somewhere. (Saved below as `Cakefoot_MacOS_DeveloperID_Application.crt`)
View the certificate
openssl x509 -in local/Cakefoot_MacOS_DeveloperID_Application.cer -text -noout
Combine the certificate with the private key into a single PEM file
openssl x509 -inform der -in Cakefoot_MacOS_DeveloperID_Application.cer -out Cakefoot_MacOS_DeveloperID_Application.pem
cat local/Cakefoot_CSR_key.pm >> Cakefoot_MacOS_DeveloperID_Application.pem
Sign the Application Bundle (in-place)
rcodesign sign --for-notarization --code-signature-flags runtime \
--pem-file local/Cakefoot_MacOS_DeveloperID_Application.pem Cakefoot.app
To view the signature info of a signed app on MacOS
codesign --display --verbose=4 /Volumes/Cakefoot/Cakefoot.app
To notarize, [generate](https://appstoreconnect.apple.com/access/integrations/api) a team API key with Developer access role. Download it to a path, for example `Cakefoot_App_Store_Connect_API_key_33UBLVSW4Y.p8`. Use the `Issuer ID` and `KEY ID` from the Apple Developer site combined with the downloaded file to create a JSON document. Submit a request for notarization, wait for the response, and automatically staple.
rcodesign notary-submit --api-key-file local/Cakefoot_App_Store_Connect_API_key.json --staple build/macos/dmg/Cakefoot.app
Check the app bundle on MacOS
codesign --verify --verbose Cakefoot.app
spctl -a -t exec -vv Cakefoot.app
Debugging notes
* Make sure there are no absolute paths other than system libraries in the binary by verifying with `otool -l /path/to/binary`. In the case of Cakefoot, an unnecessary absolute `rpath` was erroneously being added in a previous version of the build script. See [this thread](https://stackoverflow.com/q/31709087/1256386) for more info.
* Make sure the ZIP archive of the app bundle is zipped with `--symlinks` to prevent creating extra copies of the contents of the linked directories in the framework folders. In addition to taking up more space, removing the symlinks will cause the app to fail against the `spctl` test and Gatekeeper.
* Gatekeeper seems to require that `Info.plist` has the `CFBundlePackageType` key set to `APPL`.
* An application downloaded from the internet can be flagged as quarantined regardless of whether it is certified and notarized. The quarantine flag is controlled by the application which downloads the file, and it seems like web browsers on MacOS are configured to quarantine files. When an application is quarantined, it is moved into the `/private/var/` directory. When Cakefoot is directly downloaded from the web in DMG format, it is flagged to be quarantined, and an unknown reason related to quarantining cause the game to crash. The current less than ideal solution is to move Cakefoot out of the DMG into another folder, for example `/System/Applications` or `/Users/[user]/Desktop`.
* Possibly useful entitlements that would be added to a plist file `Cakefoot.entitlements`
com.apple.security.app-sandbox (set to false)
com.apple.security.cs.allow-unsigned-executable-memory
com.apple.security.cs.disable-executable-page-protection
com.apple.security.cs.disable-library-validation
com.apple.security.cs.allow-dyld-environment-variables (needed by Steam API)
Demos
-----
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.
### [Fill screen](demo/fill_screen)
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.
### [Box](demo/box)
Test OpenGL context by drawing a textured, rotating cube. It currently builds to Linux, Android, and web browsers.
### [Browser webcam](demo/browser_webcam_test)
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.
### [Squircle](demo/squircle)
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][].
### [OpenCV camera](demo/camera)
Get camera input using the OpenCV library on Linux or Android.
Other libraries
---------------
These are other libraries that have been used in projects that use this framework but aren't required by the framework
### OpenCV
Download [a source package](https://opencv.org/releases/) and follow the specific instructions for each platform.
#### Linux
Create a build directory, then configure and make. This example uses a custom installation path `~/local/opencv`:
$ mkdir build_linux/ && cd build_linux/
$ cmake -DCMAKE_INSTALL_PREFIX=$HOME/local/opencv ..
$ make && make install
The `core`, `imgproc`, `videoio`, and `highgui` modules can then be linked to by adding the following to the linker flags:
-L$(HOME)/local/opencv/lib -Wl,-rpath,$(HOME)/local/opencv/lib -lopencv_videoio -lopencv_core -lopencv_highgui \
-lopencv_imgproc
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.
$ cmake -D CMAKE_INSTALL_PREFIX=$HOME/local/opencv -D OPENCV_EXTRA_MODULES_PATH="../../opencv_contrib-4.x/modules" -D \
BUILD_opencv_python3=OFF ..
#### Emscripten
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.
$ source [EMSDK_PATH]/emsdk_env.sh
$ python3 [OPENCV_PATH]/platforms/js/build_js.py --emscripten_dir [EMSCRIPTEN_PATH] build_wasm --build_wasm
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.
$(wildcard $(addprefix $(WASM_BUILD_DIR)/lib/,*.a)) $(wildcard $(addprefix $(WASM_BUILD_DIR)/3rdparty/lib/,*.a))
#### Android
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.
$ ~/local/Android/cmdline-tools/bin/sdkmanager --sdk_root=$HOME/local/Android --install "ndk;24.0.8215888"
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.
$ cd [opencv_source]
$ python3 platforms/android/build_sdk.py --sdk_path ~/local/Android/ --ndk_path ~/local/Android/ndk/24.0.8215888/ \
--extra_modules_path ../opencv_contrib-4.7.0-subset/ --shared --no_samples_build \
--config ndk-18-api-level-24.config.py build_android/
$ ls -R build_android/OpenCV-android-sdk/sdk/native/libs/
build_android/OpenCV-android-sdk/sdk/native/libs/:
arm64-v8a armeabi-v7a x86 x86_64
build_android/OpenCV-android-sdk/sdk/native/libs/arm64-v8a:
libopencv_world.so libtbb.so
build_android/OpenCV-android-sdk/sdk/native/libs/armeabi-v7a:
libopencv_world.so libtbb.so
build_android/OpenCV-android-sdk/sdk/native/libs/x86:
libopencv_world.so libtbb.so
build_android/OpenCV-android-sdk/sdk/native/libs/x86_64:
libopencv_world.so libtbb.so
This SDK can be included in an Android NDK project. See the [camera demo](demo/camera) for an example of how to add it to a SPACEBOX project build.
#### Full example
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.
$ wget https://github.com/opencv/opencv/archive/4.7.0.zip
$ unzip 4.7.0.zip
$ tar -xf opencv_contrib-4.7.0.tar.gz
$ mkdir opencv_contrib-4.7.0-subset
$ cp -r opencv_contrib-4.7.0/modules/barcode/ opencv_contrib-4.7.0-subset/
$ rm -rf ~/local/opencv/
$ cd opencv-4.7.0/
$ mkdir build_linux
$ cd build_linux/
$ cmake -D CMAKE_INSTALL_PREFIX=$HOME/local/opencv -D OPENCV_EXTRA_MODULES_PATH="../../opencv_contrib-4.7.0-subset/" ..
...
-- OpenCV modules:
-- To be built: barcode calib3d core dnn features2d flann gapi highgui imgcodecs imgproc java ml objdetect
photo python3 stitching ts video videoio
...
$ make -j3 && make install
$ cd ..
$ source ~/ext/software/emsdk/emsdk_env.sh
$ python3 platforms/js/build_js.py --cmake_option="-DOPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-4.7.0-subset/" \
--emscripten_dir ~/ext/software/emsdk/upstream/emscripten build_wasm_contrib --build_wasm
$ python3 platforms/android/build_sdk.py --sdk_path ~/local/Android/ --ndk_path ~/local/Android/ndk/22.1.7171670/ \
--extra_modules_path ../opencv_contrib-4.7.0-subset/ --shared --no_samples_build build_android/
### curl
#### Linux
Install from the package manager
sudo apt install libcurl4-openssl-dev
#### Emscripten
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.
$ git clone --recursive https://github.com/ibaoger/libcurl-android
Add `x86` to the `APP_ABI` parameter in `build_for_android.sh`. Then run the build script.
$ NDK_ROOT=/path/to/NDK ./build_for_android.sh
The libraries should be written the `jni/build` folder. The folder `libs/x86-64` should actually be named `libs/x86_64`, so rename it.
$ mv jni/build/zlib/x86-64 jni/build/zlib/x86_64
$ mv jni/build/curl/x86-64 jni/build/curl/x86_64
$ mv jni/build/openssl/x86-64/ jni/build/openssl/x86_64
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.
### ZBar
#### Linux
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:
./configure --without-gtk --without-python --without-qt --without-xshm --without-xv --without-jpeg \
--disable-video --prefix=$HOME/local/zbar
make
make && make install
#### Emscripten
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.
$ source emsdk_env.sh
$ emconfigure ./configure --without-gtk --without-python --without-qt --without-xshm --without-xv --without-jpeg \
--disable-video
$ emmake make
$ find . -iname *.a
./zbar/.libs/libzbar.a
There is a detailed tutorial on using Zbar with WebAssembly at https://barkeywolf.consulting/posts/barcode-scanner-webassembly/
External Resources
------------------
* [Khronos's OpenGL and GLSL wiki](https://www.khronos.org/opengl/wiki/Main_Page)
* [docs.gl: official OpenGL API documentation with added features](https://docs.gl)
* [MDN's list of best practices for WebGL](https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_best_practices)
* [Emscripten documentation's chapter on optimizing for WebGL](https://emscripten.org/docs/optimizing/Optimizing-WebGL.html)
* [SDL wiki](https://wiki.libsdl.org)
* [Webassembly memory debugging article](https://web.dev/webassembly-memory-debugging/)
Font
----
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.
License
-------
SPACE🪐BOX is released under the zlib license. It is free to use, copy, modify and sell. See [LICENSE.txt](LICENSE.txt) for details.
Included libraries are included under various permissive licenses compatible with the zlib license:
* BPmono.ttf is licensed under the Creative Commons Attribution, No Derivative Works 3.0 license. See [LICENSE_BPmono.txt]()
* gif-h is unlicensed, public domain code released under the The Unlicense. See [lib/gif-h/LICENSE]()
* GLEW is included under the license in [lib/glew/LICENSE.txt]()
* GLM is included under the MIT license in [lib/glm/LICENSE]()
* nlohmann's json library is included under the MIT license in [lib/json/LICENSE.MIT]()
* SDL2 GFX is included under the license in [lib/sdl2-gfx/LICENSE]()
* superxbr.cpp is included under the license at the top of [lib/superxbr.cpp]()
Contact
-------
| Method | Contact information |
| :------ | :---------------------------- |
| E-mail | cocktail.frank@dank.game |
| Web | <https://dank.game> |
| X | <https://x.com/diskmem> |
| PayPal | <https://paypal.me/ohsqueezy> |
[SDL wiki Android page]: https://wiki.libsdl.org/Android
[SDL docs Android README]: https://github.com/libsdl-org/SDL/blob/main/docs/README-android.md
[SDL source]: https://github.com/libsdl-org/SDL/releases/
[Android command line tools]: https://developer.android.com/studio#command-tools
[SDL source package]: http://libsdl.org/download-2.0.php
[blog post about elliptical grid mapping equations]: http://squircular.blogspot.com/2015/09/mapping-circle-to-square.html
[Emscripten]: https://emscripten.org/
[Gunkiss]: https://open.shampoo.ooo/shampoo/gunkiss
[Pepy]: https://open.shampoo.ooo/shampoo/pepy
[demo/fill_screen/Makefile]: demo/fill_screen/Makefile
[fill_screen demo]: demo/fill_screen