Loading Screen Code Changes

Before you can add the code changes to implement the Loading Screen feature you first must have added the code changes for the Scripted Hud as described here and here. That done, we can move on to the new code changes. All changes take place in the CGame module except for some additions to the menudef.h file(s). It must be stressed that you have the latest version of the UI source code in your source tree before attempting any other code changes.

cg_draw.c

In the CG_Text_Paint function about line 179 add :

					colorBlack[3] = 1.0;
trap_R_SetColor( newColor );
// loadingscreen
// based on Tremulous code
} else if( style == ITEM_TEXTSTYLE_NEON ) {
vec4_t glow, outer, inner, white;

glow[ 0 ] = newColor[ 0 ] * 0.5;
glow[ 1 ] = newColor[ 1 ] * 0.5;
glow[ 2 ] = newColor[ 2 ] * 0.5;
glow[ 3 ] = newColor[ 3 ] * 0.2;

outer[ 0 ] = newColor[ 0 ];
outer[ 1 ] = newColor[ 1 ];
outer[ 2 ] = newColor[ 2 ];
outer[ 3 ] = newColor[ 3 ];

inner[ 0 ] = newColor[ 0 ] * 1.5 > 1.0f ? 1.0f : newColor[ 0 ] * 1.5;
inner[ 1 ] = newColor[ 1 ] * 1.5 > 1.0f ? 1.0f : newColor[ 1 ] * 1.5;
inner[ 2 ] = newColor[ 2 ] * 1.5 > 1.0f ? 1.0f : newColor[ 2 ] * 1.5;
inner[ 3 ] = newColor[ 3 ];

white[ 0 ] = white[ 1 ] = white[ 2 ] = white[ 3 ] = 1.0f;

trap_R_SetColor( glow );
CG_Text_PaintChar( x - 3, y - yadj - 3,
glyph->imageWidth + 6,
glyph->imageHeight + 6,
useScale,
glyph->s,
glyph->t,
glyph->s2,
glyph->t2,
glyph->glyph );

trap_R_SetColor( outer );
CG_Text_PaintChar( x - 1, y - yadj - 1,
glyph->imageWidth + 2,
glyph->imageHeight + 2,
useScale,
glyph->s,
glyph->t,
glyph->s2,
glyph->t2,
glyph->glyph );

trap_R_SetColor( inner );
CG_Text_PaintChar( x - 0.5, y - yadj - 0.5,
glyph->imageWidth + 1,
glyph->imageHeight + 1,
useScale,
glyph->s,
glyph->t,
glyph->s2,
glyph->t2,
glyph->glyph );

trap_R_SetColor( white );
// end loadingscreen

} CG_Text_PaintChar(x, y - yadj,


In the CG_DrawActive function about line 2662 add this :

	if ( !cg.snap ) {
// loadingscreen
#ifdef SCRIPTHUD
menuDef_t *loading = Menus_FindByName( "Loading" );
if(loading==NULL)
#endif
// end loadingscreen

CG_DrawInformation();

At the end of the file add this code :

// loadingscreen
#ifdef SCRIPTHUD
/*
======================
CG_UpdateMediaFraction
======================
*/
void CG_UpdateMediaFraction( float newFract )
{
cg.mediaFraction = newFract;
trap_UpdateScreen( );
}
/*
======================
CG_UpdateSoundFraction
======================
*/
void CG_UpdateSoundFraction( float newFract )
{
cg.soundFraction = newFract;
trap_UpdateScreen( );
}
/*
======================
CG_UpdateGraphicFraction
======================
*/
void CG_UpdateGraphicFraction( float newFract )
{
cg.graphicFraction = newFract;
trap_UpdateScreen( );
}
/*
====================
CG_DrawLoadingScreen
====================
*/
void CG_DrawLoadingScreen( void )
{
menuDef_t *loading = Menus_FindByName( "Loading" );
if(loading!=NULL) {
Menu_Paint( loading, qtrue );
} else {
CG_DrawInformation();
}
}
#endif // loadingscreen

cg_local.h

About line 445 added the following :

#define MAX_REWARDSTACK		10
#define MAX_SOUNDBUFFER 20 // loadingscreen
#ifdef SCRIPTHUD
typedef struct
{
int time;
int length;
} consoleLine_t;
#define MAX_CONSOLE_TEXT 8192
#define MAX_CONSOLE_LINES 32
#endif
// end loadingscreen

About line 659 in the definition of cg_t add :

	char			testModelName[MAX_QPATH];
qboolean testGun; // loadingscreen
#ifdef SCRIPTHUD
float mediaFraction;
float soundFraction;
float graphicFraction;
char consoleText[ MAX_CONSOLE_TEXT ];
consoleLine_t consoleLines[ MAX_CONSOLE_LINES ];
int numConsoleLines;
qboolean consoleValid;
#endif
} cg_t;

About line 1325 add :

qboolean CG_YourTeamHasFlag( void );
qboolean CG_OtherTeamHasFlag( void );
qhandle_t CG_StatusHandle(int task); // loadingscreen
#ifdef SCRIPTHUD
void CG_DrawLoadingScreen( void );
void CG_UpdateMediaFraction( float newFract );
void CG_UpdateSoundFraction( float newFract );
void CG_UpdateGraphicFraction( float newFract );
#endif
// end loadingscreen

cg_main.c

In the CG_RegisterSounds function about line 565 add :

	cgs.media.countPrepareSound = trap_S_RegisterSound( "sound/feedback/prepare.wav", qtrue );
#ifdef MISSIONPACK
cgs.media.countPrepareTeamSound = trap_S_RegisterSound( "sound/feedback/prepare_team.wav", qtrue );
#endif // loadingscreen
#ifdef SCRIPTHUD
CG_UpdateSoundFraction( 0.33f );
CG_UpdateMediaFraction( 0.20f );
#endif
// end loadingscreen
if ( cgs.gametype >= GT_TEAM || cg_buildScript.integer ) {

In the CG_RegisterSounds function about line 625 add :

		cgs.media.yourTeamTookTheFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_team_1flag.wav", qtrue );
cgs.media.enemyTookTheFlagSound = trap_S_RegisterSound( "sound/teamplay/voc_enemy_1flag.wav", qtrue );
#endif
} // loadingscreen
#ifdef SCRIPTHUD
CG_UpdateSoundFraction( 0.60f );
CG_UpdateMediaFraction( 0.30f );
#endif
// end loadingscreen

cgs.media.tracerSound = trap_S_RegisterSound( "sound/weapons/machinegun/buletby1.wav", qfalse );
cgs.media.selectSound = trap_S_RegisterSound( "sound/weapons/change.wav", qfalse );

In the CG_RegisterSounds function about line 702 add :

	cgs.media.jumpPadSound = trap_S_RegisterSound ("sound/world/jumppad.wav", qfalse );

// loadingscreen
#ifdef SCRIPTHUD
CG_UpdateSoundFraction( 0.75f );
CG_UpdateMediaFraction( 0.40f );
#endif
// end loadingscreen
for (i=0 ; i<4 ; i++) {
Com_sprintf (name, sizeof(name), "sound/player/footsteps/step%i.wav", i+1);

In the CG_RegisterSounds function about line 750 add :

		cgs.gameSounds[i] = trap_S_RegisterSound( soundName, qfalse );
} // loadingscreen
#ifdef SCRIPTHUD
CG_UpdateSoundFraction( 0.85f );
CG_UpdateMediaFraction( 0.50f );
#endif
// end loadingscreen
// FIXME: only needed with item
cgs.media.flightSound = trap_S_RegisterSound( "sound/items/flight.wav", qfalse );
cgs.media.medkitSound = trap_S_RegisterSound ("sound/items/use_medkit.wav", qfalse);

In the CG_RegisterGraphics function about line 863 add :

	trap_R_LoadWorldMap( cgs.mapname );

// loadingscreen
#ifdef SCRIPTHUD
CG_UpdateGraphicFraction( 0.20f );
CG_UpdateMediaFraction( 0.66f );
#endif
// end loadingscreen
// precache status bar pics
CG_LoadingString( "game media" );

In the CG_RegisterGraphics function about line 1030 add :

	cgs.media.teleportEffectModel = trap_R_RegisterModel( "models/misc/telep.md3" );
cgs.media.teleportEffectShader = trap_R_RegisterShader( "teleportEffect" );
#endif // loadingscreen
#ifdef SCRIPTHUD
CG_UpdateGraphicFraction( 0.50f );
CG_UpdateMediaFraction( 0.70f );
#endif
// end loadingscreen
#ifdef MISSIONPACK
cgs.media.kamikazeEffectModel = trap_R_RegisterModel( "models/weaphits/kamboom2.md3" );
cgs.media.kamikazeShockWave = trap_R_RegisterModel( "models/weaphits/kamwave.md3" );

In the CG_RegisterGraphics function about line 1111 add :

		cgs.gameModels[i] = trap_R_RegisterModel( modelName );
} // loadingscreen
#ifdef SCRIPTHUD
CG_UpdateGraphicFraction( 0.70f );
CG_UpdateMediaFraction( 0.85f );
#endif
// end loadingscreen
#ifdef MISSIONPACK // SCRIPTHUD
// new stuff
cgs.media.cursor = trap_R_RegisterShaderNoMip( "menu/art/3_cursor2" );

