32 bit TGA Graphics on HUD
The simple bit
The first thing we need to do is to load tga textures into the system. Fortunately Quake2 already understands the tga file format, it uses it for the skybox images and also writes tga files for screenshots. All we need to do is persuade it to use the format for pictures as well.

Look at this function Draw_FindPic in gl_draw.c.
image_t	*Draw_FindPic (char *name)
{
	image_t *gl;
	char	fullname[MAX_QPATH];

	if (name[0] != '/' && name[0] != '\\')
	{
		Com_sprintf (fullname, sizeof(fullname), "pics/%s.pcx", name);
		gl = GL_FindImage (fullname, it_pic);
	}
	else
		gl = GL_FindImage (name+1, it_pic);

	return gl;
}            
This is the function which is called when the system wants to get an image to render for the hud or for the menu system. Normally the name parameter is given without a path or an extension, and Quake2 looks for a .pcx file in the pics directory. The function GL_FindImage will search the image cache to check if the image has already been loaded. If not the disk and .pak files are searched. If the image can be found, a pointer to its loaded data is returned, otherwise GL_FindImage returns null.

All we need to do here is to make it look for .tga files first. If it finds one, then all well and good, otherwise we'll go and look for a .pcx.

Change the function like so:
image_t	*Draw_FindPic (char *name)
{
	image_t *gl;
	char	fullname[MAX_QPATH];

	if (name[0] != '/' && name[0] != '\\')
	{
		Com_sprintf (fullname, sizeof(fullname), "pics/%s.tga", name);         // c14 change this
		gl = GL_FindImage (fullname, it_pic);
		if (!gl) {	                                                                       // c14 these 4 lines here
			Com_sprintf (fullname, sizeof(fullname), "pics/%s.pcx", name);
			gl = GL_FindImage (fullname, it_pic);
		}
	}
	else
		gl = GL_FindImage (name+1, it_pic);

	return gl;
}          
Blending
Blending is simple enough. Further down in gl_draw.c find the function Draw_Pic.
void Draw_Pic (int x, int y, char *pic)
{
	image_t *gl;

	gl = Draw_FindPic (pic);
	if (!gl)
	{
		ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", pic);
		return;
	}
	if (scrap_dirty)
		Scrap_Upload ();

	if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) && !gl->has_alpha)
		qglDisable (GL_ALPHA_TEST);

	GL_Bind (gl->texnum);
	qglBegin (GL_QUADS);
	qglTexCoord2f (gl->sl, gl->tl);
	qglVertex2f (x, y);
	qglTexCoord2f (gl->sh, gl->tl);
	qglVertex2f (x+gl->width, y);
	qglTexCoord2f (gl->sh, gl->th);
	qglVertex2f (x+gl->width, y+gl->height);
	qglTexCoord2f (gl->sl, gl->th);
	qglVertex2f (x, y+gl->height);
	qglEnd ();

	if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) )  && !gl->has_alpha)
		qglEnable (GL_ALPHA_TEST);
}           
This function calls Draw_FindPic to get a pointer to the image information, binds the texture and draws a rectangle on the screen. x and y are the screen coordinate for the image, gl->width and gl->height are the dimensions of the image to be drawn and gl->sl, gl->tl, gl->sh and gl->th are the texture coordinates.

The part we are interested in is the lines where we Enable and Disable GL_ALPHA_TEST. Change the function to this:
void Draw_Pic (int x, int y, char *pic)
{
	image_t *gl;

	gl = Draw_FindPic (pic);
	if (!gl)
	{
		ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", pic);
		return;
	}
	if (scrap_dirty)
		Scrap_Upload ();

	if (gl->paletted) {
		if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) && !gl->has_alpha)
			qglDisable (GL_ALPHA_TEST);
	}
	else {
		qglDisable (GL_ALPHA_TEST);
		qglEnable (GL_BLEND);
	}


	GL_Bind (gl->texnum);
	qglBegin (GL_QUADS);
	qglTexCoord2f (gl->sl, gl->tl);
	qglVertex2f (x, y);
	qglTexCoord2f (gl->sh, gl->tl);
	qglVertex2f (x+gl->width, y);
	qglTexCoord2f (gl->sh, gl->th);
	qglVertex2f (x+gl->width, y+gl->height);
	qglTexCoord2f (gl->sl, gl->th);
	qglVertex2f (x, y+gl->height);
	qglEnd ();


	if (gl->paletted) {
		if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) )  && !gl->has_alpha)
			qglEnable (GL_ALPHA_TEST);
	}
	else {
		qglEnable (GL_ALPHA_TEST);
		qglDisable (GL_BLEND);
	}


}           
Now we are checking to see if the image has a palette, if so we will handle it as before, otherwise we will enable blending.

If you're not very familiar with opengl, you might be a little confused as to why we disable GL_ALPHA_TEST. When enabled GL_ALPHA_TEST examines the alpha value of a pixel compares it with a reference value. Depending on whether the pixel to be rendered has a higher or lower alpha than the reference, the pixel either will or will not be rendered. This is an on-off test with no shades between. Instead, we want to enable GL_BLEND so that the pixels are overlaid on the screen in proportion to their alpha.

Now if you look just above this function you will find Draw_StretchPic. You need to make similar changes there.
void Draw_StretchPic (int x, int y, int w, int h, char *pic)
{
	image_t *gl;

	gl = Draw_FindPic (pic);
	if (!gl)
	{
		ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", pic);
		return;
	}

	if (scrap_dirty)
		Scrap_Upload ();

	if (gl->paletted) {
		if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) ) && !gl->has_alpha)
			qglDisable (GL_ALPHA_TEST);
	}
	else {
		qglDisable (GL_ALPHA_TEST);
		qglEnable (GL_BLEND);
	}


	GL_Bind (gl->texnum);
	qglBegin (GL_QUADS);
	qglTexCoord2f (gl->sl, gl->tl);
	qglVertex2f (x, y);
	qglTexCoord2f (gl->sh, gl->tl);
	qglVertex2f (x+w, y);
	qglTexCoord2f (gl->sh, gl->th);
	qglVertex2f (x+w, y+h);
	qglTexCoord2f (gl->sl, gl->th);
	qglVertex2f (x, y+h);
	qglEnd ();

	if (gl->paletted) {
		if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( gl_config.renderer & GL_RENDERER_RENDITION ) )  && !gl->has_alpha)
			qglEnable (GL_ALPHA_TEST);
	}
	else {
		qglEnable (GL_ALPHA_TEST);
		qglDisable (GL_BLEND);
	}

}           
The first problem
What we have done so far does what it's supposed to, but there are a couple of issues that need to be fixed. The first problem is that unless you replace ALL of your .pcx files with .tga, you will probable find a serious drop in framerate. I'll explain... Lets say that we have a file wflag1.tga that we intend to draw on the hud, the following happens:
  1. We call Draw_Pic with the name 'wflag1'
  2. Draw_Pic calls Draw_FindPic
  3. Draw_FindPic calls GL_FindImage to look for pics/wflag1.tga
  4. GL_FindImage searches the image cache and cannot find the file
  5. GL_FindImage searches the disk and .pak files and loads the file

Now in the next frame, the following happens:
  1. We call Draw_Pic with the name 'wflag1'
  2. Draw_Pic calls Draw_FindPic
  3. Draw_FindPic calls GL_FindImage to look for pics/wflag1.tga
  4. GL_FindImage searches the image cache and finds the file already there

This is perfect. But consider the process if we do not have a wflag1.tga, and are relying on wflag1.pcx instead:
  1. We call Draw_Pic with the name 'wflag1'
  2. Draw_Pic calls Draw_FindPic
  3. Draw_FindPic calls GL_FindImage to look for pics/wflag1.tga
  4. GL_FindImage searches the image cache and cannot find the file
  5. GL_FindImage searches the disk and .pak files and cannot find it
  6. Draw_FindPic calls GL_FindImage to look for pics/wflag1.pcx
  7. GL_FindImage searches the image cache and cannot find the file
  8. GL_FindImage searches the disk and .pak files and loads the file

And in the next frame:
  1. We call Draw_Pic with the name 'wflag1'
  2. Draw_Pic calls Draw_FindPic
  3. Draw_FindPic calls GL_FindImage to look for pics/wflag1.tga
  4. GL_FindImage searches the image cache and cannot find the file
  5. GL_FindImage searches the disk and .pak files and cannot find it
  6. Draw_FindPic calls GL_FindImage to look for pics/wflag1.pcx
  7. GL_FindImage searches the image cache and finds the file already there

