Q3CenterMGON Home Q3Center   Q3Center
 
Q3Arena

    Home
    Submit News
    Contact Admin
    News Archive
    Features
    Q3 Strategy
    Mod Reviews
    Map Reviews
    Skins & Models
    File Index
    Benchmarks
    Technology
    Clans
    Link To Q3C
    IRC Chat
    Wallpaper

Clan Community
    Clans Home
    Clans News
    Clans Admin
    Clans Forum
    Clans Hosting
Q3A Console
    Commands
    Variables
    Tweaking
Site Information
    The Staff
    Hosting
MGO Channel
    MGON
    MGOChat
   Action Channel
    DarkSector
    Duke Nukem
    Halo
    HalfLife
    Quake 3
    Soldier of Fortune
    Team Fortress
    Unreal
    Wheel of Time
   Strategy Channel
    Ground Control
    Subtitans
    Worms
   RPG Channel
    Horizons
    Nox
    Roleplay Haven
   Simulations Channel
    Creatures
    Pokémon
    The Sims
   Racing Channel
    Racing Source
    Driver
   Console Channel
    Nintendo 64
Tuesday, Apr 25  

UI Coding Tutorial #1
When I first downloaded the Quake3 source, I found the folder within the source directory called UI. I figured it was just menu stuff, nothing special and moved on to the server side stuff. But when I was asked to learn how the menu code works, I sure thought of it differently.

You can do a lot of stuff with the UI code, but in this tutorial I will be detailing how the UI works.


Open up ui_menu.c in the UI folder. At the top you will see this:

#include "ui_local.h"


#define ID_SINGLEPLAYER 10
#define ID_MULTIPLAYER 11
#define ID_SETUP 12
#define ID_DEMOS 13
#define ID_CINEMATICS 14
#define ID_MODS 15
#define ID_EXIT 16

#define MAIN_BANNER_MODEL "models/mapobjects/banner/banner5.md3"
#define MAIN_MENU_VERTICAL_SPACING 34

Here is all the initial definitions for the main menu buttons. You can probably figure out what’s what. Near the bottom, you will see model definitions, that is for the “Quake3” model that’s at the top of the main menu. All the text-based buttons (even the ones that pulse) are code-based, without pictures. I’ll show you how to put your own picture-buttons later on.

Now for the next bit:

typedef struct {
menuframework_s menu;

menutext_s singleplayer;
menutext_s multiplayer;
menutext_s setup;
menutext_s demos;
menutext_s cinematics;
menutext_s mods;
menutext_s exit;

qhandle_t bannerModel;
} mainmenu_t;


static mainmenu_t s_main;

Here are additional definitions, basically what each button is. On the left you can see menutext_s’s, and a qhandle_t. These just tell Quake3 what type of button you’re using. Also, you can just comment out the bannermodel reference here and the button will not show up at all.


/*
=================
MainMenu_ExitAction
=================
*/

static void MainMenu_ExitAction( qboolean result ) {
if( !result ) {
return;
}
UI_PopMenu();
UI_CreditMenu();
}

This defines the ExitAction (when you press quit). UI_PopMenu tells Quake3 to kill any menus that are running, then the creditmenu is the menu where you see the credits, and that is in ui_credits.c.

/*
=================
Main_MenuEvent
=================
*/

void Main_MenuEvent (void* ptr, int event) {
if( event != QM_ACTIVATED ) {
return;
}

switch( ((menucommon_s*)ptr)->id ) {
case ID_SINGLEPLAYER:
UI_SPLevelMenu();
break;

case ID_MULTIPLAYER:
UI_ArenaServersMenu();
break;

case ID_SETUP:
UI_SetupMenu();
break;

case ID_DEMOS:
UI_DemosMenu();
break;

case ID_CINEMATICS:
UI_CinematicsMenu();
break;

case ID_MODS:
UI_ModsMenu();
break;

case ID_EXIT:
UI_ConfirmMenu( "EXIT GAME?", NULL, MainMenu_ExitAction );
break;
}
}

This tells Quake3 what to do if a button gets clicked on. Here different buttons will trigger other menus.

/*
===============
Main_MenuDraw
===============
*/

static void Main_MenuDraw( void ) {
refdef_t refdef;
refEntity_t ent;
vec3_t origin;
vec3_t angles;
float adjust;
float x, y, w, h;
vec4_t color = {0.5, 0, 0, 1};

// setup the refdef

memset( &refdef, 0, sizeof( refdef ) );

refdef.rdflags = RDF_NOWORLDMODEL;

AxisClear( refdef.viewaxis );

x = 0;
y = 0;

Here you can change the w and h variables (width and height) to whatever you want. (Try setting w = 640 and h = 480) =)

w = 500;
h = 60;
UI_AdjustFrom640( &x, &y, &w, &h );
refdef.x = x;
refdef.y = y;
refdef.width = w;
refdef.height = h;

adjust = 0;
// JDC: Kenneth asked me to stop this 1.0 * sin( (float)uis.realtime / 1000 );
refdef.fov_x = 60 + adjust;
refdef.fov_y = 19.6875 + adjust;

refdef.time = uis.realtime;

origin[0] = 300;
origin[1] = 0;
origin[2] = -32;

trap_R_ClearScene();

// add the model



memset( &ent, 0, sizeof(ent) );

