I believe there are free and equally good alternatives for most game production tools for game development companies. At Angels' Ware there are no money spent on software except for OS X which is a must to build for iOS. And that is unfortunate because it ruins my 100% free software goal.
Operating System. Ubuntu 64-bit 16.04.
IDE. I think the Qt Creator IDE is the best one available for C++ development at the moment. Its integrated CMake support makes it a very handy tool to work with since the projects depends on it.
Source Control. All repositories uses Git.
2D Art. There are several tools used here. Mainly OpenSCAD for vector graphics with some support from Inkscape. For raster graphics I use Krita and Pinta.
3D Art. Blender.
Sound and Music. Because the first game is still in production in parallel with the game engine there are no sound and music produced yet. Audacity will probably take a big part to handle all sounds and music recorded with my Zoom H6 recorder.
Monday, June 13, 2016
Tuesday, April 5, 2016
Folder Structure and Project Generation Using CMake
To start a new project is always a nice feeling. You get that chance to correct all those things that drove you nuts in your previous project, and for a short period believe that this time everything will be perfect. But as we all know, in reality this project will at some point become as messy as the previous one, which got as messy as the one before that one and so on. You just need to accept it and minimise the messiness as much as possible.
The folder structure is one of the first thing you need to think through when setting up a new project. At Angels' Ware the goal has been to make a simple but yet powerful and extendable structure that is intuitive and easy to navigate.
At one of my previous places of work we had a fairly good setup (which I've been inspired by when setting up the one at Angels' Ware). The problem there was that it was too complex to grasp and got very time consuming as soon as you had to add a new dependency or add a necessary define or so. It was just not intuitive enough.
One of the good things with that system was that it utilised CMake to generate project files for all platform. This is something I've chosen to also do at Angels' Ware.
The root folder (referred to as ./) consists of a few folders together with some files and looks like this.
./
apps/
doc/
cmake/
packages/
scripts/
contributors.txt
README.md
apps/ - This is where the code for the applications is. The folder contains folders named on the form com.angelsware.PROJECT_NAME. As an example, the sample project's folder structure looks like this.
./apps/com.angelsware.sample/
assets/
platform-resources/
| - android/
| - | - AndroidManifest.xml
| - | - build.gradle
| - | - ...
| - ios/
| - | - Info.plist
| - | - ...
src/
| - android/
| - | - main.cpp
| - | - ...
| - common/
| - | - sample.cpp
| – | - sample.h
| - default/
| - | - main.cpp
| - ios/
CMakeLists.txt
The platform-resources/ folder contains platform specific files that aren't code. Info.plist for iOS and AndroidManifest.xml for Android are good examples.
src/ - Folder for game specific code.
doc/ - Contains documentation. In this case a single DocBook xml file.
cmake/ - Contains CMake toolchain files for supported platforms.
packages/ - This folder contains the engine code. It consists of more than fifty different packages (libraries) at the moment which serves as optional dependencies for the applications. By having the engine split up you can easily depend on just those parts you need. Compiling the network stack for an offline game just doesn't make sense.
Every package has the same structure, so I've picked one to show as an example. The time package makes a good one as it uses all features.
./packages/
time/
| - include/
| - | - time/
| - | - | *.h
| - src/
| - | - common/
| - | - | *.h;*.cpp
| - | - default/
| - | - | *_default.h;*_default.cpp
| - | - win32/
| - | - | *_win32.h;*_win32.cpp
| - CMakeLists.txt
The include/ folder is where all public headers are and results in an include line like this #include <time/aw_second.h>.
The src/ folder contains the source files as well as the private headers. These are split up in three types of folders.
The cross-platform code is put in the common/ directory. So no matter what platform you build on this code will be linked.
Platform specific code has their own folder. So when building for Windows the code from the win32/ folder will be used. Every platform has its own predefined folder. Currently those are win32, linux, emscripten, ios and android.
In this example there is also a folder called default/. This one works as a fallback folder meaning that if there are no platform specific folder for the targeted platform the code from this folder will be linked if it exists. So in this example all platforms except Windows will link with code from the common/ and default/ directories and Windows will link from common/ and win32/.
scripts/ - Build scripts, model exporters and other tools can be found here.
./scripts/
app-resources/
blender/
binary-to-header.py
create-app.py
create-package.py
...
The app-resources/ folder contains template files used when setting up a new application.
The blender/ folder contains model export script for Blender.
The last folder that isn't represented in the example above is the libs/ folder for pre-built libraries. If you need to link with a jar file on Android for example you put the file in ./packages/MY_PACKAGE/libs/android/ and it will be linked. The same principle applies for static (*.a;*.lib) and dynamic libraries (*.so;*.dll).
My favorite IDE is QtCreator which can as CLion open CMake files directly, so this doesn't really apply for that those two. But for other IDEs the process of generating a project looks like this.
$ cmake ./apps/com.angelsware.sample -Dtarget=android
An alternative to this line is to run one of the build scripts available in the scripts/ folder.
And now to the CMakeLists.txt files. There are those for the apps and those for the packages. A very simple terminal Hello World application would have a CMakeLists.txt file that looks like this.
cmake_minimum_required (VERSION 2.8)
project (com.angelsware.helloworld)
include ("../../prerequisites.cmake")
build_app()
If you want to make your application depend on say a math library and time library you change the call from build_app() to:
build_app(
"math"
"time"
)
The names of the added dependencies corresponds to the names of the folders in the package/ folder. So in this case CMake understands that you want to link with the ./packages/math and ./packages/time packages.
If you're building for iOS you will need to link with additional frameworks. Simply add this line:
Let's have a look at the packages CMakeLists.txt files. I will use the one from the platform package as an example. It looks like this:
The folder structure is one of the first thing you need to think through when setting up a new project. At Angels' Ware the goal has been to make a simple but yet powerful and extendable structure that is intuitive and easy to navigate.
At one of my previous places of work we had a fairly good setup (which I've been inspired by when setting up the one at Angels' Ware). The problem there was that it was too complex to grasp and got very time consuming as soon as you had to add a new dependency or add a necessary define or so. It was just not intuitive enough.
One of the good things with that system was that it utilised CMake to generate project files for all platform. This is something I've chosen to also do at Angels' Ware.
The root folder (referred to as ./) consists of a few folders together with some files and looks like this.
./
apps/
doc/
cmake/
packages/
scripts/
contributors.txt
README.md
apps/ - This is where the code for the applications is. The folder contains folders named on the form com.angelsware.PROJECT_NAME. As an example, the sample project's folder structure looks like this.
./apps/com.angelsware.sample/
assets/
platform-resources/
| - android/
| - | - AndroidManifest.xml
| - | - build.gradle
| - | - ...
| - ios/
| - | - Info.plist
| - | - ...
src/
| - android/
| - | - main.cpp
| - | - ...
| - common/
| - | - sample.cpp
| – | - sample.h
| - default/
| - | - main.cpp
| - ios/
CMakeLists.txt
The platform-resources/ folder contains platform specific files that aren't code. Info.plist for iOS and AndroidManifest.xml for Android are good examples.
src/ - Folder for game specific code.
doc/ - Contains documentation. In this case a single DocBook xml file.
cmake/ - Contains CMake toolchain files for supported platforms.
packages/ - This folder contains the engine code. It consists of more than fifty different packages (libraries) at the moment which serves as optional dependencies for the applications. By having the engine split up you can easily depend on just those parts you need. Compiling the network stack for an offline game just doesn't make sense.
Every package has the same structure, so I've picked one to show as an example. The time package makes a good one as it uses all features.
./packages/
time/
| - include/
| - | - time/
| - | - | *.h
| - src/
| - | - common/
| - | - | *.h;*.cpp
| - | - default/
| - | - | *_default.h;*_default.cpp
| - | - win32/
| - | - | *_win32.h;*_win32.cpp
| - CMakeLists.txt
The include/ folder is where all public headers are and results in an include line like this #include <time/aw_second.h>.
The src/ folder contains the source files as well as the private headers. These are split up in three types of folders.
The cross-platform code is put in the common/ directory. So no matter what platform you build on this code will be linked.
Platform specific code has their own folder. So when building for Windows the code from the win32/ folder will be used. Every platform has its own predefined folder. Currently those are win32, linux, emscripten, ios and android.
In this example there is also a folder called default/. This one works as a fallback folder meaning that if there are no platform specific folder for the targeted platform the code from this folder will be linked if it exists. So in this example all platforms except Windows will link with code from the common/ and default/ directories and Windows will link from common/ and win32/.
scripts/ - Build scripts, model exporters and other tools can be found here.
./scripts/
app-resources/
blender/
binary-to-header.py
create-app.py
create-package.py
...
The app-resources/ folder contains template files used when setting up a new application.
The blender/ folder contains model export script for Blender.
The last folder that isn't represented in the example above is the libs/ folder for pre-built libraries. If you need to link with a jar file on Android for example you put the file in ./packages/MY_PACKAGE/libs/android/ and it will be linked. The same principle applies for static (*.a;*.lib) and dynamic libraries (*.so;*.dll).
So how is all this working?
Before we take a look inside the CMakeListst.txt files we will have a look on how all of this is used in practice.My favorite IDE is QtCreator which can as CLion open CMake files directly, so this doesn't really apply for that those two. But for other IDEs the process of generating a project looks like this.
$ cmake ./apps/com.angelsware.sample -Dtarget=android
An alternative to this line is to run one of the build scripts available in the scripts/ folder.
And now to the CMakeLists.txt files. There are those for the apps and those for the packages. A very simple terminal Hello World application would have a CMakeLists.txt file that looks like this.
cmake_minimum_required (VERSION 2.8)
project (com.angelsware.helloworld)
include ("../../prerequisites.cmake")
build_app()
If you want to make your application depend on say a math library and time library you change the call from build_app() to:
build_app(
"math"
"time"
)
The names of the added dependencies corresponds to the names of the folders in the package/ folder. So in this case CMake understands that you want to link with the ./packages/math and ./packages/time packages.
If you're building for iOS you will need to link with additional frameworks. Simply add this line:
if(TARGET_IOS)
add_framework(Foundation)
endif()
Let's have a look at the packages CMakeLists.txt files. I will use the one from the platform package as an example. It looks like this:
cmake_minimum_required (VERSION 2.8)
project (platform)
build_library (
"math"
"util"
)
if(TARGET_LINUX)
target_link_libraries("${PROJECT_NAME}" "-lX11 -lXxf86vm")
elseif(TARGET_ANDROID)
target_link_libraries("${PROJECT_NAME}" "-landroid -lGLESv2 -llog")
elseif(TARGET_WIN32)
target_link_libraries("${PROJECT_NAME}" "opengl32.lib")
elseif(TARGET_EMSCRIPTEN)
target_link_libraries("${PROJECT_NAME}" "-lm -lX11")
endif()
This package is dependent on system libraries thus calls the target_link_libraries function.
Conclusion
Spending a few days thinking through the folder structure, how to the generate the project files and writing a CMake script to support it all, really pays of in the long run and will keep you from headache and frustration.
Subscribe to:
Comments (Atom)