warzone2100/3rdparty/quesoglc/ofont.c

354 lines
10 KiB
C

/* QuesoGLC
* A free implementation of the OpenGL Character Renderer (GLC)
* Copyright (c) 2002, 2004-2009, Bertrand Coconnier
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* $Id$ */
/* Defines the methods of an object that is intended to managed fonts */
/** \file
* defines the object __GLCfont which manage the fonts
*/
#include <math.h>
#include "internal.h"
/* Constructor of the object : it allocates memory and initializes the member
* of the new object.
* The user must give the master 'inParent' which the font will instantiate.
*/
__GLCfont* __glcFontCreate(GLint inID, __GLCmaster* inMaster,
__GLCcontext* inContext, GLint inCode)
{
__GLCfont *This = NULL;
assert(inContext);
This = (__GLCfont*)__glcMalloc(sizeof(__GLCfont));
if (!This) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
memset(This, 0, sizeof(__GLCfont));
if (inMaster) {
/* At font creation, the default face is the first one.
* glcFontFace() can change the face.
*/
This->faceDesc = __glcFaceDescCreate(inMaster, NULL, inContext, inCode);
if (!This->faceDesc) {
__glcFree(This);
return NULL;
}
This->charMap = __glcFaceDescGetCharMap(This->faceDesc, inContext);
if (!This->charMap) {
__glcFaceDescDestroy(This->faceDesc, inContext);
__glcFree(This);
return NULL;
}
This->parentMasterID = __glcMasterGetID(inMaster, inContext);
}
else {
/* Creates an empty font (used by glcGenFontID() to reserve font IDs) */
This->faceDesc = NULL;
This->charMap = NULL;
This->parentMasterID = 0;
}
This->id = inID;
This->maxMetricCached = GL_FALSE;
memset(This->maxMetric, 0, 6 * sizeof(GLfloat));
return This;
}
/* Destructor of the object */
void __glcFontDestroy(__GLCfont *This, __GLCcontext* inContext)
{
if (This->charMap)
__glcCharMapDestroy(This->charMap);
if (This->faceDesc)
__glcFaceDescDestroy(This->faceDesc, inContext);
__glcFree(This);
}
/* Extract from the font the glyph which corresponds to the character code
* 'inCode'.
*/
__GLCglyph* __glcFontGetGlyph(const __GLCfont *This, const GLint inCode,
const __GLCcontext* inContext)
{
/* Try to get the glyph from the character map */
__GLCglyph* glyph = __glcCharMapGetGlyph(This->charMap, inCode);
if (!glyph) {
/* If it fails, we must extract the glyph from the face */
glyph = __glcFaceDescGetGlyph(This->faceDesc, inCode, inContext);
if (!glyph)
return NULL;
/* Update the character map so that the glyph will be cached */
__glcCharMapAddChar(This->charMap, inCode, glyph);
}
return glyph;
}
/* Get the bounding box of a glyph according to the size given by inScaleX and
* inScaleY. The result is returned in outVec. 'inCode' contains the character
* code for which the bounding box is requested.
*/
GLfloat* __glcFontGetBoundingBox(const __GLCfont *This, const GLint inCode,
GLfloat* outVec, const __GLCcontext* inContext,
const GLfloat inScaleX, const GLfloat inScaleY)
{
/* Get the glyph from the font */
__GLCglyph* glyph = __glcFontGetGlyph(This, inCode, inContext);
assert(outVec);
if (!glyph)
return NULL;
/* If the bounding box of the glyph is cached then copy it to outVec and
* return.
*/
if (glyph->boundingBoxCached && inContext->enableState.glObjects) {
memcpy(outVec, glyph->boundingBox, 4 * sizeof(GLfloat));
return outVec;
}
/* Otherwise, we must extract the bounding box from the face file */
if (!__glcFaceDescGetBoundingBox(This->faceDesc, glyph->index, outVec,
inScaleX, inScaleY, inContext))
return NULL;
/* Special case for glyphes which have no bounding box (i.e. spaces) */
if ((fabs(outVec[0] - outVec[2]) < GLC_EPSILON)
|| (fabs(outVec[1] - outVec[3]) < GLC_EPSILON)) {
GLfloat advance[2] = {0.f, 0.f};
if (__glcFontGetAdvance(This, inCode, advance, inContext, inScaleX,
inScaleY)) {
if (fabs(outVec[0] - outVec[2]) < GLC_EPSILON)
outVec[2] += advance[0];
if (fabs(outVec[1] - outVec[3]) < GLC_EPSILON)
outVec[3] += advance[1];
}
}
/* Copy the result to outVec and return */
if (inContext->enableState.glObjects) {
memcpy(glyph->boundingBox, outVec, 4 * sizeof(GLfloat));
glyph->boundingBoxCached = GL_TRUE;
}
return outVec;
}
/* Get the advance of a glyph according to the size given by inScaleX and
* inScaleY. The result is returned in outVec. 'inCode' contains the character
* code for which the advance is requested.
*/
GLfloat* __glcFontGetAdvance(const __GLCfont* This, const GLint inCode,
GLfloat* outVec, const __GLCcontext* inContext,
const GLfloat inScaleX, const GLfloat inScaleY)
{
/* Get the glyph from the font */
__GLCglyph* glyph = __glcFontGetGlyph(This, inCode, inContext);
assert(outVec);
if (!glyph)
return NULL;
/* If the advance of the glyph is cached then copy it to outVec and
* return.
*/
if (glyph->advanceCached && inContext->enableState.glObjects) {
memcpy(outVec, glyph->advance, 2 * sizeof(GLfloat));
return outVec;
}
/* Otherwise, we must extract the advance from the face file */
if (!__glcFaceDescGetAdvance(This->faceDesc, glyph->index, outVec, inScaleX,
inScaleY, inContext))
return NULL;
/* Copy the result to outVec and return */
if (inContext->enableState.glObjects) {
memcpy(glyph->advance, outVec, 2 * sizeof(GLfloat));
glyph->advanceCached = GL_TRUE;
}
return outVec;
}
/* Get the maximum metrics of a face that is the bounding box that encloses
* every glyph of the face, and the maximum advance of the face.
*/
GLfloat* __glcFontGetMaxMetric(__GLCfont* This, GLfloat* outVec,
const __GLCcontext* inContext,
const GLfloat inScaleX, const GLfloat inScaleY)
{
assert(outVec);
if (This->maxMetricCached && inContext->enableState.glObjects) {
memcpy(outVec, This->maxMetric, 6 * sizeof(GLfloat));
return outVec;
}
if (!__glcFaceDescGetMaxMetric(This->faceDesc, outVec, inContext, inScaleX,
inScaleY))
return NULL;
/* Copy the result to outVec and return */
if (inContext->enableState.glObjects) {
memcpy(This->maxMetric, outVec, 6 * sizeof(GLfloat));
This->maxMetricCached = GL_TRUE;
}
return outVec;
}
/* Get the kerning information of a pair of glyph according to the size given by
* inScaleX and inScaleY. The result is returned in outVec. 'inCode' contains
* the current character code and 'inPrevCode' the character code of the
* previously displayed character.
*/
GLfloat* __glcFontGetKerning(const __GLCfont* This, const GLint inCode,
const GLint inPrevCode, GLfloat* outVec,
const __GLCcontext* inContext,
const GLfloat inScaleX, const GLfloat inScaleY)
{
__GLCglyph* glyph = __glcFontGetGlyph(This, inCode, inContext);
__GLCglyph* prevGlyph = __glcFontGetGlyph(This, inPrevCode, inContext);
if (!glyph || !prevGlyph)
return NULL;
return __glcFaceDescGetKerning(This->faceDesc, glyph->index, prevGlyph->index,
inScaleX, inScaleY, outVec, inContext);
}
/* This internal function tries to open the face file which name is identified
* by 'inFace'. If it succeeds, it closes the previous face and stores the new
* face attributes in the __GLCfont object "inFont". Otherwise, it leaves the
* font unchanged. GL_TRUE or GL_FALSE are returned to indicate if the function
* succeeded or not.
*/
GLboolean __glcFontFace(__GLCfont* This, const GLCchar8* inFace,
__GLCcontext *inContext)
{
__GLCfaceDescriptor *faceDesc = NULL;
__GLCmaster *master = NULL;
__GLCcharMap* newCharMap = NULL;
/* TODO : Verify if the font has already the required face activated */
master = __glcMasterCreate(This->parentMasterID, inContext);
if (!master)
return GL_FALSE;
/* Get the face descriptor of the face identified by the string inFace */
faceDesc = __glcFaceDescCreate(master, inFace, inContext, 0);
if (!faceDesc) {
__glcMasterDestroy(master);
return GL_FALSE;
}
newCharMap = __glcFaceDescGetCharMap(faceDesc, inContext);
if (!newCharMap) {
__glcFaceDescDestroy(faceDesc, inContext);
__glcMasterDestroy(master);
return GL_FALSE;
}
__glcMasterDestroy(master);
#ifndef GLC_FT_CACHE
/* If the font belongs to GLC_CURRENT_FONT_LIST then open the font file */
if (FT_List_Find(&inContext->currentFontList, This)) {
/* Open the new face */
if (!__glcFaceDescOpen(faceDesc, inContext)) {
__glcFaceDescDestroy(faceDesc, inContext);
__glcCharMapDestroy(newCharMap);
return GL_FALSE;
}
/* Close the current face */
__glcFontClose(This);
}
#endif
/* Destroy the current charmap */
if (This->charMap)
__glcCharMapDestroy(This->charMap);
This->charMap = newCharMap;
__glcFaceDescDestroy(This->faceDesc, inContext);
This->faceDesc = faceDesc;
This->maxMetricCached = GL_FALSE;
memset(This->maxMetric, 0, 6 * sizeof(GLfloat));
return GL_TRUE;
}
/* Load a glyph of the current font face and stores the corresponding data in
* the corresponding face. The size of the glyph is given by inScaleX and
* inScaleY. 'inGlyphIndex' contains the index of the glyph in the font file.
*/
GLboolean __glcFontPrepareGlyph(const __GLCfont* This,
const __GLCcontext* inContext,
const GLfloat inScaleX, const GLfloat inScaleY,
const GLCulong inGlyphIndex)
{
GLboolean result = __glcFaceDescPrepareGlyph(This->faceDesc, inContext,
inScaleX, inScaleY,
inGlyphIndex);
#ifndef GLC_FT_CACHE
__glcFaceDescClose(This->faceDesc);
#endif
return result;
}