Table of Contents
1. Mbm Engine¶
MBM is a given name to a graphics engine which provides basic and essential resources to develop games or graphics applications 2D or 3D.
For now, is possible to develop games for Windows , Linux , and Android .
The intention is to provide the minimum necessary for game development or graphics application using minimal dependencies.
The engine is written in C++11 language using OpenGL-ES on its core and LUA as a scripting language.
Note
Although there is an effort to migrate the whole project to C++11 still there is a lot of mixed C code and maybe is not the best project to be as an example!
1.1. Another Game Engine!¶
Yes I know!
This is a personal project that I have been working for a long time (~ 2004).
It started as a way to understand C++, DirectX, 2D, 3D, geometry etc (at the time). How games in general works.
Then, I have learned more about game programming and, in the beginning, it was used the concept of framework a lot, which later, became a game engine embeding LUA script.
Of course, I had (and still have) to do a lot of improvement/refactoring and also make new features as well! (You might find some comments or variable names in portuguese BR since at the time I used to program in my on language ¯\_(ツ)_/¯)
But life is the greatest teacher and I have decided to go ahead and make new features, improvements or refactoring according to the demands.
It means that when some work in as a new game requires some feature or improvements it is implemented.
So, if you want to use it, go ahead and occasionally new features or improvements will come (¬‿¬).
1.2. Which version should I get?¶
I occasionally tag versions however it is generally safe and recommended to sync to the master.
The library is fairly stable for 2D applications and issues tend to be fixed as fast as reported/faced.
1.3. Looking for binary?¶
Here the latest binaries for Windows.
Here the latest binaries for Android.
For Linux you must compile by yourself.
1.4. Main Libraries And Status¶
Library |
Version |
Windows |
Linux |
Android |
Required |
Status |
---|---|---|---|---|---|---|
2.0 |
YES |
YES |
YES |
YES |
Complete |
|
2.0 |
YES |
NO |
NO |
Windows |
Complete |
|
5.4.1 |
YES |
YES |
YES |
NO |
Complete |
|
20151024 |
YES |
YES |
YES |
YES |
Complete |
|
2.3.1 |
YES |
YES |
YES |
NO |
Stable |
|
1.1.0
2.3.0
|
YES |
YES |
YES |
NO |
Stable |
|
2.84 |
YES |
YES |
YES |
NO |
in Progress |
|
0.9.5 |
YES |
YES |
YES |
NO |
Complete |
|
3.24 |
YES |
YES |
YES |
NO |
Complete |
|
3.0.9 |
YES |
YES |
YES |
NO |
Complete |
|
1.9.4 |
YES |
NO |
NO |
Windows |
Complete |
|
19 |
NO |
YES |
NO |
Linux |
in Progress |
|
1.0 |
YES |
NO |
NO |
Windows |
Complete |
|
1.11 |
YES |
YES |
YES |
YES |
Complete |
|
1.16 |
YES |
YES |
YES |
YES |
Complete |
|
1.75 |
YES |
YES |
NO |
NO |
Stable |
|
Audio |
|
|
|
NO |
in Progress |
- OpenGL ES
OpenGL ES is a royalty-free, cross-platform API for rendering advanced 2D and 3D graphics on embedded and mobile systems - including consoles, phones, appliances and vehicles. It consists of a well-defined subset of desktop OpenGL suitable for low-power devices, and provides a flexible and powerful interface between software and graphics acceleration hardware.
- Angle
Almost Native Graphics Layer Engine. The goal of ANGLE is to allow users of multiple operating systems to seamlessly run OpenGL ES content by translating OpenGL ES API calls to one of the hardware-supported APIs available for that platform.
- LUA
LUA is a powerful, efficient, lightweight, embeddable scripting language. It supports procedural programming, object-oriented programming, functional programming, data-driven programming, and data description. Although the main feature of this engine is to have LUA script as main way to develop, is not mandatory. You can, if you want, develop in pure C++.
- LodePNG
LodePNG is a PNG image decoder and encoder, all in one, no dependency or linkage to zlib or libpng required. It’s made for C (ISO C90), and has a C++ wrapper with a more convenient interface on top.
- Box2D
Box2D is an open source C++ engine for simulating rigid bodies in 2D. it is available as plugin. The flag to use it in Android is
USE_BOX2D
.- Liquidfun
Liquidfun is a 2D rigid-body and fluid simulation
C++
library for games based upon Box2D . This version forces to drawback Box2D to 2.3.0. The Liquidfun is under the feature/liquid_fun branch.- Bullet 3D
Bullet 3D is an open source C++ engine for simulating rigid bodies in 3D. It is available as external plugin/module however it is not ready yet :/.
- LuaSQLite 3
Available as plugin, LuaSQLite 3 is a thin wrapper around the public domain SQLite3 database engine. The flag to use it in Android is
USE_LSQLITE3
.- SQLite 3
SQLite is a C-language library that implements a small, fast, self-contained, high-reliability, full-featured, SQL database engine. It is part of the lsqlite3.
- AES Crypt
AES Crypt is a file encryption API that uses standard Advanced Encryption Standard (AES) to easily and securely encrypt files. Although is not mandatory, it is implicit added to the engine.
- Audiere
Audiere is a audio API. It can play Ogg Vorbis, MP3, FLAC, uncompressed WAV, AIFF, MOD, S3M, XM, and IT files. It is required only on Windows for now.
- PortAudio
PortAudio is a free, cross-platform, open-source, audio I/O library. For now
PortAudio
only handle wav sound format.- PlusWindows
PlusWindows is a simple library for creating Owner-Drawn components on Windows . It is required only on Windows.
- STB True Type
Do parse, decode, and rasterize characters from true type fonts.
- MiniZ
Miniz is a lossless, high performance data compression library that implements the zlib (RFC 1950) and Deflate (RFC 1951) compressed data format specification standards.
- ImGui
An immediate graphical user interface for C ++ with minimal dependencies. It is mainly used for editor. it is available as plugin. The flag to use it in Android is
USE_IMGUI
.- Audio
Unfortunately, this is still time consuming and not every platform is easy to handle with a common built-in music library. The main focus of the engine is graphics, so, for now, we will keep those libraries.
PortAudio
is a potential cross-platform API to be used however the codecs might demand some time to incorporate, so, for now, it is available overLinux
only.
1.5. Games made with mbm¶
Here some games made using the engine:
1.6. Quick start guide¶
Here a quickly description how to build the engine selecting the environment.
For now, the engine is available for Windows Linux and Android.
More platforms are coming soon!
1.6.1. Getting the source code¶
Here the needed steps:
- Get git
Install git and clone the project:
git clone https://bitbucket.org/michel-morais/mini-mbm.git
- Download instead
You also can download the project:
1.6.2. Build for Windows¶
- Install
Visual Studio 2019 or above.
You might need C++ tools for Visual Studio to be able to compile.
- Find the solution
Go to the folder mini-mbm/platform-msvs/
- Open
mini-mbm.sln solution:
- Build
Find the button
Build Solution
on Visual Studio and build it:
In the end, you should have all project inside the solution built.
Now, let’s create an example…
- Main lua
let’s create a text file called main.lua in the Windows’Desktop
Rename it for
main.lua
Copy and paste this code:
mbm.setColor(1,1,1) --white background
tTexture = texture:new('2dw') --texture mesh
tTexture:load('HB_smile.png') -- load our texture
Next let’s use the following image:
Download the HB_smile.png to Desktop folder:
Set the debug properties on Visual Studio to your just created scene main.lua :
--scene "C:\Users\home\Desktop\main.lua" -w 800 -h 600
Note
Of course your path would be different then this.
Finally, when you run you should be able to see the first scene being loaded:
1.6.3. Binary for Windows¶
You can get the binaries for Windows here:
download mini-mbm-windows-3.3.b.zip
.
What’s in this folder?
1.6.4. Build for Linux¶
- Tools
As
root
install cmake clang g++ gcc build-essential libgles2-mesa-dev libreadline-dev portaudio19-dev.
apt-get cmake
apt-get clang
apt-get g++
apt-get gcc
apt-get install build-essential
apt-get install libgles2-mesa-dev
apt-get install libreadline-dev
apt-get install portaudio19-dev
- Or
As
sudo
install cmake clang g++ gcc build-essential libgles2-mesa-dev libreadline-dev portaudio19-dev.
sudo apt-get cmake
sudo apt-get clang
sudo apt-get g++
sudo apt-get gcc
sudo apt-get install build-essential
sudo apt-get install libgles2-mesa-dev
sudo apt-get install libreadline-dev
sudo apt-get install portaudio19-dev
- Create a folder
Go to the project folder and create a folder
build
.
mkdir build
cd build/
- Cmake
To build your project you must to select a platform and which feature are you going to include:
In this case the platform is Linux and we want to include everything (modules and third party libs):
cmake .. -DPLAT=Linux -DUSE_ALL=1 -DAUDIO=portaudio -DCMAKE_BUILD_TYPE=Release
- Make
Now you just need to compile typing
make
.
make
# or
make -j8 # 8 threads to be faster
In the end, it will show you where the folder is, what is the size and what was built:
1.6.5. Audiere for Linux¶
Note
Audiere for linux is only available under audiere_linux branch. The default sound API for Linux is PortAudio.
- Compile Audiere
From project folder, install osspd, go to
third-party/audiere-1.9.4
, configure and compile.
sudo apt-get install osspd
cd third-party/audiere-1.9.4
chmod 777 configure
autoreconf -f -i
./configure
make
- Alternative Audiere
As described here (https://github.com/poikilos/Audiere/releases), you can install it from this fork:
cd /tmp
wget https://github.com/expertmm/Audiere/releases/download/1.10.1/audiere-1.10.1.tar.gz
tar -xzf audiere-1.10.1.tar.gz
cd audiere-1.10.1
autoreconf -f -i
./configure
make
sudo make install
Later you must follow the process of :Build for Linux but skip portaudio19-dev
installation. Include the option -DAUDIO=audiere
from cmake command line.
1.6.6. Build for Android¶
For Android we are using Linux environment.
- Tools
As
root
install cmake clang g++ gcc build-essential.
apt-get cmake
apt-get clang
apt-get g++
apt-get gcc
apt-get install build-essential
- Or
As
sudo
install cmake clang g++ gcc build-essential.
sudo apt-get cmake
sudo apt-get clang
sudo apt-get g++
sudo apt-get gcc
sudo apt-get install build-essential
- NDK
For Android is necessary
NDK
.The engine is using the Android ndk r26c version.
Download, extract and export the variable
NDK_ROOT
to that folder:- MINSDKVERSION
For Android is to define the minumum version
SDK
.The engine is using the Android 8.0 (API level 24) (Nougat).
You can re-define the
SDK
with-DANDROID_NATIVE_API_LEVEL=24
export NDK_ROOT=your-path/android-ndk-r26c
Tip
You can add export NDK_ROOT=your-path/android-ndk-r26c
in your .bashrc
if you want.
Note
You should not have problem using a major version then r26c
. If you have, please let me know.
- Create a folder to build
Go to the project folder and create a folder
build
mkdir build
cd build/
- Cmake
To build your project you must to select a platform and which feature are you going to include:
In this case the platform is Android and we want to include only
LUA
(modules and third party libs): You also need to specify the architecture. Cmake will set to default if not specified.
Important
Since Android 7.0, the system prevents apps from dynamically linking against non-NDK libraries.
https://developer.android.com/about/versions/nougat/android-7.0-changes.html#ndk
For this reason, you have to specify which libraries are you going to use together (box2d, ImGui, lsqlite3 etc ).
We do this through the command USE
when invoking Cmake: -USE_LSQLITE3=1
, -DUSE_IMGUI=1
, -DUSE_BOX2D=1
, -DAUDIO=jni
, etc…
Note that we are in Android using native audio with the flag -DAUDIO=jni
.
cmake .. -DPLAT=Android -DANDROID_ABI=arm64-v8a -DANDROID_NATIVE_API_LEVEL=24 -DUSE_LUA=1 -DAUDIO=jni -DCMAKE_BUILD_TYPE=Release
- Make
Now you just need to compile typing
make
:
make
# or
make -j8 # 8 threads to be faster
In the end, it will show you where the folder is, what is the size and what was built:
Note
For Android there are more steps to do…
- Install Android Studio
You need to install Android Studio.
Go to https://developer.android.com/studio download and install Android Studio. Version used: Iguana.
Note
You might need to install the latest SDK. At this point the minimum version is Android 13 (Tiramisu). See https://apilevels.com/ for more information
- Create a project
Now open Android Studio and create a new project:
- Select
Add No Activity option:
- Give a name for your project
Let’s call it My First Game.
- Set the language to Java
The project has some dependencies on JNI and you must use Java as interface.
Note
Important to leave the minimum SDK
for as many devices as possible, but use the target SDK
as recommended by Google play here https://apilevels.com/.
- Folder com/mini/mbm
You must to copy the interfaces to the right folder:
Go to
mini-mbm/platform-android
folder and copy the foldercom/mini/mbm
and its sub-folder toyour-project-android/app/src/main/java/com/mini/mbm
.
cp -r com ~/AndroidStudioProjects/MyFirstGame/app/src/main/java/com
The folder on Android Studio should be like this:
- Then
After Android Studio update the indices, you will be able to add a new class:
Add a class which will extend of the main class of the engine. Let’s call it Main.
- Main
Create a class Main.java which extend from com.mini.mbm.MainJniEngine:
- Implement
Use Android Studio option to implement abstract methods:
Your Main class should be like this:
package com.example.myfirstgame;
import android.content.Intent;
import android.graphics.Point;
import android.os.Bundle;
import com.mini.mbm.MainJniEngine;
public final class Main extends MainJniEngine {
@Override
public String getMyVersionAPP() {
return null;
}
@Override
public int getMaxSimultaneousStreams() {
return 0;
}
@Override
public Point getExpectedSizeOfWindow() {
return null;
}
@Override
public String OnDoCommands(String key, String param) {
return null;
}
@Override
public void OnCreate(Bundle icicle) {
}
@Override
public void OnResume() {
}
@Override
public void OnStart() {
}
@Override
public void OnPause() {
}
@Override
public void OnStop() {
}
@Override
public void OnDestroy() {
}
@Override
public void OnActivityResult(int requestCode, int resultCode, Intent data) {
}
@Override
public void OnPostCreate(Bundle savedInstanceState) {
}
}
- Libs
Now you need to copy the needed libraries to the right folder.
Note
The minimun ANDROID_API is defined as ANDROID_NATIVE_API_LEVEL = 24 in the CMakeLists.txt. This mean Android 8.0 (API level 24) (Nougat)
Here a table showing the right folders depend on ABI:
ABI |
Folder |
Comment |
---|---|---|
|
|
(principal 64) ARMv8 AArch64 instruction set - since NDK r10 (mandatory) |
|
|
(principal) ARMv7 based devices with hardware FPU instructions (VFPv3_D16) |
|
|
Same as armeabi-v7a, but sets NEON as floating-point unit |
|
|
same as armeabi-v7a, but sets VFPv3_D32 as floating-point unit |
|
|
IA-32 instruction set |
|
|
MIPS32 instruction set |
|
|
MIPS64 instruction set (r6) - since NDK r10 |
|
|
Intel64 instruction set (r1) - since NDK r10 |
Note
The ABI option can be set when you invoke cmake setting the argument ANDROID_ABI
Examples:
cmake .. -DPLAT=Android -DANDROID_ABI=arm64-v8a -DUSE_LUA=1 -DCMAKE_BUILD_TYPE=Release
cmake .. -DPLAT=Android -DANDROID_ABI=armeabi-v7a -DUSE_LUA=1 -DCMAKE_BUILD_TYPE=Release
cmake .. -DPLAT=Android -DANDROID_ABI=x86 -DUSE_LUA=1 -DCMAKE_BUILD_TYPE=Release
Important
Whenever you change the ABI, clean the whole folder.
On build folder do:
make clean
rm -rf *
Then do the cmake
command selecting the ABI again.
Now, let’s create the jniLibs
folder:
mkdir ~/AndroidStudioProjects/MyFirstGame/app/src/main/jniLibs
Then for this example, we will copy the folder arm64-v8a within its libs inside to the jniLibs
folder. We remove the libraries that we do not use.
cp -r bin/release/arm64-v8a/ ~/AndroidStudioProjects/MyFirstGame/app/src/main/jniLibs
Android Studio will look like this:
- Android Manifest
Now you need to update the
AndroidManifest.xml
:Here the default
AndroidManifest.xml
:
<?xml version="1.0" encoding="utf-8"?>
<!-- example AndroidManifest.xml!-->
<!-- your package (your_package) android must be replaced!-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mini.mbm.your_package"
android:configChanges="orientation|keyboardHidden|screenSize"
android:glEsVersion="0x00020000"
android:installLocation="preferExternal"
xmlns:tools="http://schemas.android.com/tools">
<!-- permission if you need uncomment -->
<!-- <uses-permission android:name="android.permission.GET_ACCOUNTS" /> -->
<!-- needed permission for mini-mbm-->
<!-- https://developers.google.com/android/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.Info#public-methods -->
<!-- Action Items If you use an advertising ID, you must declare the AD_ID Permission when your app targets Android 13 or above. Apps that don’t declare the permission will get a string of zeros.-->
<!--Case 1: The app doesn't contain any Ads:-->
<uses-permission android:name="com.google.android.gms.permission.AD_ID" tools:node="remove"/>
<!-- Case 2: The app contains Ads:-->
<!--<uses-permission android:name="com.google.android.gms.permission.AD_ID"/>-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_OWNER_DATA" />
<uses-permission android:name="android.permission.READ_OWNER_DATA" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE" />
<!-- We do need opengl-es 2.0 support-->
<uses-feature android:glEsVersion="0x00020000" />
<!-- Important LargeHeap and hardwareAccelerated!-->
<application
android:hardwareAccelerated="true"
android:largeHeap="true"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.your_package"
tools:targetApi="34"> <!-- Change the target API here if needed -->
<!-- Mode singleTask and horizontal adjust (you can change it) -->
<activity
android:name="com.mini.mbm.your_package.Main"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="@string/app_name"
android:launchMode="singleTask"
android:orientation="horizontal"
android:screenOrientation="landscape"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.lib_name"
android:value="your_package" />
</activity>
</application>
</manifest>
- Update Android Manifest
You need to update according to project:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mini.mbm.your_package"
>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myfirstgame"
>
<activity
android:name="com.mini.mbm.your_package.YourMainClassExtendedFrom_MainJniEngine"
>
<activity
android:name="com.example.myfirstgame.Main"
>
- Assets
For your scripts, textures, binary files, etc, you must to add them in the folder assets.
Let’s create the
assets
folder in the right place:
mkdir ~/AndroidStudioProjects/MyFirstGame/app/src/main/assets
Let’s create a sub-folder to organize some textures:
mkdir ~/AndroidStudioProjects/MyFirstGame/app/src/main/assets/textures
- Main lua
Next let’s create a file called main.lua inside the assets folder.
mbm.addPath('textures') --sub folder to search images
tTexture = texture:new('2dw') --texture mesh
tTexture:load('HB_smile.png') -- load our texture
Let’s copy the image HB_smile.png to assets/textures folder:
The final structure should be like this:
Tip
Every time that you update the folder assets you MUST update the internal version:
This is the way the engine organize to update from asset folders.
Tip
Always use LUA files encoded to UTF8.
Here a script to help you using iconv
:
find . -type f -iname *.lua -exec sh -c 'iconv -f $(file -bi "$1" |sed -e "s/.*[ ]charset=//") -t utf-8 -o converted "$1" && mv converted "$1"' -- {} \;
This avoid some error on interpret LUA
files.
- Run
At this point, you should be able to run the project.
The Log cat in the Android Studio shall logs some useful information.
1.6.7. Binary for Android¶
Even though you have some doubt? Here the project using Android Studio version 3.5.3 :
Or just would like to take a look on the apk generated?
download example apk for Android
Or the latest libraries to get start at Android?
binary libs for Android version 3.2.a
It contains the core of engine and LUA script support to start to develop on Android:
Note
flags
.Important
Since Android 7.0, the system prevents apps from dynamically linking against non-NDK libraries.
https://developer.android.com/about/versions/nougat/android-7.0-changes.html#ndk
For this reason, you have to specify which libraries are you going to use together (box2d, ImGui, sqlite, etc ).
We do this through the flag USE
when invoking Cmake: -USE_LSQLITE3=1
, -DUSE_IMGUI=1
, -DUSE_BOX2D=1
etc…
On Android it is possible to list the files in the cache folder through command line using adb from folder ~/Android/Sdk/platform-tools
:
./adb exec-out run-as com.mini.mbm.yourcompany ls -R /data/data/com.mini.mbm.yourcompany
More information at https://developer.android.com/studio/command-line/adb
Warning
known issue.
The current implementation does not load sound stream from cache folder in Android. This is a TODO.
You can leave the sound stream in asset folder (NOT inside of your database) then it will works.
1.6.8. Command line usage¶
Command line options:
mini-mbm
Version:3.1.b
Usage: mini-mbm [options]... [file_name.lua] or [--scene file_name.lua]...
--help display this help
-w, --width set window's width
-h, --height set window's height
-ew,--expectedwidth set expected window's width
-eh,--expectedheight set expected window's height
--stretch stretch to axis ('x', 'y', or 'xy') default is 'y'
--nosplash do not display logo
-x, --posx set x window's position
-y, --posy set y window's position
-s, --scene set scene to load (e.g.: main.lua)
-n, --name set window's name
-a, --addpath add path to search file at run time
--noborder new window without border
note: to add a global variable use '='. example:
'myVarNumber=5.0' 'stringVar=someString'
the variable will be stored as number when is number.
otherwise the variable will be stored as string.
use getGlobal function to get variable at lua script (see doc for more information)
use space to separate arguments:
usage example:
mini-mbm --scene main.lua -w 800 -h 600
mini-mbm -s main.lua -w 800 -h 600 'myVarNumber=5.0' 'stringVar=someString' --nosplash