Expand Up
@@ -36,6 +36,412 @@
#define ASCII_NEWLINE (' @' )
#define ASCII_COLOURMODE (' #' )
#ifdef WZ_OS_MAC
# include < QuesoGLC/glc.h>
#else
# include < GL/glc.h>
#endif
static char font_family[128 ];
static char font_face_regular[128 ];
static char font_face_bold[128 ];
static float font_size = 12 .f;
// Contains the font color in the following order: red, green, blue, alpha
static float font_colour[4 ] = {1 .f , 1 .f , 1 .f , 1 .f };
static GLint _glcContext = 0 ;
static GLint _glcFont_Regular = 0 ;
static GLint _glcFont_Bold = 0 ;
/* **************************************************************************/
/*
* Source
*/
/* **************************************************************************/
void iV_font (const char *fontName, const char *fontFace, const char *fontFaceBold)
{
if (_glcContext)
{
debug (LOG_ERROR, " Cannot change font in running game, yet." );
return ;
}
if (fontName)
{
sstrcpy (font_family, fontName);
}
if (fontFace)
{
sstrcpy (font_face_regular, fontFace);
}
if (fontFaceBold)
{
sstrcpy (font_face_bold, fontFaceBold);
}
}
static inline void iV_printFontList (void )
{
unsigned int i;
unsigned int font_count = glcGeti (GLC_CURRENT_FONT_COUNT);
debug (LOG_NEVER, " GLC_CURRENT_FONT_COUNT = %d" , font_count);
if (font_count == 0 )
{
debug (LOG_ERROR, " The required font (%s) isn't loaded" , font_family);
// Fall back to unselected fonts since the requested font apparently
// isn't available.
glcEnable (GLC_AUTO_FONT);
}
for (i = 0 ; i < font_count; ++i)
{
GLint font = glcGetListi (GLC_CURRENT_FONT_LIST, i);
/* The output of the family name and the face is printed using 2 steps
* because glcGetFontc and glcGetFontFace return their result in the
* same buffer (according to GLC specs).
*/
char prBuffer[1024 ];
snprintf (prBuffer, sizeof (prBuffer), " Font #%d : %s " , (int )font, (const char *)glcGetFontc (font, GLC_FAMILY));
prBuffer[sizeof (prBuffer) - 1 ] = 0 ;
sstrcat (prBuffer, (char const *)glcGetFontFace (font));
debug (LOG_NEVER, " %s" , prBuffer);
}
}
static void iV_initializeGLC (void )
{
if (_glcContext)
{
return ;
}
_glcContext = glcGenContext ();
if (!_glcContext)
{
debug (LOG_ERROR, " Failed to initialize" );
}
else
{
debug (LOG_NEVER, " Successfully initialized. _glcContext = %d" , (int )_glcContext);
}
glcContext (_glcContext);
glcEnable (GLC_AUTO_FONT); // We *do* want font fall-backs
glcRenderStyle (GLC_TEXTURE);
glcStringType (GLC_UTF8_QSO); // Set GLC's string type to UTF-8 FIXME should be UCS4 to avoid conversions
#ifdef WZ_OS_MAC
{
char resourcePath[PATH_MAX];
CFURLRef resourceURL = CFBundleCopyResourcesDirectoryURL (CFBundleGetMainBundle ());
if (CFURLGetFileSystemRepresentation (resourceURL, true , (UInt8 *) resourcePath, PATH_MAX))
{
sstrcat (resourcePath, " /Fonts" );
glcAppendCatalog (resourcePath);
}
else
{
debug (LOG_ERROR, " Could not change to resources directory." );
}
if (resourceURL != NULL )
{
CFRelease (resourceURL);
}
}
#endif
_glcFont_Regular = glcGenFontID ();
_glcFont_Bold = glcGenFontID ();
if (!glcNewFontFromFamily (_glcFont_Regular, font_family))
{
debug (LOG_ERROR, " Failed to select font family %s as regular font" , font_family);
}
else
{
debug (LOG_NEVER, " Successfully selected font family %s as regular font" , font_family);
}
if (!glcFontFace (_glcFont_Regular, font_face_regular))
{
debug (LOG_WARNING, " Failed to select the \" %s\" font face of font family %s" , font_face_regular, font_family);
}
else
{
debug (LOG_NEVER, " Successfully selected the \" %s\" font face of font family %s" , font_face_regular, font_family);
}
if (!glcNewFontFromFamily (_glcFont_Bold, font_family))
{
debug (LOG_ERROR, " iV_initializeGLC: Failed to select font family %s for the bold font" , font_family);
}
else
{
debug (LOG_NEVER, " Successfully selected font family %s for the bold font" , font_family);
}
if (!glcFontFace (_glcFont_Bold, font_face_bold))
{
debug (LOG_WARNING, " Failed to select the \" %s\" font face of font family %s" , font_face_bold, font_family);
}
else
{
debug (LOG_NEVER, " Successfully selected the \" %s\" font face of font family %s" , font_face_bold, font_family);
}
debug (LOG_NEVER, " Finished initializing GLC" );
}
void iV_TextInit ()
{
iV_initializeGLC ();
iV_SetFont (font_regular);
#ifdef DEBUG
iV_printFontList ();
#endif
}
void iV_TextShutdown ()
{
if (_glcFont_Regular)
{
glcDeleteFont (_glcFont_Regular);
}
if (_glcFont_Bold)
{
glcDeleteFont (_glcFont_Bold);
}
glcContext (0 );
if (_glcContext)
{
glcDeleteContext (_glcContext);
}
}
void iV_SetFont (enum iV_fonts FontID)
{
switch (FontID)
{
default :
case font_scaled:
case font_regular:
iV_SetTextSize (12 .f );
glcFont (_glcFont_Regular);
break ;
case font_large:
iV_SetTextSize (21 .f );
glcFont (_glcFont_Bold);
break ;
case font_small:
iV_SetTextSize (9 .f );
glcFont (_glcFont_Regular);
break ;
}
}
static inline float getGLCResolution (void )
{
float resolution = glcGetf (GLC_RESOLUTION);
// The default resolution as used by OpenGLC is 72 dpi
if (resolution == 0 .f )
{
return 72 .f ;
}
return resolution;
}
static inline float getGLCPixelSize (void )
{
float pixel_size = font_size * getGLCResolution () / 72 .f ;
return pixel_size;
}
static inline float getGLCPointWidth (const float * boundingbox)
{
// boundingbox contains: [ xlb ylb xrb yrb xrt yrt xlt ylt ]
// l = left; r = right; b = bottom; t = top;
float rightTopX = boundingbox[4 ];
float leftTopX = boundingbox[6 ];
float point_width = rightTopX - leftTopX;
return point_width;
}
static inline float getGLCPointHeight (const float * boundingbox)
{
// boundingbox contains: [ xlb ylb xrb yrb xrt yrt xlt ylt ]
// l = left; r = right; b = bottom; t = top;
float leftBottomY = boundingbox[1 ];
float leftTopY = boundingbox[7 ];
float point_height = fabsf (leftTopY - leftBottomY);
return point_height;
}
static inline float getGLCPointToPixel (float point_width)
{
float pixel_width = point_width * getGLCPixelSize ();
return pixel_width;
}
unsigned int iV_GetTextWidth (const char * string)
{
float boundingbox[8 ];
float pixel_width, point_width;
glcMeasureString (GL_FALSE, string);
if (!glcGetStringMetric (GLC_BOUNDS, boundingbox))
{
debug (LOG_ERROR, " Couldn't retrieve a bounding box for the string \" %s\" " , string);
return 0 ;
}
point_width = getGLCPointWidth (boundingbox);
pixel_width = getGLCPointToPixel (point_width);
return (unsigned int )pixel_width;
}
unsigned int iV_GetCountedTextWidth (const char * string, size_t string_length)
{
float boundingbox[8 ];
float pixel_width, point_width;
glcMeasureCountedString (GL_FALSE, string_length, string);
if (!glcGetStringMetric (GLC_BOUNDS, boundingbox))
{
debug (LOG_ERROR, " Couldn't retrieve a bounding box for the string \" %s\" of length %u" , string, (unsigned int )string_length);
return 0 ;
}
point_width = getGLCPointWidth (boundingbox);
pixel_width = getGLCPointToPixel (point_width);
return (unsigned int )pixel_width;
}
unsigned int iV_GetTextHeight (const char * string)
{
float boundingbox[8 ];
float pixel_height, point_height;
glcMeasureString (GL_FALSE, string);
if (!glcGetStringMetric (GLC_BOUNDS, boundingbox))
{
debug (LOG_ERROR, " Couldn't retrieve a bounding box for the string \" %s\" " , string);
return 0 ;
}
point_height = getGLCPointHeight (boundingbox);
pixel_height = getGLCPointToPixel (point_height);
return (unsigned int )pixel_height;
}
unsigned int iV_GetCharWidth (uint32_t charCode)
{
float boundingbox[8 ];
float pixel_width, point_width;
if (!glcGetCharMetric (charCode, GLC_BOUNDS, boundingbox))
{
debug (LOG_ERROR, " Couldn't retrieve a bounding box for the character code %u" , charCode);
return 0 ;
}
point_width = getGLCPointWidth (boundingbox);
pixel_width = getGLCPointToPixel (point_width);
return (unsigned int )pixel_width;
}
int iV_GetTextLineSize ()
{
float boundingbox[8 ];
float pixel_height, point_height;
if (!glcGetMaxCharMetric (GLC_BOUNDS, boundingbox))
{
debug (LOG_ERROR, " Couldn't retrieve a bounding box for the character" );
return 0 ;
}
point_height = getGLCPointHeight (boundingbox);
pixel_height = getGLCPointToPixel (point_height);
return (unsigned int )pixel_height;
}
static float iV_GetMaxCharBaseY (void )
{
float base_line[4 ]; // [ xl yl xr yr ]
if (!glcGetMaxCharMetric (GLC_BASELINE, base_line))
{
debug (LOG_ERROR, " Couldn't retrieve the baseline for the character" );
return 0 ;
}
return base_line[1 ];
}
int iV_GetTextAboveBase (void )
{
float point_base_y = iV_GetMaxCharBaseY ();
float point_top_y;
float boundingbox[8 ];
float pixel_height, point_height;
if (!glcGetMaxCharMetric (GLC_BOUNDS, boundingbox))
{
debug (LOG_ERROR, " Couldn't retrieve a bounding box for the character" );
return 0 ;
}
point_top_y = boundingbox[7 ];
point_height = point_base_y - point_top_y;
pixel_height = getGLCPointToPixel (point_height);
return (int )pixel_height;
}
int iV_GetTextBelowBase (void )
{
float point_base_y = iV_GetMaxCharBaseY ();
float point_bottom_y;
float boundingbox[8 ];
float pixel_height, point_height;
if (!glcGetMaxCharMetric (GLC_BOUNDS, boundingbox))
{
debug (LOG_ERROR, " Couldn't retrieve a bounding box for the character" );
return 0 ;
}
point_bottom_y = boundingbox[1 ];
point_height = point_bottom_y - point_base_y;
pixel_height = getGLCPointToPixel (point_height);
return (int )pixel_height;
}
void iV_SetTextColour (PIELIGHT colour)
{
font_colour[0 ] = colour.byte .r / 255 .0f ;
font_colour[1 ] = colour.byte .g / 255 .0f ;
font_colour[2 ] = colour.byte .b / 255 .0f ;
font_colour[3 ] = colour.byte .a / 255 .0f ;
}
/* * Draws formatted text with word wrap, long word splitting, embedded newlines
* (uses '@' rather than '\n') and colour toggle mode ('#') which enables or
* disables font colouring.
Expand Down
Expand Up
@@ -195,3 +601,79 @@ int iV_DrawFormattedText(const char* String, UDWORD x, UDWORD y, UDWORD Width, U
return jy;
}
void iV_DrawTextRotated (const char * string, float XPos, float YPos, float rotation)
{
GLint matrix_mode = 0 ;
ASSERT_OR_RETURN ( , string, " Couldn't render string!" );
pie_SetTexturePage (TEXPAGE_EXTERN);
glGetIntegerv (GL_MATRIX_MODE, &matrix_mode);
glMatrixMode (GL_TEXTURE);
glPushMatrix ();
glLoadIdentity ();
glMatrixMode (GL_MODELVIEW);
glPushMatrix ();
if (rotation != 0 .f )
{
rotation = 360 .f - rotation;
}
glTranslatef (XPos, YPos, 0 .f );
glRotatef (180 .f , 1 .f , 0 .f , 0 .f );
glRotatef (rotation, 0 .f , 0 .f , 1 .f );
glScalef (font_size, font_size, 0 .f );
glColor4fv (font_colour);
glFrontFace (GL_CW);
glcRenderString (string);
glFrontFace (GL_CCW);
glPopMatrix ();
glMatrixMode (GL_TEXTURE);
glPopMatrix ();
glMatrixMode (matrix_mode);
// Reset the current model view matrix
glLoadIdentity ();
}
static void iV_DrawTextRotatedFv (float x, float y, float rotation, const char * format, va_list ap)
{
va_list aq;
size_t size;
char * str;
/* Required because we're using the va_list ap twice otherwise, which
* results in undefined behaviour. See stdarg(3) for details.
*/
va_copy (aq, ap);
// Allocate a buffer large enough to hold our string on the stack
size = vsnprintf (NULL , 0 , format, ap);
str = (char *)alloca (size + 1 );
// Print into our newly created string buffer
vsprintf (str, format, aq);
va_end (aq);
// Draw the produced string to the screen at the given position and rotation
iV_DrawTextRotated (str, x, y, rotation);
}
void iV_DrawTextF (float x, float y, const char * format, ...)
{
va_list ap;
va_start (ap, format);
iV_DrawTextRotatedFv (x, y, 0 .f , format, ap);
va_end (ap);
}
void iV_SetTextSize (float size)
{
font_size = size;
}