zeh@Posted: Sat Aug 07, 2004 3:27 pm :
Welcome to the second of a (hopefully) long list of tutorials on GUI scripting for DOOM 3. On this second tutorial (which is in fact labeled #1), we'll finally get our hands a bit dirty by creating a new GUI script. In the end, we will also preview it in-game.

Complete GUI scripting - 1: Your first GUI script

Like I said on the previous introduction tutorial, a GUI script is much like an HTML file. You have some kind of text that defines elements that you'll have on screen, and image files that make it become alive.

Also much like HTML content, GUI scripts are defined by one main tag, filled with mini-tags that create each visual element. While in HTML this root tag would be something like <HTML>, in GUI scripting we use a windowDef.

A windowDef is the heart, the feet and the brain of every GUI script. There's much more about windowDefs that will be covered later, but for now, let's just say that we need one windowDef so we can handle all of our visual elements. So let's go and create a windowDef. Here's the magic code from out of nowhere:

Code:
windowDef Desktop {
}


This is how a windowDef works: you start with the windowDef declaration, a name you give to it, an opening bracket, and later a closing bracket. Everything between the brackets is content that belongs to this windowDef.

One thing that's important to notice is that it has been given the "Desktop" name. All GUIs have their root element called "Desktop".

We haven't, however, added any attribute to this windowDef. While it exists, it won't be shown (or do anything at all) for a number of reasons. The first thing to do is to give it a rect, which defines the boundaries of this windowDef element.

Code:
windowDef Desktop {
  rect         0, 0, 640, 480
}


To use it, you just type the attribute name, followed by the value. The rect attribute takes four values - x, y, width, and height, and thus all values are presented in the same line, separated by commas.

One thing to notice is that the 640x480 size is not really expressed in pixels. In DOOM 3 scripting, it's as if the screen is always 640x480, so this basically means that this windowDef will take 100% of the screen, no matter in which resolution the game is being ran.

With that put, we can add more windowDefs to our screen, or change other attributes for this Desktop windowDef. Although this would hardly be used in a real GUI, let's add a bit more sauce to this Desktop.

Code:
windowDef Desktop {
  rect         0, 0, 640, 480
  bordersize   3
  bordercolor  1, 1, 1, 1
  backcolor    0.5, 0.5, 0.5, 1
  visible      1

}


Okey. What we did here with the bordersize attribute is to say this windowDef will have a border displayed, and its color is defined on the bordercolor attribute. While the bordersize attribute is pretty much straightforward - it draws a border to the inside of the windowDef, with its stroke strength being the number of pixels we used in the parameter - the bordercolor needs some clarification.

This is one of the many attributes that take colors as a parameter - and color four GUI scripts mean four things: R, G, B, and alpha. Each of the RGB values represent one of three RGB values that compose a color - and in this case, 0 is black (no light) and 1 is full light. Any values between 0 and 1 are allowed, and are calculated to reach the final color. Since the first three values here are 1, it means full red, green, and blue intensity, thus white. So this "1, 1, 1" value is the same as 255, 255, 255 in RGB values or #ffffff in hexadecimal colors.

The last parameter is alpha, and it uses a similar approach as the one used on the RGB values: 0 means total transparency, and 1 means total opacity. All values between 0 and 1 are allowed, so 0.5 would be 50% of transparency. In the end, this "1, 1, 1, 1" means total white.

Of course, the same applies to the backcolor parameter that follows. This is the color used in the background, and the "0.5, 0.5, 0.5, 1" value is easy: 50% of white, with total opacity: gray.

Following all these attributes is the visible attribute, which, as a boolean value, can be set to either 1 or 0. In this case it's set to 1, meaning it is visible. This is merely a formality, but works to illustrates the range of different attributes we could have on a single windowDef.

After setting our main stage, it's time to start populating it, so we'll add a few more windowDefs. Like I said above, this Desktop windowDef is the main container for our GUI, so subsequent windowDef elements will be its child. As we did with the attributes, we just nest these new windowDefs into it. Like this,

Code:
windowDef Desktop {
  rect         0, 0, 640, 480
  bordersize   3
  bordercolor  1, 1, 1, 1
  backcolor    0.5, 0.5, 0.5, 1
  visible      1
  windowDef myMessage {
  }
}


You'll notice I gave it a new name - since we're now getting into what we want, it's advisable to create names that'll help you in the process of coding your script. These names will never be seen by the player, of course, but they'll be used on scripting.

With our new child windowDef working, it's time to set some of its attributes.

Code:
windowDef Desktop {
  rect         0, 0, 640, 480
  bordersize   3
  bordercolor  1, 1, 1, 1
  backcolor    0.5, 0.5, 0.5, 1
  visible      1
  windowDef myMessage {
    rect         10, 10, 614, 40
    bordersize   1
    bordercolor  1, 0, 0, 1
    backcolor    0, 0, 0, 0.5
    text         "HELLO WORLD"
    textscale    0.5
    font         "fonts/english"
    textalign    1
    forecolor    0,0,1,1
  }
}


Okey, a bunch of new attributes; although pretty self-explanatory, there's some things that need to be explained here.

First, notice the first rect attribute. I wanted it to be centered on screen, a little far from the corners, so I used a x/y position of 10, 10... and a width of 614, and not 620 (which would be the normal thing to do - 640 - 10 (from the left) - 10 (from the right). Why?

The thing is, nested windowDefs have their x/y position relative to its parent, so our myMessage windowDef position is relative to the Desktop position. Normally, this wouldn't be a problem, since Desktop is at 10,10, but the DOOM 3 GUI system takes borders into account. Since Desktop has a bordersize of 3, the 0,0 position of it is not on 0,0 of the screen, but rather on 3,3. The myMessage position of 10,10 then translates to 13,13 - and then the width has to be 614 so it would be centered (640 - 13 - 13).

I then used a different bordersize on this windowDef (1) for a thinner border, a bordercolor of "1,0,0,1" (that is, full red) and a backcolor of 0,0,0,0.5 (a black with 50% opacity).

One new attribute now is the text one - the everlasting message "HELLO WORLD". This is actually what it looks like: this defines which message will be shown on this windowDef.

Then we set the text scale by setting the textscale attribute, 1 being the original size of the "text material". In this case, 0.5 means that we're using it at half the size, which is pretty big for our purposes.

The font attribute says which font file we'll be using for this text. In this case, we're using one of the built-in fonts, but new fonts can be created and used here (I also expect to cover this on a later tutorial).

The textalign attribute is then used to say how this text is aligned to the windowDef bounding box - 0 meaning left, 1 meaning centered, and 2 meaning right. In this case we're using the value 1, which of course means that the text is centered in the windowDef and ultimately centered on screen.

Finally, the forecolor is a color attribute that says which color will be used in the foreground of this windowDef - meaning, in this case, the text itself. With the value of "0,0,1,1", it means we have a full blue as the text color.

But of course, GUI scripts won't be always made of crappy boxes and colors; this was merely an example. It's time for us to get into the real thing, and start adding real content to our GUI script. And that means adding images as materials. I'll be using a quick image I made, grab it from the source files (on the end of this tutorial) if you want to test it too.

Code:
windowDef Desktop {
  rect         0, 0, 640, 480
  bordersize   3
  bordercolor  1, 1, 1, 1
  backcolor    0.5, 0.5, 0.5, 1
  visible      1
  windowDef myMessage {
    rect         10, 10, 614, 40
    bordersize   1
    bordercolor  1, 0, 0, 1
    backcolor    0, 0, 0, 0.5
    text         "HELLO WORLD"
    textscale    0.5
    font         "fonts/english"
    textalign    1
    forecolor    0,0,1,1
  }
  windowDef myPic {
    rect         249, 164, 187, 165
    background   "tut1_ranger"
    matcolor     1,1,1,1
    visible 1
  }
}


Now we're making progress. The myPic windowDef is much more like the stuff you'd normally find on real GUIs: just an image and some attributes.

First there's the mandatory rect attribute. In this case, it resembles a box and sits on the middle of our Desktop screen.

Then, the background attribute. This is simply a filename - the name of a material we wish to use. There a few catches, however.

First, this is relative to the base DOOM 3 dir - so if you are running the main game (no mod), this would translate to "<doom 3 dir>/base/<filename>". Since I have used no directory name on this filename, it means this material must be sitting at the /base dir itself.

Second, the 'background' file is a material in TGA format, sans extension. So in the end it means that it's looking for "/base/tut1_ranger.tga".

And third, the material is scaled to fit the entire background of your windowDef. Unless you use scaling options (to create tiles), no matter which size the windowDef's rect is, it will always have the entire background material shown.

Then comes the matcolor attribute. Despite the name, this is not a color value. It still is in the R,G,B,A format, but the first values differ. They are not absolute values of colors to be used: they are percentages of each channel, meaning how much of each channel will be rendered.

Normally, this value would be "1,1,1,1" for a normal image displaying with 100% opacity. You can subtract from channel values, however - if a material has a matcolor value of "0,1,1,1", for example, its red channel will be left out and the resulting image would be a mix between green and blue. This is actually a very powerful feature; using one single grayscale image, you are able to manipulate its color channels during runtime to use different color settings for the image, as if the image was being colorized - you could use the same grayscale image for both red and blue huds on a red vs blue team setup, for example.

That pretty much sums a basic GUI script. Now, it's time to (finally) test it using the DOOM 3 engine itself. Save the above script as a file - I'm using the tut1.gui name - and place it on the game's /base dir.

Run DOOM 3, pull down the console (CTRL+ALT+~ or ~) and type:

Code:
testgui tut1.gui


Ta-da! Your test GUI should load and display on the whole screen. Of course, use whichever name you used when creating your .gui file. In any case, check the result of the one I created below.

Image
Yeah, it's an ugly screen, but it's a real GUI script, and serves its purpose.

Well, that pretty much sums it all. There are still lots to be covered, of course, but we'll get there.

Download source and example files

Also available: Translated french version by RedEyes



USCM-Cid@Posted: Wed Aug 11, 2004 5:10 am :
I'm just curious but..if we successfully did this tutorial while having a bit of a hard time understanding it, since we may be extremely new to scripting, does that mean that doing our very own GUIs, to make doors, elevators, and such like that work when pushing a button, will be a hard time?...It's because I personally didn't really understand a lot of the stuff here, but I successfully did it. I think acquiring a skill such as coding, like other things, can be read but it's much more easier by actually doing it yourself?...



zeh@Posted: Wed Aug 11, 2004 1:34 pm :
USCM-Cid wrote:
I'm just curious but..if we successfully did this tutorial while having a bit of a hard time understanding it, since we may be extremely new to scripting, does that mean that doing our very own GUIs, to make doors, elevators, and such like that work when pushing a button, will be a hard time?...It's because I personally didn't really understand a lot of the stuff here, but I successfully did it. I think acquiring a skill such as coding, like other things, can be read but it's much more easier by actually doing it yourself?...


It's a tough question. See this tutorial as walking as a baby.. you first do it while your parents are holding your hands, but eventually you'll have to walk by yourself and there's no way anyone can *help* in that other than by looking; you have to try, fall on the floor, and try again.

What I tried to do was to provide as much information about what I was doing as possible. I think that simple copy&paste "tutorials" aren't worth anything, so I tried to keep away from that; but depending on the level and knowledge of the person who's reading it, the level of explanation I added might still be too low.

In this case, the tutorial can be seem as someone showing what's possible, and ways to do it. Even though this is a "closed recipe", it's something that can be adapted to other cases by changing something here and there and in doing so, you'll start to understand the intrincates of the script system. Learning coding in any language - this includes the GUI script system - is 95% experimentation and 5% reading a tutorial/reference, in my opinion, so if you didn't understand some part, try messing around with it until you understand what's going on and why.



USCM-Cid@Posted: Wed Aug 11, 2004 9:01 pm :
Okay. I did do it and all and even added a few things to my script that you didn't have (My own .tga picture for instance.) and I guess thats what kinda got me to grasp the concept of this. Still, coding does seem kinda difficult for me since I'm just starting out with it. Ah well.



redneckprovence@Posted: Sat Aug 28, 2004 1:44 pm :
Very nice tut :D
I have two questions
first when you open the ranger image using MS photo editor or Paint shop, it has a black background which does not appear when running the script. Why ? Is it always the same for all images having a black background ?
then I am part of a french forum on doom3 editing and I'd like to know if I could use and translate your tutorials. I would basically translate your text but using my proper images to illustrate it.
As few of the french guys I meet on the forum don't understand a lot of english or are not confident with the language , that would be nice for them to be able to get your experience of GUI scripting through the translation. Obviously you would be cited and this page linked.
Tell me your thoughts. Many thanks in advance
get on your tuts it does help a lot of people I'm sure

red-



zeh@Posted: Sat Aug 28, 2004 3:03 pm :
redneckprovence wrote:
Very nice tut :D
I have two questions
first when you open the ranger image using MS photo editor or Paint shop, it has a black background which does not appear when running the script. Why ? Is it always the same for all images having a black background ?


It's because the TGA images take transparency from the alpha channel; the black area is unused so it could be any color. When opening a tga image, unlike a png file or a gif file, you won't see the transparency right away; you have to open the channels window for that. That's also why if you open the font image files, for example, you'll see an all white image.. because the alpha channel is what defines the glyph formats. Tutorial #3 in this series go into detail on how to export tga files with correct transparency.

Quote:
then I am part of a french forum on doom3 editing and I'd like to know if I could use and translate your tutorials. I would basically translate your text but using my proper images to illustrate it.
As few of the french guys I meet on the forum don't understand a lot of english or are not confident with the language , that would be nice for them to be able to get your experience of GUI scripting through the translation. Obviously you would be cited and this page linked.
Tell me your thoughts. Many thanks in advance
get on your tuts it does help a lot of people I'm sure


Sure, no problem, that'd be awesome, the more the better. Just make sure you mention doom3world.org and link to the original tut somewhere.



redneckprovence@Posted: Sat Aug 28, 2004 4:15 pm :
:D:D:D
Many many thanks zeh
As soon as it is finished I'll post the link here so you can have a look on the work. It will be almost a copy/paste but the translation will definetly help all the guys here.

-red



b0ksah@Posted: Mon Sep 06, 2004 6:44 pm :
Bumpy :)



zigzulquit@Posted: Thu Dec 15, 2005 11:29 am :
testgui tut1.gui

Didn't work for me, but the following below did:

testgui tut_1.gui



zeh@Posted: Thu Dec 15, 2005 11:44 am :
zigzulquit wrote:
testgui tut1.gui

Didn't work for me, but the following below did:

testgui tut_1.gui


That's because you used "tut_1.gui" as the file name, while I used "tut1.gui" on the above example.

Anyhow, the name doesn't matter, so whatever works, works.



HunterKiller@Posted: Tue Jan 17, 2006 2:00 pm :
Hey dude, blz? :)

