| PART 0 :
INTRO |
Public Release 1st May 2004 |
At the time of writing,
Custom Graphic User Interface (I will call it as a
GUI from here) is still a highly sought-after subject in the
community, especially large mod groups who wish to further add
a sense of identity to their already good work.
I
didn't receive any assistance when I first started out on
this. It was actually more like I chanced upon this
specific area of modification while attempting to do something
totally different, but let's not get to that.
(^_^)
This is my very first OFP tutorial. It was
only after much thought that I decided to do up and
release it for I believe this knowledge will be very
beneficial to the community at large. It is also an
opportunity for me to finally be able to contribute something
back to the community (lol).
Oh, you are expected to
know everything about preparing textures in OFP (including
transparencies and the tools involved to do so) as well as
config.cpp coding and your PBOs. This tutorial is
structured to only give you the fundamental understanding of
how a GUI is actually constructed. With the wide range
of other possibilities, you have to do some exploration
yourself as well.
For now, let's head on to the good
stuff right away...
|
| PART 1 : GUI
LAYOUT |
Default OFP Main Menu GUI Layout |
 This section attempts to explain how a
basic GUI layout works, using something that we all are so
familiar with - the default (boring :P) OFP main menu
screen.
Break down the interface into individual
elements and imagine them in layers that are stacked on top of
one another. So we have...
1. Black overlay
stripes (top & bottom of screen) 2. OFP logo with
a coloured tint 3. OFP version number 4. OFP
copyright statement 5. Black tinted translucent layer
that shows a camera
cut-scene underneath. 6. Menu Button :
'Player' 7. Menu Buttons : 'Campaign Game', 'Single
Mission', 'Multiplayer',
'Mission Editor', 'Options', 'Quit Game'. 8. 2
translucent white lines (one horizontal & one
vertical) 9. Mouse cursor
Every element can be
changed (fonts, size, colour, placement etc) - You can edit,
remove or even add elements. This will be covered
shortly.
|
Default OFP Main Menu GUI Layout in
Code |
If you do not already have a copy of the
decompiled config.bin, hop over to the 'OFP: Breathe' website
to download 'Binarize' [ here ] which
contains version 1.85 of the original
config.bin.
Inside the zip file, you will find a bunch
of files in the \Binarize\Bin folder (we do not actually need
the Binarize utility for this).

For this tutorial, we will look at
the file 'rscScreen.hpp'. Open it up using your
favourite text editor (WordPad works fine for me).
Scroll around a bit to locate the section as shown below (or
do a quick CTRL-F search for 'RscDisplayMain'). This is
the GUI in code form for the main menu.

Looking closer, you will find these
familiar lines. Yep, these are the individual elements
that was broken down and described earlier on (not in the
exact order/naming convention though).

Each element is simply a class (as
in config.cpp coding) that is described under "class
RscDisplayMain".
|
Code Breakdown |
You will also find that the individual
classes under "class RscDisplayMain" are defined in the
RscScreen.hpp file. I will breakdown the
Background class with a short description of important
things to note in the right column.
class Background1 :
RscText {
x = 0.0; y = 0.0; w
= 1; h = 0.125; text = ;
colorBackground[]
= {0, 0, 0,
1};
};
|
Black Overlay Stripe
(Top) Numbers used in x/y/w/h are relative
to the screen dimension (in ratio
form).
Position (x/y) 0.0/0.0 means the top left
corner of the screen. w/h represents width/height
values.
|
class Background2 : RscText {
x
= 0.0; y = 0.875; w = 1; h = 0.125; text =
;
colorBackground[] = {0, 0, 0,
1};
}; |
Black Overlay Stripe
(Bottom) colourBackground is in the format
{R,G,B,A} with a range of 0-1 each (where 0 is min &
1 the max). {0,0,0,1} means black with no
transparency.

Therefore we have a black stripe starting at
the extreme left (x=0.0) and 0.875 units down. Size is
w=1.0, h=0.125.

