Code Walkthrough

From Performous

Jump to: navigation, search

Where to find the files you are looking for

 docs/              documentation and man pages
 game/              the source code of the game
 data/              sounds and other such binaries + configuration files
 themes/            all graphics, menu music, etc
 tools/             various tools and scripts for both end-users and developers
 lang/              translations
 cmake/             CMake modules
 osx-utils/         OSX packaging tools
 win32/             Windows specific stuff and packaging utilities
 portage-overlay/   ebuilds for Gentoo
 editor/            defunct song editor

When adding new data files, you may need to edit the CMakeLists.txt file in that folder to have CMake actually install it. When adding new source code files, you don't need to edit CMakeLists.txt, but you need to remove CMakeCache.txt and run cmake again for it to rescan for files.

The game folder in detail

main.cc contains not only the main function (including commandline argument handling etc) but also the main loop of the game. The main function also owns the base objects (that some might consider global) of the game.

screen*.cc/hh contain implementation of screens. A screen should ideally by only a "view" with as little game logic or other things in it as possible. Keyboard input, being tightly coupled with UIs, is also handled there. ScreenManager's activateScreen("foo") function is used for moving from one screen to another.

You may currently access ScreenManager by a singleton, but this is discouraged and the singleton is to be removed because singletons are evil (but it is not buggy at the moment, so we are not rushing that).

Notes of the song and music file parsing are in song.cc/hh and parsers in songparser*.cc/hh.

Most other files either implement little helpers for loading and displaying images (surface), playing sound (audio), decoding video/audio (ffmpeg), rendering and displaying text (opengl_text), etc.

The program configuration is stored in a global variable named config, declared in configuration.hh. The code there is agnostic about the specific config options, so you probably don't need to touch it even if you add new options.

Adding new options is very easy. In C++ you simply use something like config["some/identfier"].get_b() to read the value and that's it. There are different getters for different types of config variables (get_b is for bool). You need to add your new option to data/performous.xml so that it appears in the config menu and has a suitable default value.

One rather widely used tool is animvalue, which implements variables that change their value smoothly over time. This effect is most prominent it the song browser, but it is used in various other parts of the UI and we also abuse it as a simple timer in some places.

The database is the access point to static information. There you can add players, songitems and - the reason why it was introduced - hiscores. It is also a facade for Players (players.cc/hh), hiscore (hiscore.cc/hh) and songitems (songitems.cc/hh). Don't confuse songs with songitems. In fact they both hold a shared_ptr to the same song (song.cc/hh), but only the songitems have a unique id which is used in the highscore. On the other hand the songs (songs.cc/hh) are used for the song browser. There is also the code for iterating above all files and call the song-parser.

The game logic runs as a separate thread so that slow OpenGL rendering or other such factors don't disturb it (engine.cc/hh). This engine runs in an endless loop, polling the audio analyzer code (pitch.cc/hh) for data that it then uses to calculate points and to record pitch history. Capture objects (owned by the main function) own a set of Analyzers each (one per microphone) and also a libda record object (corresponding to a sound card) that uses a callback to deliver the Capture object with new PCM data and then the Capture distributes that to Analyzers' input buffers (no processing is done here because it would block audio libraries for too long time).

Threading

The game heavily uses threads, primarily to simplify implementation of things that need to stay responsive even though some other parts of the program might block, but also to improve performance. You can largely ignore this fact, as the threads are hidden inside classes so that things don't break even when you don't realize that there is a thread. Just be aware of that there are plenty of them everywhere. Ask Tronic before touching any thread code directly.

Personal tools