In the CG_Init function about line 2120 change the following :

	CG_InitConsoleCommands();
// loadingscreen
#ifdef SCRIPTHUD
String_Init();
CG_AssetCache();
CG_LoadHudMenu(); // load new hud stuff
trap_Cvar_Set( "ui_loading", "1" );
#endif
cg.weaponSelect = WP_MACHINEGUN;
cgs.redflag = cgs.blueflag = -1; // For compatibily, default to unset for
cgs.flagStatus = -1;
// old servers // get the rendering configuration from the client system
trap_GetGlconfig( &cgs.glconfig );
cgs.screenXScale = cgs.glconfig.vidWidth / 640.0;
cgs.screenYScale = cgs.glconfig.vidHeight / 480.0; // get the gamestate from the client system
trap_GetGameState( &cgs.gameState ); // check version
s = CG_ConfigString( CS_GAME_VERSION );
if ( strcmp( s, GAME_VERSION ) ) {
CG_Error( "Client/Server game mismatch: %s/%s", GAME_VERSION, s );
} s = CG_ConfigString( CS_LEVEL_START_TIME );
cgs.levelStartTime = atoi( s );
CG_ParseServerinfo(); // load the new map
#ifndef SCRIPTHUD
CG_LoadingString( "collision map" );
#endif
trap_CM_LoadMap( cgs.mapname );
//#ifdef SCRIPTHUD
// String_Init();
//#endif