Do you have a list of your articles? I tried the forum search and the modwiki search, but seems that I am missing some.

Congrats by the well written articles! Im a seasoned Unreal coder flerting with Quake4, and your posts really make the transition smooth.

Take care,



rallu@Posted: Tue Jan 17, 2006 2:28 pm :
Tutorials can be found both forums and modwiki.

here is link to modwiki:

http://www.modwiki.net/wiki/Tutorial_list#GUI_scripting



zeh@Posted: Tue Jan 17, 2006 4:09 pm :
Hey Hunter, prazer, blz :D

Well, the above link (thanks Rallu) is a good list of the GUI articles available. You will also find a good link on the forum sticky post, and talking about my D3 stuff, I use an index on my directory listing just for reference.



HunterKiller@Posted: Wed Jan 18, 2006 12:27 am :
Rallu gets bonus! Interesting thing is that I was looking for that kind of stuff in the GUI area of modwiki. :)

And thanks again for writing the tuts zeh!

Take care



Project_Nightmare@Posted: Wed Jan 18, 2006 3:22 am :
HunterKiller wrote:
Rallu gets bonus! Interesting thing is that I was looking for that kind of stuff in the GUI area of modwiki. :)

And thanks again for writing the tuts zeh!

Take care
Ya, they are a piece of work :D But I like the downloads better than the tuts to understand what they're saying better :twisted: