If you cast your mind back to the "Hello World" project in the very first chapter of this book, you will recall that we used the ICF file to display a different welcome message depending on which platform the code was being executed on. Don't worry if you've forgotten how all this works, as we'll be covering it again shortly.
This functionality proves extremely useful when we are trying to target as many different devices as possible, as there are built-in parameters that allow us to apply different settings for a range of things including memory usage, OpenGL ES graphics performance, splash screens, and much more.
ICF file settings are assigned to a section identifier which is defined by placing the name of the section in square brackets. When specifying a value for an ICF setting you must ensure that it appears after the correct section identifier, otherwise it will not be found at runtime and an assert will be raised. Here's an example:
[S3E] MemSize=10000000 SysAppVersion="1.0.0"
There are far too many ICF settings to be able to cover all of them in this book, so instead we'll be taking a look at some of the more immediately useful ones. If you want to see a complete list, take a look in the Marmalade documentation, by going to Marmalade | Marmalade Development Tools Reference | ICF File Settings.
The following table shows a few of the settings that control Marmalade at its lowest level. The section identifier for these settings is [S3E]
:
Setting |
Value type |
Description |
---|---|---|
Integer |
The size, in bytes, of the main memory heap available to an application. A Marmalade application can actually have up to ten memory heaps available, so there are also settings called | |
Integer |
The size, in bytes, of the debug memory heap when a Windows debug build is executed. This is a special block of memory that is used for tasks such as processing 3D models and converting textures to different formats during the resource building process. | |
String |
Allows an application to access its version number. While this value can be set in the ICF file, it can also be set using the MKB deployment's | |
Integer |
Identifies whether the application should attempt to initialize an OpenGL ES 1.x or 2.x interface. Only the major version number (that is, 1 or 2) can be specified. | |
Integer |
The size of the stack available to the program, in bytes. It is useful, for example, when an application requires extra stack space (due to heavily recursive algorithms). | |
String |
The name of an image file that will be displayed while an application is loading. The filename is relative to the | |
Byte |
A value from | |
Integer |
The width and height that the splash screen image should be drawn at. If smaller than the screen size, the image will be centered. | |
|
When set to | |
String |
Allows the screen to be locked to a particular orientation, rather than rotating when the user rotates the device. Can be set to one of the following values: |
The following table lists some useful parameters for altering the initialization of OpenGL ES. These settings must occur after the section identifier [GL]
:
Setting |
Value type |
Description |
---|---|---|
|
When set to | |
Integer |
Indicates the number of bits to be used to store each of the red, green, blue, and alpha channels in the frame buffer. For best render quality, all of these settings would normally be given the value | |
Integer |
The number of bits to use for the depth buffer. Valid values are |
We'll finish off with some settings related to resource management that we'll be looking at in more depth later in this chapter. They have been included here for easy reference. The settings reside in the ICF section [RESMANAGER]
:
Setting |
Value type |
Description |
---|---|---|
|
When set to | |
String |
Specifies the resource building style to use when the Windows debug build is processing the original source assets. As we will learn later in this chapter, this parameter allows us to provide different sets of resources to cater for devices of varying abilities. |
One of the best things about ICF files is that we are able to make use of them ourselves by creating our own custom settings. To define new settings we just need to add them to the file app.config.txt
, which is automatically generated for us when creating a new project using an MKB file.
When defining new settings, we can also provide a string of text that explains what this setting is for. While this description isn't actually used or needed by the Marmalade SDK, it's a good way of documenting what a setting is supposed to do!
It is, however, important to add definitions for all our settings to the app.config.txt
file because it will prevent the application generating lots of asserts when it is executed. In a Windows Debug build, Marmalade checks to see if an ICF setting has been declared both when loading the ICF file at the start of execution and also whenever we try to access a setting from within our own code.
We can also define our own section identifiers in the app.config.txt
file simply by listing the name of the section in square brackets and following it with the new setting definitions. Here's an example illustrating how to create new section identifiers and settings:
[GAME_DEBUG] SkipToLevel Skip to a level at game start [GAME] FrameRate The frame rate we want the game to run at MaximumHealth Amount of energy the player has at game start
Defining our own section identifiers can be extremely useful when creating library modules, such as the GUI and Localise
modules created in Chapter 6, Implementing Fonts, User Interfaces, and Localization. The only difference when creating a module is that the app.config.txt
file changes to modulename.config.txt
and it should reside in a subdirectory called docs
in the module's main directory. As an example, if we were to add our own settings to the GUI module we would create a directory called GUIdocs
, and the file that lists the settings would be called GUI.config.txt
.
It's very little
use to be able to provide settings in the ICF files without some way of accessing them. This is where the s3eConfig API comes into play and we can use it by just including the s3eConfig.h
header file.
The first function we will look at is s3eConfigGetString
, which takes the section identifier and setting name we want to access and also a pointer to an array of char
that will be used to return the value of the setting when the function completes. Since the app.icf
file is really little more than an ASCII text file, all this function does is return the string of text following the equals sign for the specified ICF setting.
The char
array supplied to s3eConfigGetString
should be at least of length S3E_CONFIG_STRING_MAX
, as this is the largest string size the function can return. If the requested setting can't be found in the ICF file this buffer will not be changed, which is very useful as it allows us to set up a default value for the parameter in our code.
// Set default first level char lLevelName[S3E_CONFIG_STRING_MAX]; strcpy(lLevelName, "level1"); s3eConfigGetString("GAME_DEBUG", "SkipToLevel", &lLevelName); // lLevelName will still contain "level1" if the SkipToLevel setting // could not be found in the ICF file
Quite often we will want to specify ICF settings, which just need a numeric value. To make this easier for us, Marmalade provides another function called s3eConfigGetInt
, which, instead of a pointer to a char
array, takes a pointer to an int
variable.
This function will read the setting string from the ICF file and then attempt to convert it into an integer value. If this fails (for example, the string contains non-numeric characters or is out of the range of an int
) or the setting does not exist in the ICF file, the variable's current value will not be changed, thus allowing default values to be specified in code.
Both functions
will return S3E_RESULT_SUCCESS
if the setting value could be retrieved, or S3E_RESULT_ERROR
if there was a problem. The function s3eConfigGetError
will let us discover what the problem was by returning one of the following values:
Value |
Description |
---|---|
No error occurred. | |
One of the parameters to | |
The requested ICF setting could not be found. | |
There was a problem converting the ICF setting value to an integer when using |
When targeting a large number of different devices, it is not uncommon to have a situation where we want to be able to do different things depending on the device the application is running on.
The ICF filesystem makes handling this incredibly easy by allowing us to provide different values for parameters based on both the operating system of the device and even by individual device type.
To begin with, we can provide different settings on a platform-wide basis. The "Hello World" project from Chapter 1, Getting Started with Marmalade, has already demonstrated this, but to recap, we limit the settings to a particular operating system using the OS
conditional. This is best illustrated by an example:
[GAME] FrameRate=20 {OS=BADA} FrameRate=15 {OS=IPHONE} FrameRate=30 {}
This example sets a default value for the FrameRate
setting of 20
. It then overrides this value for Bada devices with a value of 15
and for iOS devices with a value of 30
. Note that for legacy
reasons the value IPHONE
refers to all iOS devices (all versions of iPad and iPod touch as well as all iPhones).
It is also possible to make settings that will only apply to a particular subset of devices on a particular platform. This is done using the ID
conditional that first specifies the platform type and then has a comma-separated list of device identifiers that the setting should apply to. Here's another example:
[GAME] FrameRate=30 {ID=ANDROID "HTC Hero", "T-Mobile G1"} FrameRate=20 {}
Here we set a default value for the FrameRate
setting of 30
, then limit the value to just 20
if the game is running on either of the listed Android devices. Quote marks are only required on device names that contain spaces.
Wondering how to discover the device name? Often it is the name of the device, but this is not always the case. The easiest way to discover the device name for a particular device is to create a short test program that makes a call to s3eDeviceGetString
, as follows:
const char* lpDeviceID = s3eDeviceGetString(S3E_DEVICE_ID);
The s3eDeviceGetString
function and its sibling s3eDeviceGetInt
allow us to determine an awful lot of information about the device we're running on, including the operating system, processor type, phone number, current language settings, and much more. Take a look at the s3eDevice.h
header file or the Marmalade documentation for more details.
18.188.154.252