cg.loading = qtrue; // force players to load instead of defer
#ifdef SCRIPTHUD
CG_RegisterSounds();
CG_UpdateSoundFraction( 1.0f );
CG_UpdateMediaFraction( 0.60f );
CG_RegisterGraphics();
CG_UpdateGraphicFraction( 1.0f );
CG_UpdateMediaFraction( 0.90f );
CG_RegisterClients(); // if low on memory, some clients will be deferred
CG_UpdateMediaFraction( 1.0f );
#else

CG_LoadingString( "sounds" );
CG_RegisterSounds();
CG_LoadingString( "graphics" );
CG_RegisterGraphics();
CG_LoadingString( "clients" );
CG_RegisterClients(); // if low on memory, some clients will be deferred
#endif //#ifdef SCRIPTHUD
// CG_AssetCache();
// CG_LoadHudMenu(); // load new hud stuff
//#endif cg.loading = qfalse; // future players will be deferred
CG_InitLocalEntities();
CG_InitMarkPolys();
// remove the last loading update
cg.infoScreenText[0] = 0;
// Make sure we have update values (scores)
CG_SetConfigValues();
CG_StartMusic();
CG_LoadingString( "" ); #ifdef MISSIONPACK
CG_InitTeamChat();
#endif CG_ShaderStateChanged();
trap_S_ClearLoopingSounds( qtrue );
#ifdef SCRIPTHUD
trap_Cvar_Set( "ui_loading", "0" );
cg.consoleValid = qtrue;
#endif
// end loadingscreen

}

cg_newdraw.c

Prior to the CG_OwnerDraw function at about line 1515 add this block of code :