adjust = 5.0 * sin( (float)uis.realtime / 5000 );
VectorSet( angles, 0, 180 + adjust, 0 );
AnglesToAxis( angles, ent.axis );
ent.hModel = s_main.bannerModel;
VectorCopy( origin, ent.origin );
VectorCopy( origin, ent.lightingOrigin );
ent.renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW;
VectorCopy( ent.origin, ent.oldorigin );

trap_R_AddRefEntityToScene( &ent );

trap_R_RenderScene( &refdef );

// standard menu drawing

Menu_Draw( &s_main.menu );

if (uis.demoversion) {
UI_DrawProportionalString( 320, 372, "DEMO FOR MATURE AUDIENCES DEMO", UI_CENTER|UI_SMALLFONT, color );
UI_DrawString( 320, 400, "Quake III Arena(c) 1999-2000, Id Software, Inc. All Rights Reserved", UI_CENTER|UI_SMALLFONT, color );
} else {
UI_DrawString( 320, 450, "Quake III Arena(c) 1999-2000, Id Software, Inc. All Rights Reserved", UI_CENTER|UI_SMALLFONT, color );
}
}

Most of this just talks about how the model will be drawn, but the bottom part adds the Id Software stuff, you might want to take out if it doesn’t match your new UI. For the next part I’m only going to go over one button, because the rest are about the same.


void UI_MainMenu( void ) {
int y;
int style = UI_CENTER | UI_DROPSHADOW;

trap_Cvar_Set( "sv_killserver", "1" );

if( !uis.demoversion && !ui_cdkeychecked.integer ) {
char key[17];

trap_GetCDKey( key, sizeof(key) );
if( strcmp( key, "123456789" ) == 0 ) {
UI_CDKeyMenu();
return;
}
}

memset( &s_main, 0 ,sizeof(mainmenu_t) );

MainMenu_Cache();

s_main.menu.draw = Main_MenuDraw;
s_main.menu.fullscreen = qtrue;
s_main.menu.wrapAround = qtrue;
s_main.menu.showlogo = qtrue;

y = 134;
s_main.singleplayer.generic.type = MTYPE_PTEXT;
s_main.singleplayer.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
s_main.singleplayer.generic.x = 320;
s_main.singleplayer.generic.y = y;
s_main.singleplayer.generic.id = ID_SINGLEPLAYER;
s_main.singleplayer.generic.callback = Main_MenuEvent;
s_main.singleplayer.string = "SINGLE PLAYER";
s_main.singleplayer.color = color_red;
s_main.singleplayer.style = style;

y += MAIN_MENU_VERTICAL_SPACING;

Ok, if you notice at the top, they define “y” and “style”. These just basically save the programmers time. The “y” is used to find the spacing for the menu buttons. Below the first button, you’ll see reference to the MAIN_MENU_VERTICAL_SPACING, that was defined before. It’s using a math formula to figure out where to stick the button on the y axis. (the x is the same for all of them) Now the style is defined, and so the programmers just have to type “style” in for the s_main.singleplayer.style (example) because the contents of “style” is the same for all the buttons.

y += MAIN_MENU_VERTICAL_SPACING;
s_main.setup.generic.type = MTYPE_PTEXT;
s_main.setup.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS;
s_main.setup.generic.x = 320;
s_main.setup.generic.y = y;
s_main.setup.generic.id = ID_SETUP;
s_main.setup.generic.callback = Main_MenuEvent;
s_main.setup.string = "SETUP";
s_main.setup.color = color_red;
s_main.setup.style = style;

Here is the main definitions for the SETUP button. You will see the math thingy at the top, and on the second line it tells Quake3 what generic type the button is. Then the flags, and the only real important thing there is that the button will “pulse” when the mouse is over it. The next is the x coordinate, after that the y, then it tells Quake3 to find the ID_SETUP when the button is clicked. (remember that from before?) Then it tells Quake3 which menu the action will be taking place in, then what text is actually going to be displayed, (change it to configuration for fun) what color is being used, and then the style part.
That’s basically how the Quake3 Main Menu works, and later I will do more tutorials about how to actually change things, etc.

-IoN_PuLse

Latest Features
UI Coding Tutorial #1 - IoN_PuLse - 22/04
The Q3Center Map Contest Verdict - PaRaDoX - 30/03
Q3 Console by Keen - Bigdog - 11/03
Quaker's Day - Marine71 - 09/03
Q3 Mods – End Of February - IoN_PuLse - 05/03

Forums
    Quake 3 Arena
    Q3A Strategy
    Hardware
    Art & Skinning
    MODS & Editing
    Clans Forum

Get your own »
Hardware

    Reviews
    Articles
    Hardware Q&A

Send Questions

Hosted sites
    Clans

   Modifications
    MODNews
    DBZ
    Dragonball Q
    Refraction
    Crusade
    Frenzy3
    007Q2
    CTF Resource

    Predator

   Skins/Art
    SKUN
    Skin & Model RC
    Arena X
    Elite Imagery
    Dethayngel
    Type3 Skins
    RuffSkinz

   Mapping
    Map CC
    Pur3 Q3
    RA3 Mapping
    Vexar's Maps
    Gef's Maps

   Misc.
    Console
    QTCentral
    Q3Log
    Shader Tool
    Quakeage
    XyGeNaTeD
    1on1 Q3

¯ Home         ¯ Top

The Gamers' Choice