I've re-zipped the source off my Windows desktop:
http://quakeone.com/proquake/interims/E ... in_src.rar
Code to look for: File = insertions_3d.c
Code: Select all
// insertions_3d.c -- Adds stuff to 3D world
#include "quakedef.h"
//qbool SV_InvisibleToClient(edict_t *viewer, edict_t *seen);
//void R_EmitBox (const vec_rgba_t myColor, const vec3_t centerpoint, const vec3_t xyz_mins, const vec3_t xyz_maxs, const qbool bTopMost, const qbool bLines, const float Expandsize);
qbool SV_InvisibleToClient(edict_t *viewer, edict_t *seen);
void ShowBBoxes_Draw (void)
{
extern edict_t *sv_player;
edict_t *ed;
int i;
entity_t *clent;
// Cycle through the server entities
for (i=1, ed=NEXT_EDICT(sv.edicts) ; i<sv.num_edicts ; i++, ed=NEXT_EDICT(ed))
{
char *my_classname = PR_GETSTRING(ed->v.classname);
vec_rgba_t BoxColor;
if (ed->free)
continue; // Free edict, just skip
clent = NULL;
if (i<cl.num_entities) // Baker: Not all server ents get communicated to client.
clent = cl_entities + i;
if (ed == sv_player && !chase_active.integer)
continue; // Don't draw in this scenario
// Obtain Quake specific super-special color
do
{
int special_entity = 0;
if (COM_StringMatchCaseless (my_classname, "info_player_start")) special_entity = 1;
else if (COM_StringMatchCaseless (my_classname, "info_player_coop")) special_entity = 2;
else if (COM_StringMatchCaseless (my_classname, "info_player_deathmatch")) special_entity = 3;
switch (special_entity)
{
case 1: VectorSetColor4f (BoxColor, 1, 0, 0, 0.40); break;
case 2: VectorSetColor4f (BoxColor, 1, 1, 0, 0.30); break;
case 3: VectorSetColor4f (BoxColor, 1, 0, 0, 0.40); break;
}
// If we already determined a color, exit stage left ...
if (special_entity)
continue;
// normal color selection
switch ((int)ed->v.solid)
{
case SOLID_NOT: VectorSetColor4f (BoxColor, 1, 1, 1, 0.05);break;
case SOLID_TRIGGER: VectorSetColor4f (BoxColor, 1, 0, 1, 0.10);break;
case SOLID_BBOX: VectorSetColor4f (BoxColor, 0, 1, 0, 0.10);break;
case SOLID_SLIDEBOX: VectorSetColor4f (BoxColor, 1, 0, 0, 0.10);break;
case SOLID_BSP: VectorSetColor4f (BoxColor, 0, 0, 1, 0.05);break;
default: VectorSetColor4f (BoxColor, 0, 0, 0, 0.50);break;
}
} while (0);
// Render box phase
do
{
qbool isPointEntity = VectorCompare(ed->v.mins, ed->v.maxs); // point entities have 0 size
if (isPointEntity)
{
qbool bRenderTopMost = false;
qbool bRenderLines = false;
float size_adjust = 4.0f; // Give it a little bit of size
R_EmitBox (BoxColor, ed->v.origin, NULL, NULL, bRenderTopMost, bRenderLines, size_adjust);
}
else
{
qbool bRenderTopMost = false;
qbool bRenderLines = false;
float size_adjust = -0.10f; // Pull size in just a little
R_EmitBox (BoxColor, ed->v.origin, ed->v.mins, ed->v.maxs, bRenderTopMost, bRenderLines, size_adjust);
}
} while (0);
// Render Caption phase
do
{
extern vec3_t lastbox_mins, lastbox_maxs; // Last box rendering result
vec3_t caption_location;
if (SV_InvisibleToClient (sv_player, ed))
continue; //don't draw if entity cannot be seen
// Averaging the vectors gives the center
LerpVector (lastbox_mins, lastbox_maxs, 0.5, caption_location);
// Except we want the caption to be at the top
caption_location[2] = lastbox_maxs[2];
// Add a couple of height units to make it overhead
caption_location[2] = caption_location[2] + 20;
// Depending on cvar value, have caption show different things
switch (tool_showbboxes.integer)
{
default:
case 1: R_EmitCaption (caption_location, my_classname); break;
case 2: R_EmitCaption (caption_location, ed->v.model ? PR_GETSTRING(ed->v.model) : "No model"); break;
case 3: R_EmitCaption (caption_location, va("ent #%i", i)); break;
case 4: R_EmitCaption (caption_location, va("modelindex %i", (int)ed->v.modelindex)); break;
// Baker: First ... this isn't how you do it with sprites.
case 5: // Client mirror
R_EmitCaption (caption_location,
va("\bServer model:\b\n"
"'%s'\n"
"\bClient model:\b\n"
"'%s'", ed->v.model ? PR_GETSTRING(ed->v.model) : "No model", clent ? clent->model->name : "No entity"));
break;
}
} while (0);
// End of this entity
} // For Loop closing brace
// Now do static entities
for (i=0; i < cl.num_statics; i++)
{
vec_rgba_t BoxColor;
clent = &cl_static_entities[i];
if (!(clent->visframe == r_framecount))
continue; // Not visible this frame
VectorSetColor4f (BoxColor, 1, 0.5, 0, 0.40);
// Render box phase
do
{
qbool isPointEntity = VectorCompare(clent->model->mins, clent->model->maxs); // point entities have 0 size
if (isPointEntity)
{
qbool bRenderTopMost = false;
qbool bRenderLines = false;
float size_adjust = 4.0f; // Give it a little bit of size
R_EmitBox (BoxColor, clent->currentorigin, NULL, NULL, bRenderTopMost, bRenderLines, size_adjust);
}
else
{
qbool bRenderTopMost = false;
qbool bRenderLines = false;
float size_adjust = -0.10f; // Pull size in just a little
R_EmitBox (BoxColor, clent->currentorigin, clent->model->mins, clent->model->maxs, bRenderTopMost, bRenderLines, size_adjust);
}
} while (0);
// Render Caption phase
do
{
extern vec3_t lastbox_mins, lastbox_maxs; // Last box rendering result
vec3_t caption_location;
// Averaging the vectors gives the center
LerpVector (lastbox_mins, lastbox_maxs, 0.5, caption_location);
// Except we want the caption to be at the top
caption_location[2] = lastbox_maxs[2];
// Add a couple of height units to make it overhead
caption_location[2] = caption_location[2] + 20;
// Depending on cvar value, have caption show different things
R_EmitCaption (caption_location, va("\bStatic ent\b %i '%s'\n", clent- cl_static_entities, clent->model->name));
} while (0);
// End of this entity
} // For Loop closing brace
}
As you can see in this code, I didn't draw the captions in 2D.

I drew them in 3D, hahaha
The 3D drawing of text works like this (really it is exactly the same as drawing a sprite) ...
Code: Select all
void R_EmitCaption (const vec3_t location, const char *caption)
{
const int string_length = strlen(caption);
const float charwidth = 8;
const float charheight = 8;
vec3_t point;
vec3_t right, up;
int string_columns, string_rows;
float string_width, string_height; // pixels
fRect_t captionbox;
int i, x, y;
qbool bronze = false;
// Step 1: Detemine Rows and columns
Text_Get_Columns_And_Rows (caption, &string_columns, &string_rows);
string_width = (float)string_columns * charwidth;
string_height = (float)string_rows * charheight;
// Step 2: Calculate bounds of rectangle
captionbox.top = -(float)string_height/2;
captionbox.bottom = (float)string_height/2;
captionbox.left = -(float)string_width /2;
captionbox.right = (float)string_width /2;
// Copy the view origin up and right angles
VectorCopy (vup, up);
VectorCopy (vright, right);
mglPushStates ();
GL_Bind (char_texture);
MeglDisable (GL_CULL_FACE);
MeglEnable (GL_ALPHA_TEST);
MeglDepthRange (0, 0.3); // Baker: The "hack the depth range" trick. Not sure why this works, but it does ...
mglFinishedStates ();
for (i=0, x = 0, y =0; i<string_length; i++)
{
// Deal with the string
if (caption[i] == '\n') { x = 0; y ++; continue; } // Reset the row, ignore and carry on
if (caption[i] == '\b')
{
bronze = !bronze;
continue;
} // Toggle the bronzing and carry on
x++; // New character to print
{
fRect_t charcoords;
float s, t;
int charcode = caption[i] | (bronze * 128); // "ascii" ish character code, but Quake character code
int charrow = charcode >> 4; // Fancy way of dividing by 16
int charcol = charcode & 15; // column = mod (16-1)
// Calculate s, t texture coords from character set image
// if (bronze) charcode |=128;
s = charcol * 0.0625f; // 0.0625 = 1/16th
t = charrow * 0.0625f;
// Calculate coords
// charcoords.top = captionbox.top;
// charcoords.bottom = captionbox.bottom;
// charcoords.left = captionbox.left + (x/string_length)*(captionbox.right - captionbox.left);
// charcoords.right = captionbox.left + ((x+1)/string_length)*(captionbox.right - captionbox.left);
// charcoords.top = captionbox.top + (y/(float)string_rows)*(captionbox.bottom - captionbox.top);
// charcoords.bottom = captionbox.top + ((y+1)/(float)string_rows)*(captionbox.bottom - captionbox.top);
charcoords.top = captionbox.top + ((string_rows - 1 - y)/(float)string_rows)*(captionbox.bottom - captionbox.top);
charcoords.bottom = captionbox.top + (((string_rows - 1 - y)+1)/(float)string_rows)*(captionbox.bottom - captionbox.top);
charcoords.left = captionbox.left + (x/(float)string_columns)*(captionbox.right - captionbox.left);
charcoords.right = captionbox.left + ((x+1)/(float)string_columns)*(captionbox.right - captionbox.left);
// Draw box
eglBegin (GL_QUADS);
// top left
eglTexCoord2f (s, t + 0.03125);
VectorMultiplyAdd (location, charcoords.top, up, point);
VectorMultiplyAdd (point, charcoords.left, right, point);
eglVertex3fv (point);
// top, right
eglTexCoord2f (s + 0.0625, t + 0.03125); // 0.03125 = 1/32th;
VectorMultiplyAdd (location, charcoords.top, up, point);
VectorMultiplyAdd (point, charcoords.right, right, point);
eglVertex3fv (point);
// bottom right
eglTexCoord2f (s + 0.0625, t);
VectorMultiplyAdd (location, charcoords.bottom, up, point);
VectorMultiplyAdd (point, charcoords.right, right, point);
eglVertex3fv (point);
// bottom, left
eglTexCoord2f (s, t);
VectorMultiplyAdd (location, charcoords.bottom, up, point);
VectorMultiplyAdd (point, charcoords.left, right, point);
eglVertex3fv (point);
eglEnd ();
}
}
MeglEnable (GL_CULL_FACE);
MeglDisable (GL_ALPHA_TEST);
MeglDepthRange (0, 1);
mglPopStates ();
}
And as you can see, I used your anti-wallhack code to test for entity visibility to decide whether or not to display the text.
Obviously drawing the text in the 3D phase makes more sense since:
1. I'm drawing boxes around stuff anyways. That has to be in the 3D rendering phase.
2. The 2D phase would introduce irritating factors not drawing over the HUD, how to scale the text for screen resolution and other stuff I didn't want to do.
3. Why do unnecessary projection calculations in the 2D phase ... I mean that's just faking 3D anyway. So do it in the 3D phase. But at the end and ignore depth testing.