// loadingscreen
// code based on Tremulous source code
#ifdef SCRIPTHUD
static void CG_DrawProgressBar( rectDef_t *rect, vec4_t color, float scale,
   int align, int textStyle, int special, float progress )
   {
   float rimWidth = rect->h / 20.0f;
   float doneWidth, leftWidth;
   float tx, ty, tw, th;
   char textBuffer[ 8 ];
   
   if( rimWidth < 0.6f )
   rimWidth = 0.6f;
 if( special >= 0.0f )
   rimWidth = special;
 if( progress < 0.0f )
   progress = 0.0f;
   else if( progress > 1.0f )
   progress = 1.0f;
   
   doneWidth = ( rect->w - 2 * rimWidth ) * progress;
   leftWidth = ( rect->w - 2 * rimWidth ) - doneWidth;
   
   trap_R_SetColor( color );
   
   //draw rim and bar
   if( align == ITEM_ALIGN_RIGHT )
   {
   CG_DrawPic( rect->x, rect->y, rimWidth, rect->h, cgs.media.whiteShader );
   CG_DrawPic( rect->x + rimWidth, rect->y,
   leftWidth, rimWidth, cgs.media.whiteShader );
   CG_DrawPic( rect->x + rimWidth, rect->y + rect->h - rimWidth,
   leftWidth, rimWidth, cgs.media.whiteShader );
   CG_DrawPic( rect->x + rimWidth + leftWidth, rect->y,
   rimWidth + doneWidth, rect->h, cgs.media.whiteShader );
   }
   else
   {
   CG_DrawPic( rect->x, rect->y, rimWidth + doneWidth, rect->h, cgs.media.whiteShader );
   CG_DrawPic( rimWidth + rect->x + doneWidth, rect->y,
   leftWidth, rimWidth, cgs.media.whiteShader );
   CG_DrawPic( rimWidth + rect->x + doneWidth, rect->y + rect->h - rimWidth,
   leftWidth, rimWidth, cgs.media.whiteShader );
   CG_DrawPic( rect->x + rect->w - rimWidth, rect->y, rimWidth, rect->h, cgs.media.whiteShader );
   }
 trap_R_SetColor( NULL );
             
   //draw text
   if( scale > 0.0 )
   {
   Com_sprintf( textBuffer, sizeof( textBuffer ), "%d%%", (int)( progress * 100 ) );
   tw = CG_Text_Width( textBuffer, scale, 0 );
   th = scale * 40.0f;
   
   switch( align )
   {
   case ITEM_ALIGN_LEFT:
   tx = rect->x + ( rect->w / 10.0f );
   ty = rect->y + ( rect->h / 2.0f ) + ( th / 2.0f );
   break;
 case ITEM_ALIGN_RIGHT:
   tx = rect->x + rect->w - ( rect->w / 10.0f ) - tw;
   ty = rect->y + ( rect->h / 2.0f ) + ( th / 2.0f );
   break;
 case ITEM_ALIGN_CENTER:
   tx = rect->x + ( rect->w / 2.0f ) - ( tw / 2.0f );
   ty = rect->y + ( rect->h / 2.0f ) + ( th / 2.0f );
   break;
 default:
   tx = ty = 0.0f;
   }
   
   CG_Text_Paint( tx, ty, scale, color, textBuffer, 0, 0, textStyle );
   }
   }
static void CG_DrawProgressLabel( rectDef_t *rect, float text_x, float text_y, vec4_t color,
   float scale, int align, const char *s, float fraction )
   {
   vec4_t white = { 1.0f, 1.0f, 1.0f, 1.0f };
   float tx, tw = CG_Text_Width( s, scale, 0 );
 switch( align )
   {
   case ITEM_ALIGN_LEFT:
   tx = 0.0f;
   break;
 case ITEM_ALIGN_RIGHT:
   tx = rect->w - tw;
   break;
 case ITEM_ALIGN_CENTER:
   tx = ( rect->w / 2.0f ) - ( tw / 2.0f );
   break;
 default:
   tx = 0.0f;
   }
   
   if( fraction < 1.0f )
   CG_Text_Paint( rect->x + text_x + tx, rect->y + text_y, scale, white,
   s, 0, 0, ITEM_TEXTSTYLE_NORMAL );
   else
   CG_Text_Paint( rect->x + text_x + tx, rect->y + text_y, scale, color,
   s, 0, 0, ITEM_TEXTSTYLE_NEON );
   }
static void CG_DrawMediaProgress( rectDef_t *rect, vec4_t color, float scale,
   int align, int textStyle, int special )
   {
   CG_DrawProgressBar( rect, color, scale, align, textStyle, special, cg.mediaFraction );
   }
static void CG_DrawMediaProgressLabel( rectDef_t *rect, float text_x, float text_y,
   vec4_t color, float scale, int align )
   {
   CG_DrawProgressLabel( rect, text_x, text_y, color, scale, align, "Overall", cg.mediaFraction );
   }
static void CG_DrawSoundProgress( rectDef_t *rect, vec4_t color, float scale,
   int align, int textStyle, int special )
   {
   CG_DrawProgressBar( rect, color, scale, align, textStyle, special, cg.soundFraction );
   }
static void CG_DrawSoundProgressLabel( rectDef_t *rect, float text_x, float text_y,
   vec4_t color, float scale, int align )
   {
   CG_DrawProgressLabel( rect, text_x, text_y, color, scale, align, "Sound", cg.soundFraction );
   }
static void CG_DrawGraphicProgress( rectDef_t *rect, vec4_t color, float scale,
   int align, int textStyle, int special )
   {
   CG_DrawProgressBar( rect, color, scale, align, textStyle, special, cg.graphicFraction );
   }
static void CG_DrawGraphicProgressLabel( rectDef_t *rect, float text_x, float text_y,
   vec4_t color, float scale, int align )
   {
   CG_DrawProgressLabel( rect, text_x, text_y, color, scale, align, "Graphics", cg.graphicFraction );
   }
static void CG_DrawLevelShot( rectDef_t *rect )
           {
   const char *s;
   const char *info;
   qhandle_t levelshot;
   qhandle_t detail;
   
   info = CG_ConfigString( CS_SERVERINFO );
   s = Info_ValueForKey( info, "mapname" );
   levelshot = trap_R_RegisterShaderNoMip( va( "levelshots/%s.tga", s ) );
   
   if( !levelshot )
   levelshot = trap_R_RegisterShaderNoMip( "menu/art/unknownmap" );
   
   trap_R_SetColor( NULL );
   CG_DrawPic( rect->x, rect->y, rect->w, rect->h, levelshot );
   
   // blend a detail texture over it
   detail = trap_R_RegisterShader( "levelShotDetail" );
   CG_DrawPic( rect->x, rect->y, rect->w, rect->h, detail );
   }
static void CG_DrawLoadingString( rectDef_t *rect, float text_x, float text_y, vec4_t color,
   float scale, int align, int textStyle, const char *s )
   {
   float tw, th, tx;
   int pos, i;
   char buffer[ 1024 ];
   char *end;
   
   if( !s[ 0 ] )
   return;
   
   strcpy( buffer, s );
   tw = CG_Text_Width( s, scale, 0 );
   th = scale * 40.0f;
 pos = i = 0;
             
   while( pos < strlen( s ) )
   {
   strcpy( buffer, &s[ pos ] );
   tw = CG_Text_Width( buffer, scale, 0 );
 while( tw > rect->w )
   {
   end = strrchr( buffer, ' ' );
   
   if( end == NULL )
   break;
   
   *end = '\0';
   tw = CG_Text_Width( buffer, scale, 0 );
   }
 switch( align )
   {
   case ITEM_ALIGN_LEFT:
   tx = rect->x;
   break;
 case ITEM_ALIGN_RIGHT:
   tx = rect->x + rect->w - tw;
   break;
 case ITEM_ALIGN_CENTER:
   tx = rect->x + ( rect->w / 2.0f ) - ( tw / 2.0f );
   break;
 default:
   tx = 0.0f;
   }
   
   CG_Text_Paint( tx + text_x, rect->y + text_y + i * ( th + 3 ), scale, color,
   buffer, 0, 0, textStyle );
   
   pos += strlen( buffer ) + 1;
   i++;
   }
   }
static void CG_DrawLevelName( rectDef_t *rect, float text_x, float text_y,
   vec4_t color, float scale, int align, int textStyle )
   {
   const char *s;
   
   s = CG_ConfigString( CS_MESSAGE );
 CG_DrawLoadingString( rect, text_x, text_y, color, scale, align, textStyle, s );
           }
static void CG_DrawMOTD( rectDef_t *rect, float text_x, float text_y,
   vec4_t color, float scale, int align, int textStyle )
   {
   const char *s;
   
   s = CG_ConfigString( CS_MOTD );
 CG_DrawLoadingString( rect, text_x, text_y, color, scale, align, textStyle, s );
           }
static void CG_DrawHostname( rectDef_t *rect, float text_x, float text_y,
   vec4_t color, float scale, int align, int textStyle )
   {
   char buffer[ 1024 ];
   const char *info;
 info = CG_ConfigString( CS_SERVERINFO );
             
   Q_strncpyz( buffer, Info_ValueForKey( info, "sv_hostname" ), 1024 );
   Q_CleanStr( buffer );
 CG_DrawLoadingString( rect, text_x, text_y, color, scale, align, textStyle, buffer );
           }
#endif
// end loadingscreen

In the CG_OwnerDraw function about line 1970 add :

  case CG_2NDPLACE:
CG_Draw2ndPlace(&rect, scale, color, shader, textStyle);
break;
// loadingscreen
#ifdef SCRIPTHUD
case CG_LOAD_LEVELSHOT:
CG_DrawLevelShot( &rect );
break;
case CG_LOAD_MEDIA:
CG_DrawMediaProgress( &rect, color, scale, align, textStyle, special );
break;
case CG_LOAD_MEDIA_LABEL:
CG_DrawMediaProgressLabel( &rect, text_x, text_y, color, scale, align );
break;
case CG_LOAD_SOUND:
CG_DrawSoundProgress( &rect, color, scale, align, textStyle, special );
break;
case CG_LOAD_SOUND_LABEL:
CG_DrawSoundProgressLabel( &rect, text_x, text_y, color, scale, align );
break;
case CG_LOAD_GRAPHIC:
CG_DrawGraphicProgress( &rect, color, scale, align, textStyle, special );
break;
case CG_LOAD_GRAPHIC_LABEL:
CG_DrawGraphicProgressLabel( &rect, text_x, text_y, color, scale, align );
break;
case CG_LOAD_LEVELNAME:
CG_DrawLevelName( &rect, text_x, text_y, color, scale, align, textStyle );
break;
case CG_LOAD_MOTD:
CG_DrawMOTD( &rect, text_x, text_y, color, scale, align, textStyle );
break;
case CG_LOAD_HOSTNAME:
CG_DrawHostname( &rect, text_x, text_y, color, scale, align, textStyle );
break;
#endif
// end loadingscreen

default:
break;
}

cg_view.c

In the CG_DrawActiveFrame function about line 770 add :

	// if we are only updating the screen as a loading
// pacifier, don't even try to read snapshots
if ( cg.infoScreenText[0] != 0 ) {
// loadingscreen
#ifdef SCRIPTHUD
CG_DrawLoadingScreen( );
#else

CG_DrawInformation();
#endif
// end loadingscreen

return;
}

In the CG_DrawActiveFrame function about line 793 add :

	// if we haven't received any snapshots yet, all
// we can draw is the information screen
if ( !cg.snap || ( cg.snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) {
// loadingscreen
#ifdef SCRIPTHUD
CG_DrawLoadingScreen( );
#else

CG_DrawInformation();
#endif
// end loadingscreen

return;
}

menudef.h

There are two menudef.h files that must be modified for this feature. The first is in the source code tree in the ui folder. This folder is at the same level as the code folder that contains the Quake 3 source code. The second is in the baseq3/ui folder where the menu and Hud scripts are located. These files must be identical so the following changes must be done to both of them.

At about line 47 add :

#define ITEM_TEXTSTYLE_SHADOWEDMORE 6
// loadingscreen
#define ITEM_TEXTSTYLE_NEON 7
// loadingscreen

About line 225 add :

#define CG_2NDPLACE 68
#define CG_CAPTURES 69 // loadingscreen
#define CG_LOAD_LEVELSHOT 75
#define CG_LOAD_MEDIA 76
#define CG_LOAD_MEDIA_LABEL 77
#define CG_LOAD_LEVELNAME 78
#define CG_LOAD_MOTD 79
#define CG_LOAD_HOSTNAME 80
#define CG_LOAD_SOUND 81
#define CG_LOAD_SOUND_LABEL 82
#define CG_LOAD_GRAPHIC 83
#define CG_LOAD_GRAPHIC_LABEL 84
// end loadingscreen

 

Return to Home Page