q3mod

QuakeDev.com :: Q3MOD :: HUD DRAWING FOR DUMMIES

TUTORIAL 3a :: HUD Drawing For Dummies

Welcome back, today I will show you how to add new elements to the HUD. This tutorial is longer than my others, but bear with me and we will design a cool box that displays all our current ammo. Nice ey?

I will also note that I will be taking a different approach to my tutorials from here on in. Most of the teaching will be done through the use of comments in the code. I have colored them green to make it easier for you.

First things first open up cg_draw.c and head over to line number 517. We will be adding all new code from here on.

Add the following code :


/*
==============
CG_DrawSmallField
Draws small numbers for status bar and powerups.
==============
*/

static void CG_DrawSmallField (int x, int y, int width, int value)
{
    char num[16], *ptr;
    int l;
    int frame;

    if ( width < 1 ) {
        return;
    }

    // draw number string
    if ( width > 5 ) {
        width = 5;
    }

    switch ( width ) {
    case 1:
        value = value > 9 ? 9 : value;
        value = value < 0 ? 0 : value;
    break;
    case 2:
        value = value > 99 ? 99 : value;
        value = value < -9 ? -9 : value;
    break;
    case 3:
        value = value > 999 ? 999 : value;
        value = value < -99 ? -99 : value;
    break;
    case 4:
        value = value > 9999 ? 9999 : value;
        value = value < -999 ? -999 : value;
    break;
    }

    Com_sprintf (num, sizeof(num), "%i", value);
    l = strlen(num);
    if (l > width)
        l = width;
    x += 2 + CHAR_WIDTH/3*(width - l);

    ptr = num;
    while (*ptr && l)
    {
        if (*ptr == '-')
            frame = STAT_MINUS;
        else
            frame = *ptr -'0';

        CG_DrawPic( x,y, CHAR_WIDTH/3, CHAR_HEIGHT/3, cgs.media.numberShaders[frame] );
        x += CHAR_WIDTH/3;
        ptr++;
        l--;
     }
}


WHAT WE DID
We made a copy of the DrawField function from cg_drawtools.c, and added some new code to make the numbers display a little bit smaller. The code we added is colored green.

Underneath our new function paste this :


/*
==============
CG_DrawFrameRect
This draws a rectangular frame with a border.
==============
*/


static void CG_DrawFrameRect(int x, int y, int w, int h, int size, const float *color1, const float *color2)
{
    // trap our first color
    trap_R_SetColor(color1);
    
    // draw back layer first
    CG_FillRect(x, y, w, h, color1);
    
    // reset colors
    trap_R_SetColor(NULL);

    // trap our second color
    trap_R_SetColor(color2);

    // draw borders
    CG_DrawRect(x, y, w, h, size, color2);
    
    // reset colors
    trap_R_SetColor(NULL);
}



WHAT WE DID
We made a function that will draw a box of any given height and width, and color it, and position it where we specify.

Now for the heart of the beast, add this below what we just added :


// MAIN DRAWING FUNCTIONS
// CG_DrawAmmoBar : Draws our ammo bar

/*
==============
CG_DrawAmmoBar
This draws our nice ammo bar
==============
*/


static void CG_DrawAmmoBar( void )
{
    /*-------------------------------------------------------------
    // Setting it all up
    //-----------------------------------------------------------*/


    qhandle_t icon[8]; // Create an array for our icons
    playerState_t *ps; // Create a playerstate

    int i = 0;         // we will use these in our loop
    int iconNum = 0;   // this will be used for icon numbers
    int y = 105;       // this will be used for our y location for our icons

    int value[8];     // this is our array for our ammo amounts
    int valueNum = 0; // this will be used for our ammo amounts

    // set up our color array
    static float colors[2][4] = {
        { 1.0f, 1.0f, 1.0f, 1.0f }, // White
        { 0.0f, 0.0f, 0.0f, 0.5f }  // Black
    };

    ps = &cg.snap->ps; // initialize our player state

    // Set up our icon array
    icon[0] = cg_weapons[WP_MACHINEGUN].ammoIcon;
    icon[1] = cg_weapons[WP_SHOTGUN].ammoIcon;
    icon[2] = cg_weapons[WP_GRENADE_LAUNCHER].ammoIcon;
    icon[3] = cg_weapons[WP_ROCKET_LAUNCHER].ammoIcon;
    icon[4] = cg_weapons[WP_LIGHTNING].ammoIcon;
    icon[5] = cg_weapons[WP_RAILGUN].ammoIcon;
    icon[6] = cg_weapons[WP_PLASMAGUN].ammoIcon;
    icon[7] = cg_weapons[WP_BFG].ammoIcon;

    // set up our ammo amount array
    value[0] = ps->ammo[WP_MACHINEGUN];
    value[1] = ps->ammo[WP_SHOTGUN];
    value[2] = ps->ammo[WP_GRENADE_LAUNCHER];
    value[3] = ps->ammo[WP_ROCKET_LAUNCHER];
    value[4] = ps->ammo[WP_LIGHTNING];
    value[5] = ps->ammo[WP_RAILGUN];
    value[6] = ps->ammo[WP_PLASMAGUN];
    value[7] = ps->ammo[WP_BFG];

    /*-------------------------------------------------------------
    // Draw It All
    //-----------------------------------------------------------*/


    // Draw Ammo String Container
    CG_DrawFrameRect(0, 75, 100, 20, 1, colors[1], colors[0]);

    // Draw Ammo Icon and Ammo Amounts container
    CG_DrawFrameRect(0, 96, 100, 175, 1, colors[1], colors[0]);

    // OK our basic layout is set up, lets add some content :)
    // Lets add some text to our little box up top


    CG_DrawStringExt(10, 80, "Ammo", colors[0], qfalse, qfalse, 10, 10, 8);

    // Ok lets go ahead and add the ammo icons and the ammounts.

    // Here we use a for loop to draw the icons to the screen
    for(i = 0; i < 8; i++) // for i = 0, i is less than 8, and increment i by 1 each pass
    {
        
        CG_DrawPic( 10, y, 16, 16, icon[iconNum] ); // draw our icons
       
        CG_DrawSmallField ( 50, y, 3, value[valueNum] ); // draw our ammo ammounts
        y += 20; // increment y by 20

        iconNum++; // increment iconNum by 1

        valueNum++; // increment valueNum by 1
    } // when the loop realizes that it has reached 8, it will exit out.
}

Whew, that was hefty.
Dont worry, the next peice of code is only one line.

Scroll down to CG_DrawStatusBar:

/*
================
CG_DrawStatusBar
================
*/


#ifndef MISSIONPACK
static void CG_DrawStatusBar( void )

Now paste this after the first If statement :

CG_DrawAmmoBar(); // Draw our ammo bar


And there we have it. Compile the source, and run the mod. You should have a nifty frame on the left hand side displaying all our ammo.

Stay tuned for Chapter B of this two part epic, we will be adding a cvar that allows us to toggle our ammo box. I will also be introducing you to the UI project, and how to add custom controls.

Happy Fragging.

PSYKoR3