|
class Background3 : RscText {
x
= 0.0; y = 0.125; w = 1; h = 0.75; text =
;
colorBackground[] = {0, 0, 0,
0.5};
}; |
Black Translucent Layer
(camera cutscene underneath) There is
actually a black layer with 50% transparency set over a
camera cutscene running. The 0.5 value in {0,0,0,0.5}
represents the transparency of the layer. Half of
1 (the max value) is 0.5, hence the transparency can be
said to be set at 50%.


Remember that the x/y value
always describes the
starting point with reference from the top left
corner.

This is what you get when you put all 3
classes - Background1, Background2 and
Background3 together.

|
Applying this concept of element
placement / sizing, the remaining elements (classes) from the
respective portions of the code should be pretty straight
forward for button text, lines and boxes.
The following
elements are added on top of the Background: OFP
logo with a coloured tint FP1, FP2,
FP3
Vertical and Horizontal white
lines Line1, Line2
respectively.
Menu
Buttons Player - User profile
menu Game - Campaign mode SingleMission -
Single mission mode Multiplayer - Multiplayer
mission mode Custom - Loads mission
editor Options - Load options menu Quit -
Exit button Version - OFP version
number Copy - Copyright
statement
Misc Continue AllMissions
Additional
Notes :
|
$STR_FIELD represents an entry from
the stringtable.csv file (this file is found in
binarize's bin folder as well).
For
example, class copy : RscText
{
style = ST_MULTI + ST_CENTER
+ ST_NO_RECT; lineSpacing =
1.0; text = $STR_CREDITS23;
x = 0.03; y = 0.93; w = 0.9; h =
0.7;
colorText[] = {1, 1, 1,
0.5}; font =
FontS; sizeEx =
0.016;
};
$STR_CREDITS23 is found as an entry
in Line 2050 in the file stringtable.csv in
English language as :
" © 2001 Bohemia
Interactive Studio and The Codemasters Software Company
Limited. All rights reserved. "
You should
change the other languages of the
same entry as well to maintain consistency
across your modification. Then again, you can
simply add in a new class for your text instead of going
through the hassle of editing the
stringtable.csv.
The decision is
entirely up to you, you can either edit an existing
entry (class) or add a new one.
|
-
sizeEx affects the font size.. you can try to
play with it.
|
- There are
more things that you can do but will not
be covered in this tutorial. Go
learn some camera scripting... you can
then change the default cutscene
running underneath in the main menu. Or fonts
can be changed as well if you do not
like the default ones. I remember
seeing a font tutorial somewhere.
If someone can send me a url to put it
here, that'll will be
good.
|
- As in
config.cpp coding, you can null any sections
which you may want to omit by adding a double-slash //
in front of the line.
|
- This one is
just for fun... here are some other
entry references in stringtable.csv
(which are not related to the GUI though).
Change them away if you
like!!! L1168 STR_LOAD_INIT - "The coundown
begins..." L1169 STR_LOAD_WORLD -
"Receiving" L1170 STR_LOAD_MISSION - "Get
Ready" L1171 STR_LOAD_INTRO - "Wait a
moment" L1172 STR_LOAD_GAME - "Receiving
mission status.." L1173 STR_SAVE_GAME - "Saving mission
status..." L1174 STR_AUTOSAVE_GAME - "Updating
retry mission" L1175 STR_WAIT_NETWORK - "Waiting for
opponent..." L1176 STR_NETWORK_SEND - "Sending
data..." L1177 STR_NETWORK_RECEIVE - "Receiving
data..." L1178 STR_NETWORK_RECEIVING
-"Receiving mission file.." L1179 STR_CREATE_SERVER - "Creating
server..." L1180 STR_CREATE_CLIENT - "Creating
client..." L1181 STR_SHUTDOWN -
"Shutdown..."
| |
| PART 2 : PREPARING
GRAPHICS FOR GUI |
Quite A Pain In The Arse
|
This section covers the use of image files
as part of the GUI. For a start, I will talk about the
OFP logo found at the top of the screen in the default main
menu GUI.
The logo actually comprises of 3 separate
classes, FP1, FP2 and FP3. Each
class defines a third of the image (extracted from data.pbo)
and adds a colour tint as described by the line
colorText[]={0.23,0.3,0.08,0.75}.
class FP1 : RscPicture {
text =
"OFPlogo1.paa"; colorText[]={0.23,0.3,0.08,0.75}; x
= 0.365; y = 0.01; w = 0.09; h =
0.1;
}; |
 |
class FP2 : RscPicture {
text =
"OFPlogo2.paa"; colorText[]={0.23,0.3,0.08,0.75}; x
= 0.455; y = 0.01; w = 0.09; h =
0.1;
}; |
 |
class FP3 : RscPicture {
text =
"OFPlogo3.paa"; colorText[]={0.23,0.3,0.08,0.75}; x
= 0.545; y = 0.01; w = 0.09; h =
0.1;
}; |
 |
| Images are originally 256*256 but
are resized to 120*120 to fit this
page. |
This is how the colour values are
derived... the RGB palette has originally a range of 0-255 for
each channel. However, in the code form, 0-1 is used
instead.
Now let's read the line
again, colorText[]={0.23,0.3,0.08,0.75};
Knowing
that, one can easily convert these values to and
fro.
R channel : 0.23/1.00 * 255 =
58.65 G channel : 0.3/1.00 * 255 = 76.5 B
channel : 0.08/1.00 * 255 = 20.4
I usually round up the
numbers, so in a standard image editing application, the
converted RGB on the palette will look like this
image...

And don't
forget the 0.75 transparency (1 being opaque and 0 being
totally transparent). Therefore, conceptually we get
this:

( Tint @ 75%
Transparency + Image
= End Result )
The 3 images are then resized (w = 0.09; h =
0.1) and strategically positioned next to each other (x/y
values). You just have to work that out a bit when
working on your own GUI for accurate placement.
|
Summing Up
|
Coming along this far, I hope you have at
least a brief idea of how everything is put together.
You can add new text, lines or graphics by modifying the
existing class or add in a new class so long as it is properly
defined (don't forget to add it under the "class
RscMainDisplay" as well).
After you are done with your
coding, these are the last steps:
1. Pop the entire BIN
folder (the one you have been working
with) into a new folder (name it with your
mod's initial!!!) inside
\Codemasters\OperationFlashpoint.
This will be your mod
folder.
 (In my case, my mod folder name is
called "PWC")
2.
Pathing to external images should
be "\pboname\imagename.paa" across
your
codes.
Compile all external images into a PBO. This PBO
can be placed either in the
default \addons folder or a new
\addons folder residing in your mod folder.
3. Add a
-mod=modfoldername switch to the end of
your execution
command.
Shortcut
Example "C:\Program
Files\Codemasters\OperationFlashpoint\
FLASHPOINTBETA.EXE" -mod=pwc
This is one of the fastest
and easiest way to implement your GUI. If you wish to
compile everything back into config.bin for whatever reason,
feel free to do so if you can.
|
| PART 3 : CREATION OF THE
PWC GUI |
For Inspiration (or not?)
|

In this
last section, I will briefly go through how I did the GUI for
the Project War Chamber mod (as requested).
The
original image composite was done up with a canvas size of
1024 * 768 pixels. Anything smaller would result in
quite a crappy image quality after PAA conversion and being
blown up full-screen (at probably a higher resolution).
The image is sliced in the into 4 parts (at the red
lines).

Now we
know that the number of pixels (both horizontal and vertical
values) for OFP textures should be in one of the sizes - 2, 4,
8, 16, 32, 64, 128, 256 or 512 (power of 2). You can see
that the heights of all 4 pieces are now out of the size
range. The choice for these values is such that
each piece can be easily resized later on using a numeric
representation relative to the screen. You'll see what I
mean later on.
The 2 heights (576 and 192) are now
being considered to their respective closest in the range of
sizes, and so we have 512 and 256. Resize the pieces
(height only) using your favourite image editing
application. The example below shows the "Before &
After" for the left pieces.
 |
 |
| *Sliced pieces (Left Top &
Bottom) - Original |
|
|
 |
 |
| *Sliced pieces (Left Top &
Bottom) - Heights Resized
|
Each piece is then exported as an
uncompressed 32-bit TARGA (RGBA) file and converted to PAA
(with alpha/transparency preserved). We now have 2 x
512*512 and 2 x 512*256 PAA files.
Back to
rscScreen.hpp, the following changes are made in "class
RscDisplayMain": 1. Background1, Background 2
classes omitted. 2. FP1, FP2, FP3 classes
omitted. 3. 4 new classes added - PWC1, PWC2,
PWC3, PWC4. 4. 2 new classes added - mytext1,
mytext2. 5. Line1 class omitted. 6.
Repositioning of various existing classes.
Earlier on,
we picked the values 576 & 192 as the heights (before
resizing). This is because 576 is three-quarter (75%) of
768 and 192 is a quarter (25%) of 768. Translating this
percentage relation into classes PWC1 thru PWC4
makes it easier to insert in the correct x/y/w/h values (at
least this is how I think). It is up to you if you do
not wish to follow how I do it.
| ADDED
CLASSES |
class PWC1
:
RscPicture
[ top left piece
] {
text =
"\pwc\pwc_main1a.paa"; x = 0.00; y = 0.00; w = 0.5; h
= 0.75;
};
class PWC2 :
RscPicture
[ top right piece
] {
text =
"\pwc\pwc_main1b.paa"; x = 0.50; y = 0.00; w = 0.5; h
= 0.75;
};
class PWC3 :
RscPicture
[ bottom left piece
] {
text =
"\pwc\pwc_main2a.paa"; x = 0.00; y = 0.75; w = 0.5; h
= 0.25;
};
class PWC4 :
RscPicture
[ bottom right piece
] {
text =
"\pwc\pwc_main2b.paa"; x = 0.50; y = 0.75; w = 0.5; h
= 0.25;
};
class mytext1 :
RscText
[ bottom screen text - line 1
]
{
style = ST_MULTI +
ST_CENTER + ST_NO_RECT; lineSpacing = 1.0; text =
An Army PC Gaming & Simulation Training
Initiative;
x
= 0.048; y = 0.958; w = 0.91; h = 0.7; colorText[] =
{0.921, 0.827, 0.596, 0.5}; font =
FontS;
sizeEx = 0.020;
};
class
mytext2 :
RscText
[ bottom screen text - line 2
] {
style = ST_MULTI + ST_CENTER +
ST_NO_RECT; lineSpacing = 1.0; text = SAF - School
of Armour;
x = 0.048; y = 0.978; w = 0.91;
h = 0.7; colorText[] = {0.921, 0.827, 0.596,
0.5}; font = FontS; sizeEx =
0.016;
};
|
| MODIFIED/EXISTING CLASSES |
class
Background3 :
RscText
[ coloured tint overlay
] {
x = 0.0; y = 0.125; w =
1; h = 0.75;
text = ;
colorBackground[]
= {0.419, 0.168, 0.000, 0.3};
};
class Line2 :
RscText
[ horizontal white line
] {
style = ST_LINE; x =
0.0; y = 0.82; w = 1; h = 0; text =
; colorBackground[] = {1, 1, 1, 1}; color[] = {1,
1, 1, 1}; colorText[] = {1, 1, 1,
1};
};
class Continue :
RscActiveMenu {
idc =
IDC_MAIN_CONTINUE; x = 0.05; y = 0.155; w =
0.0; h = 0.0;
font = FontTITLE; sizeEx =
0.6 * 0.098;
text =
$STR_DISP_MAIN_CONTINUE;
};
class
Player : RscActiveMenu {
idc =
IDC_MAIN_PLAYER; x = 0.04; y = 0.145; w =
0.5; h = 0.05;
font = FontTITLE; sizeEx =
0.6 * 0.098;
text =
$STR_DISP_ERROR; colorText[] = {0.98, 0.25, 0.058,
1};
};
class Game :
RscActiveMenu {
font =
FontTITLE; sizeEx = 0.6 * 0.098; idc =
IDC_MAIN_GAME;
x = 0.78; y = 0.145; w =
0.25; h = 0.05;
text =
$STR_DISP_MAIN_GAME;
};
class
SingleMission : RscActiveMenu {
font =
FontTITLE; sizeEx = 0.6 * 0.098;
idc =
IDC_MAIN_SINGLE;
x = 0.78; y = 0.33; w =
0.52; h = 0.05;
text =
$STR_DISP_MAIN_SINGLE;
default =
1;
};
class Multiplayer :
RscActiveMenu {
font =
FontTITLE; sizeEx = 0.6 * 0.098;
idc =
IDC_MAIN_MULTIPLAYER;
x = 0.78; y = 0.39; w
= 0.52; h = 0.05;
text =
$STR_DISP_MAIN_MULTI;
};
class Custom :
RscActiveMenu {
font =
FontTITLE; sizeEx = 0.6 * 0.098; style =
ST_RIGHT;
idc = IDC_MAIN_EDITOR; x =
0.21; y = 0.85; w = 0.30; h = 0.05;
text
= MISSION EDITOR
};
class Options :
RscActiveMenu {
font =
FontTITLE; sizeEx = 0.6 * 0.098;
idc =
IDC_MAIN_OPTIONS;
style = ST_RIGHT;
x =
0.42; y = 0.85; w = 0.20; h = 0.05;
text
= OPTIONS
};
class Quit :
RscActiveMenu {
font = FontTITLE; idc =
IDC_MAIN_QUIT;
x = 0.895; y = 0.85; w =
0.20; h = 0.05;
sizeEx = 0.6 *
0.098;
text = EXIT
};
class Date
: RscText {
idc = IDC_MAIN_DATE;
x
= 0.4; y = 0.17; w = 0.2; h =
0.05;
style = ST_CENTER; font =
FontS;
sizeEx = 0.02; text =
$STR_DISP_ERROR;
colorText[] = {0.98, 0.25,
0.058, 1};
};
class Version :
RscText {
idc = IDC_MAIN_VERSION; x =
0.40; y = 0.915; w = 0.2; h =
0.05;
style = ST_CENTER; font =
FontS;
sizeEx = 0.016; text =
$STR_DISP_ERROR;
colorText[] = {1, 1, 1,
0.5};
};
class AllMissions :
RscActiveMenu {
idc =
IDC_MAIN_CUSTOM;
x = 0.4; y = 0.935; w =
0.52; h = 0.03;
font =
FontTITLEHalf; sizeEx = 0.5 * 0.05; colorText[] =
{1, 1, 1, 0.25};
text =
$STR_DISP_MAIN_DESIGN;
};
class copy :
RscText {
style = ST_MULTI + ST_CENTER +
ST_NO_RECT; lineSpacing = 1.0; text = OFP
Engine; x = 0.045; y = 0.915; w = 0.91; h =
0.7; colorText[] = {1, 1, 1, 0.5};
font =
FontS; sizeEx =
0.016;
}; | |
The End |
I finished this tutorial in a mad rush and
did not have the time to fully go through the chunk of codes
up there... most were copied-and-pasted from my many
versions. It can't be that wrong though... and you
should be able to figure things out from here. :P
(If
you spot any typos or incorrect information, please let me
know)
|
[ CREDITS / DISCLAIMER ]
2004 Written by Raymond Koh K.C. for the OFP community.
Share
and pass on this knowledge!!! However, if you intend to extract
this tutorial and host it somewhere, I would
appreciate if you have the basic courtesy of
linking back to the Project War
Chamber or at least provide a
line of credit. :)
All diagrams
are not drawn to scale.
Like everything else in
life, think how you want to apply what you have
learnt (if any at all) from this
tutorial. Nothing is guaranteed though
everything should work if you have the
necessary basics (this is a tutorial for
'Advanced' users anyway). If your OFP is
screwed along the way, get over it and just
reinstall. And please don't come whining to me about it
(or BIS even).
[ FEEDBACK PLEASE ] Tell me how you like
this tutorial, this is my first after all !!! There is
a feedback form at the bottom of the page at
Project War
Chamber.
Maybe this will motivate me to do up more tutorials
in future (lol). Thank you very
much.
~ Takano
|