Each frame, the system is searching the disk for the non-existant .tga file even though we have a perfectly good .pcx already loaded in memory.

We will deal with this by changing the way we search the image cache, relying solely on file name and ignoring the extension.

The function we want is GL_FindImage
image_t	*GL_FindImage (char *name, imagetype_t type)
{
	image_t	*image;
	int		i, len;
	byte	*pic, *palette;
	int		width, height;

	if (!name)
		return NULL;	//	ri.Sys_Error (ERR_DROP, "GL_FindImage: NULL name");
	len = strlen(name);
	if (len<5)
		return NULL;	//	ri.Sys_Error (ERR_DROP, "GL_FindImage: bad name: %s", name);

	// look for it
	for (i=0, image=gltextures ; i<numgltextures ; i++,image++)
	{
		if (!strcmp(name, image->name))
		{
			image->registration_sequence = registration_sequence;
			return image;
		}
	}         
Change the code as follows, so that we only campare names up to but not including the extension.
image_t	*GL_FindImage (char *name, imagetype_t type)
{
	image_t	*image;
	int		i, len;
	byte	*pic, *palette;
	int		width, height;

	if (!name)
		return NULL;	//	ri.Sys_Error (ERR_DROP, "GL_FindImage: NULL name");
	len = strlen(name);
	if (len<5)
		return NULL;	//	ri.Sys_Error (ERR_DROP, "GL_FindImage: bad name: %s", name);

	// look for it

	for (i=0, image=gltextures ; i<numgltextures ; i++,image++)
	{
		if (!strncmp(name, image->name, len-3))
		{
			image->registration_sequence = registration_sequence;
			return image;
		}
	}         
The second problem
You might never come across the second problem, but if you want a transparent console, then you probably will. The image for the console is pics/conback.pcx. It is drawn part of the screen if you bring it down during the game and if you add a pics/conback.tga you can make it partially transparent. The problem comes when you are not in a game. Before the game starts, or if you disconnect from a game, the console covers the whole screen, but if the system doesn't have anything to render behind it, you will be able to see through the console to the previous contents of the frame buffers. This is ugly and distracting. The console is drawn by the function SCR_DrawConsole in the file cl_scrn.c. Note that this is part of the quake2.exe, not ref_gl.dll.
void SCR_DrawConsole (void)
{
	Con_CheckResize ();

	if (cls.state == ca_disconnected || cls.state == ca_connecting)
	{	// forced full screen console
		Con_DrawConsole (1.0);
		return;
	}

	if (cls.state != ca_active || !cl.refresh_prepped)
	{	// connected, but can't render
		Con_DrawConsole (0.5);
		re.DrawFill (0, viddef.height/2, viddef.width, viddef.height/2, 0);
		return;
	}

	if (scr_con_current)
	{
		Con_DrawConsole (scr_con_current);
	}
	else
	{
		if (cls.key_dest == key_game || cls.key_dest == key_message)
			Con_DrawNotify ();	// only draw notify in game
	}
}           
You'll notice in the middle of this function, that if the client is connected, but for some reason not in a position to render, such as while it is loading the first map, then the console is drawn halfway down the screen, and the remainder of the screen is filled in black. All we need to do is ensure that the entire screen is filled with black before we draw the console, but only when we're not in game:
void SCR_DrawConsole (void)
{
	Con_CheckResize ();

	if (cls.state == ca_disconnected || cls.state == ca_connecting)
	{	// forced full screen console
		re.DrawFill (0, 0, viddef.width, viddef.height, 0);   // c14 add this line
		Con_DrawConsole (1.0);
		return;
	}

	if (cls.state != ca_active || !cl.refresh_prepped)
	{	// connected, but can't render
		re.DrawFill (0, 0, viddef.width, viddef.height, 0);   // c14 change this line and it needs moving to before Con_DrawConsole
		Con_DrawConsole (0.5);
		return;
	}

	if (scr_con_current)
	{
		Con_DrawConsole (scr_con_current);
	}
	else
	{
		if (cls.key_dest == key_game || cls.key_dest == key_message)
			Con_DrawNotify ();	// only draw notify in game
	}
}           
The finished product blended hud, crosshairs and semi-transparent console