Integrate QuesoGLC.

Since no fixed release is out at the moment, always use ours.

Closes #2828.
master
safety0ff 2012-01-06 19:33:17 -05:00 committed by cybersphinx
parent 95d09c169b
commit 9cb0afa9b8
41 changed files with 18164 additions and 3 deletions

330
3rdparty/quesoglc/GL/glc.h vendored Normal file
View File

@ -0,0 +1,330 @@
/* QuesoGLC
* A free implementation of the OpenGL Character Renderer (GLC)
* Copyright (c) 2002, 2004-2007, 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
*/
#if !defined(__glc_h_)
#define __glc_h_
/************************************************************************
* Begin system-specific stuff
* from Mesa 3-D graphics library
* Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* __WIN32__ */
#if !defined(__WIN32__) && (defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__))
# define __WIN32__
#endif
#ifdef __WIN32__
# include <windows.h>
#endif
/* GLCAPI, part 1 (use WINGDIAPI, if defined) */
#if defined(__WIN32__) && defined(WINGDIAPI) && !defined(GLCAPI)
# define GLCAPI WINGDIAPI
#endif
/* GLCAPI, part 2 */
#if !defined(GLCAPI)
# if defined(_MSC_VER) /* Microsoft Visual C++ */
# define GLCAPI __declspec(dllimport)
# elif defined(__LCC__) && defined(__WIN32__) /* LCC-Win32 */
# define GLCAPI __stdcall
# elif defined(__GNUC__) && __GNUC__ >= 4
# define GLCAPI extern __attribute__ ((visibility("default")))
# else /* Others (e.g. MinGW, Cygwin, non-win32) */
# define GLCAPI extern
# endif
#endif
/* APIENTRY */
#if !defined(APIENTRY)
# if defined(__WIN32__)
# define APIENTRY __stdcall
# else
# define APIENTRY
# endif
#endif
/* CALLBACK */
#if !defined(CALLBACK)
# if defined(__WIN32__)
# define CALLBACK __stdcall
# else
# define CALLBACK
# endif
#endif
/*
* End system-specific stuff.
************************************************************************/
#if defined __APPLE__ && defined __MACH__
#include <OpenGL/gl.h>
#else
#include <GL/gl.h>
#endif
#if defined(__cplusplus)
extern "C" {
#endif
typedef void GLCchar;
typedef GLint GLCenum;
#if defined(__cplusplus)
typedef GLboolean (CALLBACK *GLCfunc)(GLint);
#else
typedef GLboolean (CALLBACK *GLCfunc)(GLint);
#endif
/*************************************************************/
#define GLC_NONE 0x0000
#define GLC_AUTO_FONT 0x0010
#define GLC_GL_OBJECTS 0x0011
#define GLC_MIPMAP 0x0012
#define GLC_OP_glcUnmappedCode 0x0020
#define GLC_BASELINE 0x0030
#define GLC_BOUNDS 0x0031
#define GLC_PARAMETER_ERROR 0x0040
#define GLC_RESOURCE_ERROR 0x0041
#define GLC_STATE_ERROR 0x0042
#define GLC_CHAR_LIST 0x0050
#define GLC_FACE_LIST 0x0051
#define GLC_FAMILY 0x0060
#define GLC_MASTER_FORMAT 0x0061
#define GLC_VENDOR 0x0062
#define GLC_VERSION 0x0063
#define GLC_CHAR_COUNT 0x0070
#define GLC_FACE_COUNT 0x0071
#define GLC_IS_FIXED_PITCH 0x0072
#define GLC_MAX_MAPPED_CODE 0x0073
#define GLC_MIN_MAPPED_CODE 0x0074
#define GLC_IS_OUTLINE 0x0075
#define GLC_CATALOG_LIST 0x0080
#define GLC_CURRENT_FONT_LIST 0x0090
#define GLC_FONT_LIST 0x0091
#define GLC_LIST_OBJECT_LIST 0x0092
#define GLC_TEXTURE_OBJECT_LIST 0x0093
#define GLC_DATA_POINTER 0x00A0
#define GLC_EXTENSIONS 0x00B0
#define GLC_RELEASE 0x00B1
#define GLC_RESOLUTION 0x00C0
#define GLC_BITMAP_MATRIX 0x00D0
#define GLC_CATALOG_COUNT 0x00E0
#define GLC_CURRENT_FONT_COUNT 0x00E1
#define GLC_FONT_COUNT 0x00E2
#define GLC_LIST_OBJECT_COUNT 0x00E3
#define GLC_MASTER_COUNT 0x00E4
#define GLC_MEASURED_CHAR_COUNT 0x00E5
#define GLC_RENDER_STYLE 0x00E6
#define GLC_REPLACEMENT_CODE 0x00E7
#define GLC_STRING_TYPE 0x00E8
#define GLC_TEXTURE_OBJECT_COUNT 0x00E9
#define GLC_VERSION_MAJOR 0x00EA
#define GLC_VERSION_MINOR 0x00EB
#define GLC_BITMAP 0x0100
#define GLC_LINE 0x0101
#define GLC_TEXTURE 0x0102
#define GLC_TRIANGLE 0x0103
#define GLC_UCS1 0x0110
#define GLC_UCS2 0x0111
#define GLC_UCS4 0x0112
/*************************************************************/
GLCAPI void APIENTRY glcContext (GLint inContext);
GLCAPI void APIENTRY glcDeleteContext (GLint inContext);
GLCAPI GLint APIENTRY glcGenContext (void);
GLCAPI GLint* APIENTRY glcGetAllContexts (void);
GLCAPI GLint APIENTRY glcGetCurrentContext (void);
GLCAPI GLCenum APIENTRY glcGetError (void);
GLCAPI GLboolean APIENTRY glcIsContext (GLint inContext);
GLCAPI void APIENTRY glcCallbackFunc (GLCenum inOpcode, GLCfunc inFunc);
GLCAPI void APIENTRY glcDataPointer (GLvoid *inPointer);
GLCAPI void APIENTRY glcDeleteGLObjects (void);
GLCAPI void APIENTRY glcDisable (GLCenum inAttrib);
GLCAPI void APIENTRY glcEnable (GLCenum inAttrib);
GLCAPI GLCfunc APIENTRY glcGetCallbackFunc (GLCenum inOpcode);
GLCAPI const GLCchar* APIENTRY glcGetListc (GLCenum inAttrib, GLint inIndex);
GLCAPI GLint APIENTRY glcGetListi (GLCenum inAttrib, GLint inIndex);
GLCAPI GLvoid* APIENTRY glcGetPointer (GLCenum inAttrib);
GLCAPI const GLCchar* APIENTRY glcGetc (GLCenum inAttrib);
GLCAPI GLfloat APIENTRY glcGetf (GLCenum inAttrib);
GLCAPI GLfloat* APIENTRY glcGetfv (GLCenum inAttrib, GLfloat *outVec);
GLCAPI GLint APIENTRY glcGeti (GLCenum inAttrib);
GLCAPI GLboolean APIENTRY glcIsEnabled (GLCenum inAttrib);
GLCAPI void APIENTRY glcStringType (GLCenum inStringType);
GLCAPI void APIENTRY glcAppendCatalog (const GLCchar *inCatalog);
GLCAPI const GLCchar* APIENTRY glcGetMasterListc (GLint inMaster,
GLCenum inAttrib,
GLint inIndex);
GLCAPI const GLCchar* APIENTRY glcGetMasterMap (GLint inMaster, GLint inCode);
GLCAPI const GLCchar* APIENTRY glcGetMasterc (GLint inMaster, GLCenum inAttrib);
GLCAPI GLint APIENTRY glcGetMasteri (GLint inMaster, GLCenum inAttrib);
GLCAPI void APIENTRY glcPrependCatalog (const GLCchar *inCatalog);
GLCAPI void APIENTRY glcRemoveCatalog (GLint inIndex);
GLCAPI void APIENTRY glcAppendFont (GLint inFont);
GLCAPI void APIENTRY glcDeleteFont (GLint inFont);
GLCAPI void APIENTRY glcFont (GLint inFont);
GLCAPI GLboolean APIENTRY glcFontFace (GLint inFont, const GLCchar *inFace);
GLCAPI void APIENTRY glcFontMap (GLint inFont, GLint inCode,
const GLCchar *inCharName);
GLCAPI GLint APIENTRY glcGenFontID (void);
GLCAPI const GLCchar* APIENTRY glcGetFontFace (GLint inFont);
GLCAPI const GLCchar* APIENTRY glcGetFontListc (GLint inFont,
GLCenum inAttrib,
GLint inIndex);
GLCAPI const GLCchar* APIENTRY glcGetFontMap (GLint inFont, GLint inCode);
GLCAPI const GLbyte* APIENTRY glcGetFontMasterArray (GLint inFont,
GLboolean inFull,
GLint *outCount);
GLCAPI const GLCchar* APIENTRY glcGetFontc (GLint inFont, GLCenum inAttrib);
GLCAPI GLint APIENTRY glcGetFonti (GLint inFont, GLCenum inAttrib);
GLCAPI GLboolean APIENTRY glcIsFont (GLint inFont);
GLCAPI GLint APIENTRY glcNewFontFromFamily (GLint inFont,
const GLCchar *inFamily);
GLCAPI GLint APIENTRY glcNewFontFromMaster (GLint inFont, GLint inMaster);
GLCAPI void APIENTRY glcLoadIdentity (void);
GLCAPI void APIENTRY glcLoadMatrix (const GLfloat *inMatrix);
GLCAPI void APIENTRY glcMultMatrix (const GLfloat *inMatrix);
GLCAPI void APIENTRY glcRotate (GLfloat inAngle);
GLCAPI void APIENTRY glcScale (GLfloat inX, GLfloat inY);
GLCAPI void APIENTRY glcRenderChar (GLint inCode);
GLCAPI void APIENTRY glcRenderCountedString (GLint inCount,
const GLCchar *inString);
GLCAPI void APIENTRY glcRenderString (const GLCchar *inString);
GLCAPI void APIENTRY glcRenderStyle (GLCenum inStyle);
GLCAPI void APIENTRY glcReplacementCode (GLint inCode);
GLCAPI void APIENTRY glcResolution (GLfloat inVal);
GLCAPI GLfloat* APIENTRY glcGetCharMetric (GLint inCode, GLCenum inMetric,
GLfloat *outVec);
GLCAPI GLfloat* APIENTRY glcGetMaxCharMetric (GLCenum inMetric,
GLfloat *outVec);
GLCAPI GLfloat* APIENTRY glcGetStringCharMetric (GLint inIndex,
GLCenum inMetric,
GLfloat *outVec);
GLCAPI GLfloat* APIENTRY glcGetStringMetric (GLCenum inMetric, GLfloat *outVec);
GLCAPI GLint APIENTRY glcMeasureCountedString (GLboolean inMeasureChars,
GLint inCount,
const GLCchar *inString);
GLCAPI GLint APIENTRY glcMeasureString (GLboolean inMeasureChars,
const GLCchar *inString);
/*************************************************************/
#define GLC_SGI_ufm_typeface_handle 1
#define GLC_UFM_TYPEFACE_HANDLE_SGI 0x8001
#define GLC_UFM_TYPEFACE_HANDLE_COUNT_SGI 0x8003
GLCAPI GLint APIENTRY glcGetMasterListiSGI(GLint inMaster, GLCenum inAttrib,
GLint inIndex);
GLCAPI GLint APIENTRY glcGetFontListiSGI(GLint inFont, GLCenum inAttrib,
GLint inIndex);
#define GLC_SGI_full_name 1
#define GLC_FULL_NAME_SGI 0x8002
#define GLC_QSO_utf8 1
#define GLC_UTF8_QSO 0x8004
#define GLC_QSO_hinting 1
#define GLC_HINTING_QSO 0x8005
#define GLC_QSO_extrude 1
#define GLC_EXTRUDE_QSO 0x8006
#define GLC_QSO_kerning 1
#define GLC_KERNING_QSO 0x8007
#define GLC_QSO_matrix_stack 1
#define GLC_MATRIX_STACK_DEPTH_QSO 0x8008
#define GLC_MAX_MATRIX_STACK_DEPTH_QSO 0x8009
#define GLC_STACK_OVERFLOW_QSO 0x800A
#define GLC_STACK_UNDERFLOW_QSO 0x800B
GLCAPI void APIENTRY glcPushMatrixQSO(void);
GLCAPI void APIENTRY glcPopMatrixQSO(void);
#define GLC_QSO_attrib_stack 1
#define GLC_ENABLE_BIT_QSO 0x00000001
#define GLC_RENDER_BIT_QSO 0x00000002
#define GLC_STRING_BIT_QSO 0x00000004
#define GLC_GL_ATTRIB_BIT_QSO 0x00000008
#define GLC_ALL_ATTRIB_BITS_QSO 0x0000FFFF
#define GLC_ATTRIB_STACK_DEPTH_QSO 0x800C
#define GLC_MAX_ATTRIB_STACK_DEPTH_QSO 0x800D
GLCAPI void APIENTRY glcPushAttribQSO(GLbitfield inMask);
GLCAPI void APIENTRY glcPopAttribQSO(void);
#define GLC_QSO_buffer_object 1
#define GLC_BUFFER_OBJECT_COUNT_QSO 0x800E
#define GLC_BUFFER_OBJECT_LIST_QSO 0x800F
#define GLC_QSO_render_parameter 1
#define GLC_PARAMETRIC_TOLERANCE_QSO 0x8010
GLCAPI void APIENTRY glcRenderParameteriQSO(GLenum inAttrib, GLint inVal);
GLCAPI void APIENTRY glcRenderParameterfQSO(GLenum inAttrib, GLfloat inVal);
#define GLC_QSO_render_pixmap
#define GLC_PIXMAP_QSO 0x8011
#if defined (__cplusplus)
}
#endif
#endif /* defined (__glc_h_) */

50
3rdparty/quesoglc/Makefile.am vendored Normal file
View File

@ -0,0 +1,50 @@
AM_CPPFLAGS = $(FREETYPE_CFLAGS) $(FRIBIDI_CFLAGS) $(FONTCONFIG_CFLAGS) $(WZ_CPPFLAGS) $(OPENGL_CFLAGS) $(GLEW_CFLAGS)
AM_CFLAGS =
AM_CXXFLAGS =
AUTOMAKE_OPTIONS = subdir-objects
WZ_CPPFLAGS += -I`pwd`
WZ_CFLAGS += -I`pwd`
WZ_CXXFLAGS += -I`pwd`
noinst_LIBRARIES = libquesoglc.a
noinst_HEADERS = \
GL/glc.h \
except.h \
internal.h \
oarray.h \
ocharmap.h \
ocontext.h \
ofacedesc.h \
ofont.h \
oglyph.h \
omaster.h \
qglc_config.h \
texture.h
libquesoglc_a_SOURCES = \
database.c \
context.c \
except.c \
font.c \
global.c \
master.c \
measure.c \
misc.c \
oarray.c \
ofacedesc.c \
ofont.c \
oglyph.c \
render.c \
scalable.c \
texture.c \
transform.c \
unicode.c
if MINGW32
libquesoglc_a_SOURCES += win32-ocharmap.c win32-ocontext.c win32-omaster.c
else
libquesoglc_a_SOURCES += ocharmap.c ocontext.c omaster.c
endif

1540
3rdparty/quesoglc/context.c vendored Normal file

File diff suppressed because it is too large Load Diff

586
3rdparty/quesoglc/database.c vendored Normal file
View File

@ -0,0 +1,586 @@
/* This is automagically generated by buildDB.py */
#include "internal.h"
const __GLCdataCodeFromName __glcCodeFromNameArray[] = {
{ 180, "ACUTE ACCENT"},
{ 38, "AMPERSAND"},
{ 39, "APOSTROPHE"},
{ 42, "ASTERISK"},
{ 166, "BROKEN BAR"},
{ 184, "CEDILLA"},
{ 162, "CENT SIGN"},
{ 94, "CIRCUMFLEX ACCENT"},
{ 58, "COLON"},
{ 44, "COMMA"},
{ 64, "COMMERCIAL AT"},
{ 169, "COPYRIGHT SIGN"},
{ 164, "CURRENCY SIGN"},
{ 176, "DEGREE SIGN"},
{ 168, "DIAERESIS"},
{ 56, "DIGIT EIGHT"},
{ 53, "DIGIT FIVE"},
{ 52, "DIGIT FOUR"},
{ 57, "DIGIT NINE"},
{ 49, "DIGIT ONE"},
{ 55, "DIGIT SEVEN"},
{ 54, "DIGIT SIX"},
{ 51, "DIGIT THREE"},
{ 50, "DIGIT TWO"},
{ 48, "DIGIT ZERO"},
{ 247, "DIVISION SIGN"},
{ 36, "DOLLAR SIGN"},
{ 61, "EQUALS SIGN"},
{ 33, "EXCLAMATION MARK"},
{ 170, "FEMININE ORDINAL INDICATOR"},
{ 46, "FULL STOP"},
{ 96, "GRAVE ACCENT"},
{ 62, "GREATER-THAN SIGN"},
{ 45, "HYPHEN-MINUS"},
{ 161, "INVERTED EXCLAMATION MARK"},
{ 191, "INVERTED QUESTION MARK"},
{ 65, "LATIN CAPITAL LETTER A"},
{ 193, "LATIN CAPITAL LETTER A WITH ACUTE"},
{ 258, "LATIN CAPITAL LETTER A WITH BREVE"},
{ 194, "LATIN CAPITAL LETTER A WITH CIRCUMFLEX"},
{ 196, "LATIN CAPITAL LETTER A WITH DIAERESIS"},
{ 192, "LATIN CAPITAL LETTER A WITH GRAVE"},
{ 256, "LATIN CAPITAL LETTER A WITH MACRON"},
{ 260, "LATIN CAPITAL LETTER A WITH OGONEK"},
{ 197, "LATIN CAPITAL LETTER A WITH RING ABOVE"},
{ 195, "LATIN CAPITAL LETTER A WITH TILDE"},
{ 198, "LATIN CAPITAL LETTER AE"},
{ 66, "LATIN CAPITAL LETTER B"},
{ 67, "LATIN CAPITAL LETTER C"},
{ 262, "LATIN CAPITAL LETTER C WITH ACUTE"},
{ 268, "LATIN CAPITAL LETTER C WITH CARON"},
{ 199, "LATIN CAPITAL LETTER C WITH CEDILLA"},
{ 264, "LATIN CAPITAL LETTER C WITH CIRCUMFLEX"},
{ 266, "LATIN CAPITAL LETTER C WITH DOT ABOVE"},
{ 68, "LATIN CAPITAL LETTER D"},
{ 270, "LATIN CAPITAL LETTER D WITH CARON"},
{ 272, "LATIN CAPITAL LETTER D WITH STROKE"},
{ 69, "LATIN CAPITAL LETTER E"},
{ 201, "LATIN CAPITAL LETTER E WITH ACUTE"},
{ 276, "LATIN CAPITAL LETTER E WITH BREVE"},
{ 282, "LATIN CAPITAL LETTER E WITH CARON"},
{ 202, "LATIN CAPITAL LETTER E WITH CIRCUMFLEX"},
{ 203, "LATIN CAPITAL LETTER E WITH DIAERESIS"},
{ 278, "LATIN CAPITAL LETTER E WITH DOT ABOVE"},
{ 200, "LATIN CAPITAL LETTER E WITH GRAVE"},
{ 274, "LATIN CAPITAL LETTER E WITH MACRON"},
{ 280, "LATIN CAPITAL LETTER E WITH OGONEK"},
{ 208, "LATIN CAPITAL LETTER ETH"},
{ 70, "LATIN CAPITAL LETTER F"},
{ 71, "LATIN CAPITAL LETTER G"},
{ 286, "LATIN CAPITAL LETTER G WITH BREVE"},
{ 290, "LATIN CAPITAL LETTER G WITH CEDILLA"},
{ 284, "LATIN CAPITAL LETTER G WITH CIRCUMFLEX"},
{ 288, "LATIN CAPITAL LETTER G WITH DOT ABOVE"},
{ 72, "LATIN CAPITAL LETTER H"},
{ 292, "LATIN CAPITAL LETTER H WITH CIRCUMFLEX"},
{ 294, "LATIN CAPITAL LETTER H WITH STROKE"},
{ 73, "LATIN CAPITAL LETTER I"},
{ 205, "LATIN CAPITAL LETTER I WITH ACUTE"},
{ 300, "LATIN CAPITAL LETTER I WITH BREVE"},
{ 206, "LATIN CAPITAL LETTER I WITH CIRCUMFLEX"},
{ 207, "LATIN CAPITAL LETTER I WITH DIAERESIS"},
{ 304, "LATIN CAPITAL LETTER I WITH DOT ABOVE"},
{ 204, "LATIN CAPITAL LETTER I WITH GRAVE"},
{ 298, "LATIN CAPITAL LETTER I WITH MACRON"},
{ 302, "LATIN CAPITAL LETTER I WITH OGONEK"},
{ 296, "LATIN CAPITAL LETTER I WITH TILDE"},
{ 74, "LATIN CAPITAL LETTER J"},
{ 308, "LATIN CAPITAL LETTER J WITH CIRCUMFLEX"},
{ 75, "LATIN CAPITAL LETTER K"},
{ 310, "LATIN CAPITAL LETTER K WITH CEDILLA"},
{ 76, "LATIN CAPITAL LETTER L"},
{ 313, "LATIN CAPITAL LETTER L WITH ACUTE"},
{ 317, "LATIN CAPITAL LETTER L WITH CARON"},
{ 315, "LATIN CAPITAL LETTER L WITH CEDILLA"},
{ 319, "LATIN CAPITAL LETTER L WITH MIDDLE DOT"},
{ 77, "LATIN CAPITAL LETTER M"},
{ 78, "LATIN CAPITAL LETTER N"},
{ 209, "LATIN CAPITAL LETTER N WITH TILDE"},
{ 79, "LATIN CAPITAL LETTER O"},
{ 211, "LATIN CAPITAL LETTER O WITH ACUTE"},
{ 212, "LATIN CAPITAL LETTER O WITH CIRCUMFLEX"},
{ 214, "LATIN CAPITAL LETTER O WITH DIAERESIS"},
{ 210, "LATIN CAPITAL LETTER O WITH GRAVE"},
{ 216, "LATIN CAPITAL LETTER O WITH STROKE"},
{ 213, "LATIN CAPITAL LETTER O WITH TILDE"},
{ 80, "LATIN CAPITAL LETTER P"},
{ 81, "LATIN CAPITAL LETTER Q"},
{ 82, "LATIN CAPITAL LETTER R"},
{ 83, "LATIN CAPITAL LETTER S"},
{ 84, "LATIN CAPITAL LETTER T"},
{ 222, "LATIN CAPITAL LETTER THORN"},
{ 85, "LATIN CAPITAL LETTER U"},
{ 218, "LATIN CAPITAL LETTER U WITH ACUTE"},
{ 219, "LATIN CAPITAL LETTER U WITH CIRCUMFLEX"},
{ 220, "LATIN CAPITAL LETTER U WITH DIAERESIS"},
{ 217, "LATIN CAPITAL LETTER U WITH GRAVE"},
{ 86, "LATIN CAPITAL LETTER V"},
{ 87, "LATIN CAPITAL LETTER W"},
{ 88, "LATIN CAPITAL LETTER X"},
{ 89, "LATIN CAPITAL LETTER Y"},
{ 221, "LATIN CAPITAL LETTER Y WITH ACUTE"},
{ 90, "LATIN CAPITAL LETTER Z"},
{ 306, "LATIN CAPITAL LIGATURE IJ"},
{ 97, "LATIN SMALL LETTER A"},
{ 225, "LATIN SMALL LETTER A WITH ACUTE"},
{ 259, "LATIN SMALL LETTER A WITH BREVE"},
{ 226, "LATIN SMALL LETTER A WITH CIRCUMFLEX"},
{ 228, "LATIN SMALL LETTER A WITH DIAERESIS"},
{ 224, "LATIN SMALL LETTER A WITH GRAVE"},
{ 257, "LATIN SMALL LETTER A WITH MACRON"},
{ 261, "LATIN SMALL LETTER A WITH OGONEK"},
{ 229, "LATIN SMALL LETTER A WITH RING ABOVE"},
{ 227, "LATIN SMALL LETTER A WITH TILDE"},
{ 230, "LATIN SMALL LETTER AE"},
{ 98, "LATIN SMALL LETTER B"},
{ 99, "LATIN SMALL LETTER C"},
{ 263, "LATIN SMALL LETTER C WITH ACUTE"},
{ 269, "LATIN SMALL LETTER C WITH CARON"},
{ 231, "LATIN SMALL LETTER C WITH CEDILLA"},
{ 265, "LATIN SMALL LETTER C WITH CIRCUMFLEX"},
{ 267, "LATIN SMALL LETTER C WITH DOT ABOVE"},
{ 100, "LATIN SMALL LETTER D"},
{ 271, "LATIN SMALL LETTER D WITH CARON"},
{ 273, "LATIN SMALL LETTER D WITH STROKE"},
{ 305, "LATIN SMALL LETTER DOTLESS I"},
{ 101, "LATIN SMALL LETTER E"},
{ 233, "LATIN SMALL LETTER E WITH ACUTE"},
{ 277, "LATIN SMALL LETTER E WITH BREVE"},
{ 283, "LATIN SMALL LETTER E WITH CARON"},
{ 234, "LATIN SMALL LETTER E WITH CIRCUMFLEX"},
{ 235, "LATIN SMALL LETTER E WITH DIAERESIS"},
{ 279, "LATIN SMALL LETTER E WITH DOT ABOVE"},
{ 232, "LATIN SMALL LETTER E WITH GRAVE"},
{ 275, "LATIN SMALL LETTER E WITH MACRON"},
{ 281, "LATIN SMALL LETTER E WITH OGONEK"},
{ 240, "LATIN SMALL LETTER ETH"},
{ 102, "LATIN SMALL LETTER F"},
{ 103, "LATIN SMALL LETTER G"},
{ 287, "LATIN SMALL LETTER G WITH BREVE"},
{ 291, "LATIN SMALL LETTER G WITH CEDILLA"},
{ 285, "LATIN SMALL LETTER G WITH CIRCUMFLEX"},
{ 289, "LATIN SMALL LETTER G WITH DOT ABOVE"},
{ 104, "LATIN SMALL LETTER H"},
{ 293, "LATIN SMALL LETTER H WITH CIRCUMFLEX"},
{ 295, "LATIN SMALL LETTER H WITH STROKE"},
{ 105, "LATIN SMALL LETTER I"},
{ 237, "LATIN SMALL LETTER I WITH ACUTE"},
{ 301, "LATIN SMALL LETTER I WITH BREVE"},
{ 238, "LATIN SMALL LETTER I WITH CIRCUMFLEX"},
{ 239, "LATIN SMALL LETTER I WITH DIAERESIS"},
{ 236, "LATIN SMALL LETTER I WITH GRAVE"},
{ 299, "LATIN SMALL LETTER I WITH MACRON"},
{ 303, "LATIN SMALL LETTER I WITH OGONEK"},
{ 297, "LATIN SMALL LETTER I WITH TILDE"},
{ 106, "LATIN SMALL LETTER J"},
{ 309, "LATIN SMALL LETTER J WITH CIRCUMFLEX"},
{ 107, "LATIN SMALL LETTER K"},
{ 311, "LATIN SMALL LETTER K WITH CEDILLA"},
{ 312, "LATIN SMALL LETTER KRA"},
{ 108, "LATIN SMALL LETTER L"},
{ 314, "LATIN SMALL LETTER L WITH ACUTE"},
{ 318, "LATIN SMALL LETTER L WITH CARON"},
{ 316, "LATIN SMALL LETTER L WITH CEDILLA"},
{ 320, "LATIN SMALL LETTER L WITH MIDDLE DOT"},
{ 109, "LATIN SMALL LETTER M"},
{ 110, "LATIN SMALL LETTER N"},
{ 241, "LATIN SMALL LETTER N WITH TILDE"},
{ 111, "LATIN SMALL LETTER O"},
{ 243, "LATIN SMALL LETTER O WITH ACUTE"},
{ 244, "LATIN SMALL LETTER O WITH CIRCUMFLEX"},
{ 246, "LATIN SMALL LETTER O WITH DIAERESIS"},
{ 242, "LATIN SMALL LETTER O WITH GRAVE"},
{ 248, "LATIN SMALL LETTER O WITH STROKE"},
{ 245, "LATIN SMALL LETTER O WITH TILDE"},
{ 112, "LATIN SMALL LETTER P"},
{ 113, "LATIN SMALL LETTER Q"},
{ 114, "LATIN SMALL LETTER R"},
{ 115, "LATIN SMALL LETTER S"},
{ 223, "LATIN SMALL LETTER SHARP S"},
{ 116, "LATIN SMALL LETTER T"},
{ 254, "LATIN SMALL LETTER THORN"},
{ 117, "LATIN SMALL LETTER U"},
{ 250, "LATIN SMALL LETTER U WITH ACUTE"},
{ 251, "LATIN SMALL LETTER U WITH CIRCUMFLEX"},
{ 252, "LATIN SMALL LETTER U WITH DIAERESIS"},
{ 249, "LATIN SMALL LETTER U WITH GRAVE"},
{ 118, "LATIN SMALL LETTER V"},
{ 119, "LATIN SMALL LETTER W"},
{ 120, "LATIN SMALL LETTER X"},
{ 121, "LATIN SMALL LETTER Y"},
{ 253, "LATIN SMALL LETTER Y WITH ACUTE"},
{ 255, "LATIN SMALL LETTER Y WITH DIAERESIS"},
{ 122, "LATIN SMALL LETTER Z"},
{ 307, "LATIN SMALL LIGATURE IJ"},
{ 123, "LEFT CURLY BRACKET"},
{ 40, "LEFT PARENTHESIS"},
{ 91, "LEFT SQUARE BRACKET"},
{ 171, "LEFT-POINTING DOUBLE ANGLE QUOTATION MARK"},
{ 60, "LESS-THAN SIGN"},
{ 95, "LOW LINE"},
{ 175, "MACRON"},
{ 186, "MASCULINE ORDINAL INDICATOR"},
{ 181, "MICRO SIGN"},
{ 183, "MIDDLE DOT"},
{ 215, "MULTIPLICATION SIGN"},
{ 160, "NO-BREAK SPACE"},
{ 172, "NOT SIGN"},
{ 35, "NUMBER SIGN"},
{ 37, "PERCENT SIGN"},
{ 182, "PILCROW SIGN"},
{ 43, "PLUS SIGN"},
{ 177, "PLUS-MINUS SIGN"},
{ 163, "POUND SIGN"},
{ 63, "QUESTION MARK"},
{ 34, "QUOTATION MARK"},
{ 174, "REGISTERED SIGN"},
{ 92, "REVERSE SOLIDUS"},
{ 125, "RIGHT CURLY BRACKET"},
{ 41, "RIGHT PARENTHESIS"},
{ 93, "RIGHT SQUARE BRACKET"},
{ 187, "RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK"},
{ 167, "SECTION SIGN"},
{ 59, "SEMICOLON"},
{ 173, "SOFT HYPHEN"},
{ 47, "SOLIDUS"},
{ 32, "SPACE"},
{ 185, "SUPERSCRIPT ONE"},
{ 179, "SUPERSCRIPT THREE"},
{ 178, "SUPERSCRIPT TWO"},
{ 126, "TILDE"},
{ 124, "VERTICAL LINE"},
{ 189, "VULGAR FRACTION ONE HALF"},
{ 188, "VULGAR FRACTION ONE QUARTER"},
{ 190, "VULGAR FRACTION THREE QUARTERS"},
{ 165, "YEN SIGN"},
};
const GLint __glcNameFromCodeArray[] = {
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
246,
28,
235,
228,
26,
229,
1,
2,
216,
239,
3,
231,
9,
33,
30,
245,
24,
19,
23,
22,
17,
16,
21,
20,
15,
18,
8,
243,
219,
27,
32,
234,
10,
36,
47,
48,
54,
57,
68,
69,
74,
77,
87,
89,
91,
96,
97,
99,
106,
107,
108,
109,
110,
112,
117,
118,
119,
120,
122,
217,
237,
240,
7,
220,
31,
124,
135,
136,
142,
146,
157,
158,
163,
166,
175,
177,
180,
185,
186,
188,
195,
196,
197,
198,
200,
202,
207,
208,
209,
210,
213,
215,
251,
238,
250,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
226,
34,
6,
233,
12,
255,
4,
242,
14,
11,
29,
218,
227,
244,
236,
221,
13,
232,
249,
248,
0,
223,
230,
224,
5,
247,
222,
241,
253,
252,
254,
35,
41,
37,
39,
45,
40,
44,
46,
51,
64,
58,
61,
62,
83,
78,
80,
81,
67,
98,
103,
100,
101,
105,
102,
225,
104,
116,
113,
114,
115,
121,
111,
199,
129,
125,
127,
133,
128,
132,
134,
139,
153,
147,
150,
151,
171,
167,
169,
170,
156,
187,
192,
189,
190,
194,
191,
25,
193,
206,
203,
204,
205,
211,
201,
212,
42,
130,
38,
126,
43,
131,
49,
137,
52,
140,
53,
141,
50,
138,
55,
143,
56,
144,
65,
154,
59,
148,
63,
152,
66,
155,
60,
149,
72,
161,
70,
159,
73,
162,
71,
160,
75,
164,
76,
165,
86,
174,
84,
172,
79,
168,
85,
173,
82,
145,
123,
214,
88,
176,
90,
178,
179,
92,
181,
94,
183,
93,
182,
95,
184,
};
const GLint __glcMaxCode = 320;
const GLint __glcCodeFromNameSize = 256;

233
3rdparty/quesoglc/except.c vendored Normal file
View File

@ -0,0 +1,233 @@
/* QuesoGLC
* A free implementation of the OpenGL Character Renderer (GLC)
* Copyright (c) 2002, 2004-2007, 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$ */
/** \file
* defines the functions needed for cleanup stack exception handling (CSEH)
* which concept is described in details at
* http://www.freetype.org/david/reliable-c.html
*/
#include "internal.h"
#include "except.h"
#include <assert.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_LIST_H
/* Unhandled exceptions (when area->exceptionStack.tail == NULL)
* still need to be implemented. Such situations can occur if an exception
* is thrown out of a try/catch block.
*/
typedef struct __GLCcleanupStackNodeRec __GLCcleanupStackNode;
typedef struct __GLCexceptContextRec __GLCexceptContext;
struct __GLCcleanupStackNodeRec {
FT_ListNodeRec node;
void (*destructor) (void *);
void *data;
};
struct __GLCexceptContextRec {
FT_ListNodeRec node;
__glcException exception;
FT_ListRec cleanupStack;
jmp_buf env;
};
/* Create a context for exception handling */
jmp_buf* __glcExceptionCreateContext(void)
{
__GLCthreadArea *area = NULL;
__GLCexceptContext *xContext = NULL;
area = GLC_GET_THREAD_AREA();
assert(area);
xContext = (__GLCexceptContext*)malloc(sizeof(__GLCexceptContext));
if (!xContext) {
area->failedTry = GLC_MEMORY_EXC;
return NULL;
}
xContext->exception = GLC_NO_EXC;
xContext->cleanupStack.head = NULL;
xContext->cleanupStack.tail = NULL;
FT_List_Add(&area->exceptionStack, (FT_ListNode)xContext);
return &xContext->env;
}
/* Destroy the last context for exception handling */
void __glcExceptionReleaseContext(void)
{
__GLCthreadArea *area = NULL;
__GLCexceptContext *xContext = NULL;
area = GLC_GET_THREAD_AREA();
assert(area);
xContext = (__GLCexceptContext*)area->exceptionStack.tail;
assert(xContext);
/* The cleanup stack must be empty */
assert(!xContext->cleanupStack.head);
assert(!xContext->cleanupStack.tail);
FT_List_Remove(&area->exceptionStack, (FT_ListNode)xContext);
free(xContext);
}
/* Keep track of data to be destroyed in case of */
void __glcExceptionPush(void (*destructor)(void*), void *data)
{
__GLCthreadArea *area = NULL;
__GLCexceptContext *xContext = NULL;
__GLCcleanupStackNode *stackNode = NULL;
area = GLC_GET_THREAD_AREA();
assert(area);
xContext = (__GLCexceptContext*)area->exceptionStack.tail;
assert(xContext);
stackNode = (__GLCcleanupStackNode*) malloc(sizeof(__GLCcleanupStackNode));
if (!stackNode) {
destructor(data);
THROW(GLC_MEMORY_EXC);
}
stackNode->destructor = destructor;
stackNode->data = data;
FT_List_Add(&xContext->cleanupStack, (FT_ListNode)stackNode);
}
/* Remove the last entry of the cleanup stack, eventually destroying the
* corresponding data if destroy != 0
*/
void __glcExceptionPop(int destroy)
{
__GLCthreadArea *area = NULL;
__GLCexceptContext *xContext = NULL;
__GLCcleanupStackNode *stackNode = NULL;
area = GLC_GET_THREAD_AREA();
assert(area);
xContext = (__GLCexceptContext*)area->exceptionStack.tail;
assert(xContext);
stackNode = (__GLCcleanupStackNode*)xContext->cleanupStack.tail;
assert(stackNode);
if (destroy) {
assert(stackNode->destructor);
assert(stackNode->data);
stackNode->destructor(stackNode->data);
}
FT_List_Remove(&xContext->cleanupStack, (FT_ListNode)stackNode);
free(stackNode);
}
/* Empty the cleanup stack and destroy the corresponding data if
* destroy != 0
*/
void __glcExceptionUnwind(int destroy)
{
__GLCthreadArea *area = NULL;
__GLCexceptContext *xContext = NULL;
FT_ListNode next = NULL;
__GLCcleanupStackNode *stackNode = NULL;
area = GLC_GET_THREAD_AREA();
assert(area);
xContext = (__GLCexceptContext*)area->exceptionStack.tail;
assert(xContext);
stackNode = (__GLCcleanupStackNode*)xContext->cleanupStack.head;
while (stackNode) {
next = stackNode->node.next;
if (destroy) {
assert(stackNode->destructor);
assert(stackNode->data);
stackNode->destructor(stackNode->data);
}
free(stackNode);
stackNode = (__GLCcleanupStackNode*)next;
}
xContext->cleanupStack.head = NULL;
xContext->cleanupStack.tail = NULL;
}
/* Throw an exception */
jmp_buf* __glcExceptionThrow(__glcException exception)
{
__GLCthreadArea *area = NULL;
__GLCexceptContext *xContext = NULL;
area = GLC_GET_THREAD_AREA();
assert(area);
xContext = (__GLCexceptContext*)area->exceptionStack.tail;
assert(xContext);
xContext->exception = exception;
return &xContext->env;
}
/* Rethrow an exception that has already been catched */
__glcException __glcExceptionCatch(void)
{
__GLCthreadArea *area = NULL;
__GLCexceptContext *xContext = NULL;
area = GLC_GET_THREAD_AREA();
assert(area);
if (area->failedTry) {
__glcException exc = area->failedTry;
area->failedTry = GLC_NO_EXC;
return exc;
}
xContext = (__GLCexceptContext*)area->exceptionStack.tail;
assert(xContext);
return xContext->exception;
}

91
3rdparty/quesoglc/except.h vendored Normal file
View File

@ -0,0 +1,91 @@
/* QuesoGLC
* A free implementation of the OpenGL Character Renderer (GLC)
* Copyright (c) 2002, 2004-2007, 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$ */
/** \file
* header of the functions needed for cleanup stack exception handling (CSEH)
*/
#ifndef __glc_except_h
#define __glc_except_h
#include <setjmp.h>
#ifdef __cpluplus
extern "C" {
#endif
typedef unsigned int __glcException;
#define GLC_NO_EXC (__glcException)0
#define GLC_MEMORY_EXC (__glcException)1
jmp_buf* __glcExceptionCreateContext(void);
void __glcExceptionReleaseContext(void);
void __glcExceptionPush(void (*destructor)(void*), void *data);
void __glcExceptionPop(int destroy);
void __glcExceptionUnwind(int destroy);
jmp_buf* __glcExceptionThrow(__glcException exception);
__glcException __glcExceptionCatch(void);
#define TRY \
do { \
jmp_buf* __glcEnv = __glcExceptionCreateContext(); \
if (__glcEnv && (setjmp(*__glcEnv) == 0)) {
#define CATCH(__e__) \
__glcExceptionUnwind(0); \
} \
else { \
__e__ = __glcExceptionCatch();
#define END_CATCH \
} \
__glcExceptionReleaseContext(); \
} while (0);
#define THROW(__e__) \
do { \
jmp_buf* __glcEnv; \
__glcExceptionUnwind(1); \
__glcEnv = __glcExceptionThrow(__e__); \
longjmp(*__glcEnv, 1); \
} while (0);
#define RETHROW(__e__) \
do { \
jmp_buf* __glcEnv; \
__glcExceptionReleaseContext(); \
__glcExceptionUnwind(1); \
__glcEnv = __glcExceptionThrow(__e__); \
longjmp(*__glcEnv, 1); \
} while (0);
#define RETURN(__value__) \
do { \
__glcExceptionUnwind(0); \
__glcExceptionReleaseContext(); \
return __value__; \
} while(0);
#ifdef __cplusplus
}
#endif
#endif

1119
3rdparty/quesoglc/font.c vendored Normal file

File diff suppressed because it is too large Load Diff

707
3rdparty/quesoglc/global.c vendored Normal file
View File

@ -0,0 +1,707 @@
/* 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$ */
/** \file
* defines the so-called "Global commands" described in chapter 3.4 of the
* GLC specs.
*/
/** \defgroup global Global Commands
* Commands to create, manage and destroy GLC contexts.
*
* Those commands do not use GLC context state variables and can therefore be
* executed successfully if the issuing thread has no current GLC context.
*
* Each GLC context has a nonzero ID of type \b GLint. When a client is linked
* with a GLC library, the library maintains a list of IDs that contains one
* entry for each of the client's GLC contexts. The list is initially empty.
*
* Each client thread has a private GLC context ID variable that always
* contains either the value zero, indicating that the thread has no current
* GLC context, or the ID of the thread's current GLC context. The initial
* value is zero.
*
* When the ID of a GLC context is stored in the GLC context ID variable of a
* client thread, the context is said to be current to the thread. It is not
* possible for a GLC context to be current simultaneously to multiple
* threads. With the exception of the per-thread GLC error code and context ID
* variables, all of the GLC state variables that are used during the
* execution of a GLC command are stored in the issuing thread's current GLC
* context. To make a context current, call glcContext().
*
* When a client thread issues a GLC command, the thread's current GLC context
* executes the command.
*
* Note that the results of issuing a GL command when there is no current GL
* context are undefined. Because GLC issues GL commands, you must create a GL
* context and make it current before calling GLC.
*
* All other GLC commands raise \b GLC_STATE_ERROR if the issuing thread has
* no current GLC context.
*/
#include "internal.h"
#include <stdlib.h>
#ifdef __GNUC__
__attribute__((constructor)) void init(void);
__attribute__((destructor)) void fini(void);
#else
void _init(void);
void _fini(void);
#endif
/* Since the common area can be accessed by any thread, this function should
* be called before any access (read or write) to the common area. Otherwise
* race conditions can occur. This function must also be used whenever we call
* a function which is not reentrant (it is the case for some Fontconfig
* entries).
* __glcLock/__glcUnlock can be nested : they keep track of the number of
* time they have been called and the mutex will be released as soon as
* __glcUnlock() will be called as many time as __glcLock() was.
*/
void __glcLock(void)
{
__GLCthreadArea *area = NULL;
area = GLC_GET_THREAD_AREA();
assert(area);
if (!area->lockState)
#ifdef __WIN32__
EnterCriticalSection(&__glcCommonArea.section);
#else
pthread_mutex_lock(&__glcCommonArea.mutex);
#endif
area->lockState++;
}
/* Unlock the mutex in order to allow other threads to make accesses to the
* common area.
* See also the note on nested calls in __glcLock's description.
*/
void __glcUnlock(void)
{
__GLCthreadArea *area = NULL;
area = GLC_GET_THREAD_AREA();
assert(area);
assert(area->lockState);
area->lockState--;
if (!area->lockState)
#ifdef __WIN32__
LeaveCriticalSection(&__glcCommonArea.section);
#else
pthread_mutex_unlock(&__glcCommonArea.mutex);
#endif
}
#if !defined(HAVE_TLS) && !defined(__WIN32__)
/* This function is called each time a pthread is cancelled or exits in order
* to free its specific area
*/
static void __glcFreeThreadArea(void *keyValue)
{
__GLCthreadArea *area = (__GLCthreadArea*)keyValue;
__GLCcontext *ctx = NULL;
if (area) {
/* Release the context which is current to the thread, if any */
ctx = area->currentContext;
if (ctx)
ctx->isCurrent = GL_FALSE;
free(area); /* DO NOT use __glcFree() !!! */
}
}
#endif /* !HAVE_TLS && !__WIN32__ */
/* This function is called when QuesoGLC is no longer needed.
*/
#ifdef __GNUC__
__attribute__((destructor)) void fini(void)
#else
void _fini(void)
#endif
{
FT_ListNode node = NULL;
#if 0
void *key = NULL;
#endif
__glcLock();
/* destroy remaining contexts */
node = __glcCommonArea.contextList.head;
while (node) {
FT_ListNode next = node->next;
__glcContextDestroy((__GLCcontext*)node);
node = next;
}
#if FC_MINOR > 2 && defined(DEBUGMODE)
FcFini();
#endif
__glcUnlock();
#ifdef __WIN32__
DeleteCriticalSection(&__glcCommonArea.section);
#else
pthread_mutex_destroy(&__glcCommonArea.mutex);
#endif
#if 0
/* Destroy the thread local storage */
key = pthread_getspecific(__glcCommonArea.threadKey);
if (key)
__glcFreeThreadArea(key);
pthread_key_delete(__glcCommonArea.threadKey);
#endif
}
/* Routines for memory management of FreeType
* The memory manager of our FreeType library class uses the same memory
* allocation functions than QuesoGLC
*/
static void* __glcAllocFunc(FT_Memory GLC_UNUSED_ARG(inMemory), long inSize)
{
return malloc(inSize);
}
static void __glcFreeFunc(FT_Memory GLC_UNUSED_ARG(inMemory), void *inBlock)
{
free(inBlock);
}
static void* __glcReallocFunc(FT_Memory GLC_UNUSED_ARG(inMemory),
long GLC_UNUSED_ARG(inCurSize),
long inNewSize, void* inBlock)
{
return realloc(inBlock, inNewSize);
}
/* This function is called before any function of QuesoGLC
* is used. It reserves memory and initialiazes the library, hence the name.
*/
#ifdef __GNUC__
__attribute__((constructor)) void init(void)
#else
void _init(void)
#endif
{
#if !defined(__WIN32__) && !defined(HAVE_TLS)
/* A temporary variable is used to store the PTHREAD_ONCE_INIT value because
* some platforms (namely Mac OSX) define PTHREAD_ONCE_INIT as a structure
* initialization "{.., ..}" which is not allowed to be used by C99 anywhere
* but at variables declaration.
*/
const pthread_once_t onceInit = PTHREAD_ONCE_INIT;
#endif
/* Initialize fontconfig */
if (!FcInit())
goto FatalError;
__glcCommonArea.versionMajor = 0;
__glcCommonArea.versionMinor = 2;
/* Create the thread-local storage for GLC errors */
#ifdef __WIN32__
__glcCommonArea.threadKey = TlsAlloc();
if (__glcCommonArea.threadKey == 0xffffffff)
goto FatalError;
__glcCommonArea.__glcInitThreadOnce = 0;
#elif !defined(HAVE_TLS)
if (pthread_key_create(&__glcCommonArea.threadKey, __glcFreeThreadArea))
goto FatalError;
/* Now we can initialize our actual once_control variable by copying the value
* of the temporary variable onceInit.
*/
__glcCommonArea.__glcInitThreadOnce = onceInit;
#endif
__glcCommonArea.memoryManager.user = NULL;
__glcCommonArea.memoryManager.alloc = __glcAllocFunc;
__glcCommonArea.memoryManager.free = __glcFreeFunc;
__glcCommonArea.memoryManager.realloc = __glcReallocFunc;
/* Initialize the list of context states */
__glcCommonArea.contextList.head = NULL;
__glcCommonArea.contextList.tail = NULL;
/* Initialize the mutex for access to the contextList array */
#ifdef __WIN32__
InitializeCriticalSection(&__glcCommonArea.section);
#else
if (pthread_mutex_init(&__glcCommonArea.mutex, NULL))
goto FatalError;
#endif
return;
FatalError:
__glcRaiseError(GLC_RESOURCE_ERROR);
/* Is there a better thing to do than that ? */
perror("GLC Fatal Error");
exit(-1);
}
#if defined __WIN32__ && !defined __GNUC__
BOOL WINAPI DllMain(HANDLE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
{
switch(dwReason) {
case DLL_PROCESS_ATTACH:
_init();
return TRUE;
case DLL_PROCESS_DETACH:
_fini();
return TRUE;
}
return TRUE;
}
#endif
/* Get the context state corresponding to a given context ID */
static __GLCcontext* __glcGetContext(const GLint inContext)
{
FT_ListNode node = NULL;
__glcLock();
for (node = __glcCommonArea.contextList.head; node; node = node->next)
if (((__GLCcontext*)node)->id == inContext) break;
__glcUnlock();
return (__GLCcontext*)node;
}
/** \ingroup global
* This command checks whether \e inContext is the ID of one of the client's
* GLC context and returns \b GLC_TRUE if and only if it is the case.
* \param inContext The context ID to be tested
* \return \b GL_TRUE if \e inContext is the ID of a GLC context,
* \b GL_FALSE otherwise
* \sa glcDeleteContext()
* \sa glcGenContext()
* \sa glcGetAllContexts()
* \sa glcContext()
*/
GLboolean APIENTRY glcIsContext(GLint inContext)
{
GLC_INIT_THREAD();
return (__glcGetContext(inContext) ? GL_TRUE : GL_FALSE);
}
/** \ingroup global
* Returns the value of the issuing thread's current GLC context ID variable
* \return The context ID of the current thread
* \sa glcContext()
* \sa glcDeleteContext()
* \sa glcGenContext()
* \sa glcGetAllContexts()
* \sa glcIsContext()
*/
GLint APIENTRY glcGetCurrentContext(void)
{
__GLCcontext *ctx = NULL;
GLC_INIT_THREAD();
ctx = GLC_GET_CURRENT_CONTEXT();
if (!ctx)
return 0;
else
return ctx->id;
}
/** \ingroup global
* Marks for deletion the GLC context identified by \e inContext. If the
* marked context is not current to any client thread, the command deletes
* the marked context immediatly. Otherwise, the marked context will be
* deleted during the execution of the next glcContext() command that causes
* it not to be current to any client thread.
*
* \note glcDeleteContext() does not destroy the GL objects associated with
* the context \e inContext. Indeed for performance reasons, GLC does not keep
* track of the GL context that contains the GL objects associated with the
* the GLC context that is destroyed. Even if GLC would keep track of the GL
* context, it could lead GLC to temporarily change the GL context, delete the
* GL objects, then restore the correct GL context. In order not to adversely
* impact the performance of most of programs, it is the responsability of the
* user to call glcDeleteGLObjects() on a GLC context that is intended to be
* destroyed.
*
* The command raises \b GLC_PARAMETER_ERROR if \e inContext is not the ID of
* one of the client's GLC contexts.
* \param inContext The ID of the context to be deleted
* \sa glcGetAllContexts()
* \sa glcIsContext()
* \sa glcContext()
* \sa glcGetCurrentContext()
*/
void APIENTRY glcDeleteContext(GLint inContext)
{
__GLCcontext *ctx = NULL;
GLC_INIT_THREAD();
/* Lock the "Common Area" in order to prevent race conditions. Indeed, we
* must prevent other threads to make current the context that we are
* destroying.
*/
__glcLock();
/* verify if the context exists */
ctx = __glcGetContext(inContext);
if (!ctx) {
__glcRaiseError(GLC_PARAMETER_ERROR);
__glcUnlock();
return;
}
if (ctx->isCurrent)
/* The context is current to a thread : just mark for deletion */
ctx->pendingDelete = GL_TRUE;
else {
/* Remove the context from the context list then destroy it */
FT_List_Remove(&__glcCommonArea.contextList, (FT_ListNode)ctx);
ctx->isInGlobalCommand = GL_TRUE;
__glcContextDestroy(ctx);
}
__glcUnlock();
}
/** \ingroup global
* Assigns the value \e inContext to the issuing thread's current GLC context
* ID variable. If another context is already current to the thread, no error
* is generated but the context is released and the context identified by
* \e inContext is made current to the thread.
*
* Call \e glcContext with \e inContext set to zero to release a thread's
* current context.
*
* When a GLCcontext is made current to a thread, GLC issues the commands
* \code
* glGetString(GL_VERSION);
* glGetString(GL_EXTENSIONS);
* \endcode
* and stores the returned strings. If there is no GL context current to the
* thread, the result of the above GL commands is undefined and so is the
* result of glcContext().
*
* The command raises \b GLC_PARAMETER_ERROR if \e inContext is not zero
* and is not the ID of one of the client's GLC contexts. \n
* The command raises \b GLC_STATE_ERROR if \e inContext is the ID of a GLC
* context that is current to a thread other than the issuing thread. \n
* The command raises \b GLC_STATE_ERROR if the issuing thread is executing
* a callback function that has been called from GLC.
* \param inContext The ID of the context to be made current
* \sa glcGetCurrentContext()
* \sa glcDeleteContext()
* \sa glcGenContext()
* \sa glcGetAllContexts()
* \sa glcIsContext()
*/
void APIENTRY glcContext(GLint inContext)
{
__GLCcontext *currentContext = NULL;
__GLCcontext *ctx = NULL;
__GLCthreadArea *area = NULL;
GLC_INIT_THREAD();
if (inContext < 0) {
__glcRaiseError(GLC_PARAMETER_ERROR);
return;
}
area = GLC_GET_THREAD_AREA();
assert(area);
/* Lock the "Common Area" in order to prevent race conditions */
__glcLock();
if (inContext) {
/* verify that the context exists */
ctx = __glcGetContext(inContext);
if (!ctx) {
__glcRaiseError(GLC_PARAMETER_ERROR);
__glcUnlock();
return;
}
/* Get the current context of the issuing thread */
currentContext = area->currentContext;
/* Check if the issuing thread is executing a callback
* function that has been called from GLC
*/
if (currentContext) {
if (currentContext->isInCallbackFunc) {
__glcRaiseError(GLC_STATE_ERROR);
__glcUnlock();
return;
}
}
/* Is the context already current to a thread ? */
if (ctx->isCurrent) {
/* If the context is current to another thread => ERROR ! */
if (ctx != currentContext)
__glcRaiseError(GLC_STATE_ERROR);
/* If we get there, this means that the context 'inContext'
* is already current to one thread (whether it is the issuing thread
* or not) : there is nothing else to be done.
*/
__glcUnlock();
return;
}
/* Release old current context if any */
if (currentContext)
currentContext->isCurrent = GL_FALSE;
/* Make the context current to the thread */
area->currentContext = ctx;
ctx->isCurrent = GL_TRUE;
}
else {
/* inContext is null, the current thread must release its context if any */
/* Gets the current context state */
currentContext = area->currentContext;
if (currentContext) {
/* Deassociate the context from the issuing thread */
area->currentContext = NULL;
/* Release the context */
currentContext->isCurrent = GL_FALSE;
}
}
/* Execute pending deletion if any. Here, the variable name 'currentContext'
* is not appropriate any more : 'currentContext' used to be the current
* context but it has either been replaced by another one or it has been
* released.
*/
if (currentContext) {
if (currentContext->pendingDelete) {
assert(!currentContext->isCurrent);
FT_List_Remove(&__glcCommonArea.contextList, (FT_ListNode)currentContext);
currentContext->isInGlobalCommand = GL_TRUE;
__glcContextDestroy(currentContext);
}
}
__glcUnlock();
/* If the issuing thread has released its context then there is no point to
* check for OpenGL extensions.
*/
if (!inContext)
return;
/* During its initialization, GLEW calls glGetString(GL_VERSION) and
* glGetString(GL_EXTENSIONS) so, not only glewInit() allows to determine the
* available extensions, but it also allows to be conformant with GLC specs
* which require to issue those GL commands.
*
* Notice however that not all OpenGL implementations return a result if the
* function glGetString() is called while no GL context is bound to the
* current thread. Since this behaviour is not required by the GL specs, such
* calls may just fail or lead to weird results or even crash the app (on
* Mac OSX). It is the user's responsibility to make sure that it does not
* happen since the GLC specs state clearly that :
* 1. glGetString() is called by glcContext()
* 2. the behaviour of GLC is undefined if no GL context is current while
* issuing GL commands.
*/
if (glewInit() != GLEW_OK)
__glcRaiseError(GLC_RESOURCE_ERROR);
}
/** \ingroup global
* Generates a new GLC context and returns its ID.
* \return The ID of the new context
* \sa glcGetAllContexts()
* \sa glcIsContext()
* \sa glcContext()
* \sa glcGetCurrentContext()
*/
GLint APIENTRY glcGenContext(void)
{
int newContext = 0;
__GLCcontext *ctx = NULL;
FT_ListNode node = NULL;
GLC_INIT_THREAD();
/* Create a new context */
ctx = __glcContextCreate(0);
if (!ctx)
return 0;
/* Lock the "Common Area" in order to prevent race conditions */
__glcLock();
/* Search for the first context ID that is unused */
if (__glcCommonArea.contextList.tail)
newContext = ((__GLCcontext*)__glcCommonArea.contextList.tail)->id;
ctx->id = newContext + 1;
node = (FT_ListNode)ctx;
node->data = ctx;
FT_List_Add(&__glcCommonArea.contextList, node);
__glcUnlock();
return ctx->id;
}
/** \ingroup global
* Returns a zero terminated array of GLC context IDs that contains one entry
* for each of the client's GLC contexts. GLC uses the ISO C library command
* \c malloc to allocate the array. The client should use the ISO C library
* command \c free to deallocate the array when it is no longer needed.
* \return The pointer to the array of context IDs.
* \sa glcContext()
* \sa glcDeleteContext()
* \sa glcGenContext()
* \sa glcGetCurrentContext()
* \sa glcIsContext()
*/
GLint* APIENTRY glcGetAllContexts(void)
{
int count = 0;
GLint* contextArray = NULL;
FT_ListNode node = NULL;
GLC_INIT_THREAD();
/* Count the number of existing contexts (whether they are current to a
* thread or not).
*/
__glcLock();
for (node = __glcCommonArea.contextList.head, count = 0; node;
node = node->next, count++);
/* Allocate memory to store the array (including the zero termination value)*/
contextArray = (GLint *)__glcMalloc(sizeof(GLint) * (count+1));
if (!contextArray) {
__glcRaiseError(GLC_RESOURCE_ERROR);
__glcUnlock();
return NULL;
}
/* Array must be null-terminated */
contextArray[count] = 0;
/* Copy the context IDs to the array */
for (node = __glcCommonArea.contextList.tail; node; node = node->prev)
contextArray[--count] = ((__GLCcontext*)node)->id;
__glcUnlock();
return contextArray;
}
/** \ingroup global
* Retrieves the value of the issuing thread's GLC error code variable,
* assigns the value \b GLC_NONE to that variable, and returns the retrieved
* value.
* \note In contrast to the GL function \c glGetError, \e glcGetError only
* returns one error, not a list of errors.
* \return An error code from the table below : \n\n
* <center>
* <table>
* <caption>Error codes</caption>
* <tr>
* <td>Name</td> <td>Enumerant</td>
* </tr>
* <tr>
* <td><b>GLC_NONE</b></td> <td>0x0000</td>
* </tr>
* <tr>
* <td><b>GLC_PARAMETER_ERROR</b></td> <td>0x0040</td>
* </tr>
* <tr>
* <td><b>GLC_RESOURCE_ERROR</b></td> <td>0x0041</td>
* </tr>
* <tr>
* <td><b>GLC_STATE_ERROR</b></td> <td>0x0042</td>
* </tr>
* </table>
* </center>
*/
GLCenum APIENTRY glcGetError(void)
{
GLCenum error = GLC_NONE;
__GLCthreadArea * area = NULL;
GLC_INIT_THREAD();
area = GLC_GET_THREAD_AREA();
assert(area);
error = area->errorState;
__glcRaiseError(GLC_NONE);
return error;
}

386
3rdparty/quesoglc/internal.h vendored Normal file
View File

@ -0,0 +1,386 @@
/* 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$ */
/** \file
* header of all private functions that are used throughout the library.
*/
#ifndef __glc_internal_h
#define __glc_internal_h
#include <stdlib.h>
#if !defined(DEBUGMODE) && !defined(NDEBUG)
#define NDEBUG
#endif
#include <assert.h>
#ifdef HAVE_LIBGLEW
#include <GL/glew.h>
#else
#include "GL/glew.h"
#endif
#define GLCAPI GLEWAPI
#include "GL/glc.h"
#include "qglc_config.h"
#include <ft2build.h>
#include FT_FREETYPE_H
#if defined(HAVE_FT_CACHE) && defined(FT_CACHE_H)
#define GLC_FT_CACHE
#endif
#define GLCchar8 FcChar8
#define GLCchar16 FcChar16
#define GLCchar32 FcChar32
#define GLCuint FT_UInt
#define GLClong FT_Long
#define GLCulong FT_ULong
#include "ofont.h"
#define GLC_OUT_OF_RANGE_LEN 11
#define GLC_EPSILON 1E-6
#define GLC_POINT_SIZE 128
#if defined(__GNUC__)
# define GLC_UNUSED_ARG(_arg) GLC_UNUSED_ ## _arg __attribute__((unused))
#elif defined(__LCLINT__)
# define GLC_UNUSED_ARG(_arg) /*@unused@*/ GLC_UNUSED_ ## _arg
#else
# define GLC_UNUSED_ARG(_arg) GLC_UNUSED_ ## _arg
#endif
/* Definition of the GLC_INIT_THREAD macro : it is some sort of an equivalent to
* XInitThreads(). It allows to get rid of pthread_get_specific()/TlsGetValue()
* when only one thread is used and to fallback to the usual thread management
* if more than one thread is used.
* If Thread Local Storage is used the macro does nothing.
*/
#ifdef __WIN32__
# define GLC_INIT_THREAD() \
if (!InterlockedCompareExchange(&__glcCommonArea.__glcInitThreadOnce, 1, 0)) \
__glcInitThread();
#elif !defined(HAVE_TLS)
# define GLC_INIT_THREAD() \
pthread_once(&__glcCommonArea.__glcInitThreadOnce, __glcInitThread);
#else
#define GLC_INIT_THREAD()
#endif
/* Definition of the GLC_GET_THREAD_AREA macro */
#ifdef __WIN32__
# define GLC_GET_THREAD_AREA() \
(((__glcCommonArea.threadID == GetCurrentThreadId()) && __glcThreadArea) ? \
__glcThreadArea : __glcGetThreadArea())
#elif !defined(HAVE_TLS)
# define GLC_GET_THREAD_AREA() \
((pthread_equal(__glcCommonArea.threadID, pthread_self()) && __glcThreadArea) ? \
__glcThreadArea : __glcGetThreadArea())
#else
# define GLC_GET_THREAD_AREA() &__glcTlsThreadArea
#endif
/* Definition of the GLC_GET_CURRENT_CONTEXT macro */
#ifdef __WIN32__
# define GLC_GET_CURRENT_CONTEXT() \
(((__glcCommonArea.threadID == GetCurrentThreadId()) && __glcThreadArea) ? \
__glcThreadArea->currentContext : __glcGetCurrent())
#elif !defined(HAVE_TLS)
# define GLC_GET_CURRENT_CONTEXT() \
((pthread_equal(__glcCommonArea.threadID, pthread_self()) && __glcThreadArea) ? \
__glcThreadArea->currentContext : __glcGetCurrent())
#else
#define GLC_GET_CURRENT_CONTEXT() __glcTlsThreadArea.currentContext
#endif
/* ceil() and floor() macros for 26.6 fixed integers */
#define GLC_CEIL_26_6(x) (((x) < 0) ? ((x) & -64) : ((x) + 63) & -64)
#define GLC_FLOOR_26_6(x) (((x) < 0) ? (((x) - 63) & -64) : ((x) & -64))
typedef struct __GLCdataCodeFromNameRec __GLCdataCodeFromName;
typedef struct __GLCcharacterRec __GLCcharacter;
struct __GLCrendererDataRec {
GLfloat vector[8]; /* Current coordinates */
GLfloat tolerance; /* Chordal tolerance */
__GLCarray* vertexArray; /* Array of vertices */
__GLCarray* controlPoints; /* Array of control points */
__GLCarray* endContour; /* Array of contour limits */
__GLCarray* vertexIndices; /* Array of vertex indices */
__GLCarray* geomBatches; /* Array of geometric batches */
GLfloat* transformMatrix; /* Transformation matrix from the
object space to the viewport */
GLfloat halfWidth;
GLfloat halfHeight;
};
struct __GLCdataCodeFromNameRec {
GLint code;
const char* name;
};
struct __GLCgeomBatchRec {
GLenum mode;
GLint length;
GLuint start;
GLuint end;
};
struct __GLCcharacterRec {
GLint code;
__GLCfont* font;
__GLCglyph* glyph;
GLfloat advance[2];
};
/* Those functions are used to protect against race conditions whenever we try
* to access the common area or functions which are not multi-threaded.
*/
void __glcLock(void);
void __glcUnlock(void);
/* Callback function type that is called by __glcProcessChar().
* It allows to unify the character processing before the rendering or the
* measurement of a character : __glcProcessChar() is called first (see below)
* then the callback function of type __glcProcessCharFunc is called by
* __glcProcessChar(). Two functions are defined according to this type :
* __glcRenderChar() for rendering and __glcGetCharMetric() for measurement.
*/
typedef void* (*__glcProcessCharFunc)(const GLint inCode,
const GLint inPrevCode,
const GLboolean inIsRTL,
const __GLCfont* inFont,
__GLCcontext* inContext,
const void* inProcessCharData,
const GLboolean inMultipleChars);
/* Process the character in order to find a font that maps the code and to
* render the corresponding glyph. Replacement code or the '\<hexcode>'
* character sequence is issued if necessary.
* 'inCode' must be given in UCS-4 format
*/
extern void* __glcProcessChar(__GLCcontext *inContext, const GLint inCode,
__GLCcharacter* inPrevCode,
const GLboolean inIsRTL,
const __glcProcessCharFunc inProcessCharFunc,
const void* inProcessCharData);
/* Render scalable characters using either the GLC_LINE style or the
* GLC_TRIANGLE style
*/
extern void __glcRenderCharScalable(const __GLCfont* inFont,
const __GLCcontext* inContext,
GLfloat* inTransformMatrix,
const GLfloat inScaleX,
const GLfloat inScaleY,
__GLCglyph* inGlyph);
/* QuesoGLC own allocation and memory management routines */
#ifdef DEBUGMODE
extern void* __glcMalloc(size_t size);
extern void __glcFree(void* ptr);
extern void* __glcRealloc(void* ptr, size_t size);
#else
static inline void* __glcMalloc(size_t size)
{
return malloc(size);
}
static inline void __glcFree(void *ptr)
{
free(ptr);
}
static inline void* __glcRealloc(void *ptr, size_t size)
{
return realloc(ptr, size);
}
#endif
/* Arrays that contain the Unicode name of characters */
extern const __GLCdataCodeFromName __glcCodeFromNameArray[];
extern const GLint __glcNameFromCodeArray[];
extern const GLint __glcMaxCode;
extern const GLint __glcCodeFromNameSize;
/* Find a Unicode name from its code */
extern const GLCchar8* __glcNameFromCode(const GLint code);
/* Find a Unicode code from its name */
extern GLint __glcCodeFromName(const GLCchar8* name);
/* Duplicate a string and convert if from any Unicode format to UTF-8 format */
extern GLCchar8* __glcConvertToUtf8(const GLCchar* inString,
const GLint inStringType);
/* Duplicate a string to the context buffer and convert it from UTF-8 format to
* any Unicode format.
*/
extern GLCchar* __glcConvertFromUtf8ToBuffer(__GLCcontext* This,
const GLCchar8* inString);
/* Duplicate a counted string to the context buffer and convert it from any
* Unicode format to UTF-8 format.
*/
extern GLCchar8* __glcConvertCountedStringToUtf8(const GLint inCount,
const GLCchar* inString,
const GLint inStringType);
/* Convert a UCS-4 character code into the current string type. The result is
* stored in a GLint. This function is needed since the GLC specs store
* individual character codes in GLint whatever is their string type.
*/
extern GLint __glcConvertUcs4ToGLint(__GLCcontext *inContext, GLint inCode);
/* Convert a character encoded in the current string type to the UCS-4 format.
* This function is needed since the GLC specs store individual character
* codes in GLint whatever is their string type.
*/
extern GLint __glcConvertGLintToUcs4(const __GLCcontext *inContext,
GLint inCode);
/* Verify that the thread has a current context and that the master identified
* by 'inMaster' exists. Returns the master object corresponding to the master
* ID 'inMaster'.
*/
extern __GLCmaster* __glcVerifyMasterParameters(const GLint inMaster);
/* Verify that the thread has a current context and that the font identified
* by 'inFont' exists.
*/
extern __GLCfont* __glcVerifyFontParameters(GLint inFont);
/* Do the actual job of glcAppendFont(). This function can be called as an
* internal version of glcAppendFont() where the current GLC context is already
* determined and the font ID has been resolved in its corresponding __GLCfont
* object.
*/
extern void __glcAppendFont(__GLCcontext* inContext, __GLCfont* inFont);
/* This internal function deletes the font identified by inFont (if any) and
* creates a new font based on the pattern 'inPattern'. The resulting font is
* added to the list GLC_FONT_LIST.
*/
extern __GLCfont* __glcNewFontFromMaster(GLint inFontID, __GLCmaster* inMaster,
__GLCcontext *inContext, GLint inCode);
/* 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.
*/
extern GLboolean __glcFontFace(__GLCfont* inFont, const GLCchar8* inFace,
__GLCcontext *inContext);
/* Allocate a new ID for a font and store it in a special list so that the same
* ID is not allocated twice.
*/
GLint __glcGenFontID(__GLCcontext* inContext);
#ifndef HAVE_TLS
/* Return a struct which contains thread specific info. If the platform supports
* pointers for thread-local storage (TLS) then __glcGetThreadArea is replaced
* by a macro that returns a thread-local pointer. Otherwise, a function is
* called to return the structure using pthread_get_specific (POSIX) or
* TlsGetValue (WIN32) which are much slower.
*/
extern __GLCthreadArea* __glcGetThreadArea(void);
#endif
/* Raise an error.
* See also remarks above about TLS pointers.
*/
#ifdef HAVE_TLS
#define __glcRaiseError(inError) \
if (!__glcTlsThreadArea.errorState || ! (inError)) \
__glcTlsThreadArea.errorState = (inError)
#else
extern void __glcRaiseError(GLCenum inError);
#endif
#ifndef HAVE_TLS
/* Return the current context state.
* See also remarks above about TLS pointers.
*/
extern __GLCcontext* __glcGetCurrent(void);
#endif
/* Compute an optimal size for the glyph to be rendered on the screen (if no
* display list is currently building).
*/
extern void __glcGetScale(const __GLCcontext* inContext,
GLfloat* outTransformMatrix,
GLfloat* outScaleX, GLfloat* outScaleY);
/* Convert 'inString' (stored in logical order) to UCS4 format and return a
* copy of the converted string in visual order.
*/
extern GLCchar32* __glcConvertToVisualUcs4(__GLCcontext* inContext,
GLboolean *outIsRTL,
GLint *outLength,
const GLCchar* inString);
/* Convert 'inCount' characters of 'inString' (stored in logical order) to UCS4
* format and return a copy of the converted string in visual order.
*/
extern GLCchar32* __glcConvertCountedStringToVisualUcs4(__GLCcontext* inContext,
GLboolean *outIsRTL,
const GLCchar* inString,
const GLint inCount);
#ifdef GLC_FT_CACHE
/* Callback function used by the FreeType cache manager to open a given face */
extern FT_Error __glcFileOpen(FTC_FaceID inFile, FT_Library inLibrary,
FT_Pointer inData, FT_Face* outFace);
/* Rename FTC_Manager_LookupFace for old freetype versions */
# if FREETYPE_MAJOR == 2 \
&& (FREETYPE_MINOR < 1 \
|| (FREETYPE_MINOR == 1 && FREETYPE_PATCH < 8))
# define FTC_Manager_LookupFace FTC_Manager_Lookup_Face
# endif
#endif
/* Save the GL State in a structure */
extern void __glcSaveGLState(__GLCglState* inGLState,
const __GLCcontext* inContext,
const GLboolean inAll);
/* Restore the GL State from a structure */
extern void __glcRestoreGLState(const __GLCglState* inGLState,
const __GLCcontext* inContext,
const GLboolean inAll);
#ifdef GLEW_MX
/* Macro/function for GLEW so that it can get a context */
GLEWAPI GLEWContext* __glcGetGlewContext(void);
#define glewGetContext() __glcGetGlewContext()
#endif
#ifndef HAVE_TLS
/* This function initializes the thread management of QuesoGLC when TLS is not
* available. It must be called once (see the macro GLC_INIT_THREAD)
*/
extern void __glcInitThread(void);
#endif
extern int __glcdeCasteljauConic(void *inUserData);
extern int __glcdeCasteljauCubic(void *inUserData);
#endif /* __glc_internal_h */

590
3rdparty/quesoglc/master.c vendored Normal file
View File

@ -0,0 +1,590 @@
/* QuesoGLC
* A free implementation of the OpenGL Character Renderer (GLC)
* Copyright (c) 2002, 2004-2008, 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$ */
/** \file
* defines the so-called "Master commands" described in chapter 3.6 of the GLC
* specs.
*/
/** \defgroup master Master Commands
* Commands to create, manage and destroy masters.
*
* A master is a representation of a font that is stored outside QuesoGLC in a
* standard format such as TrueType or Type1.
*
* Every master has an associated character map. A character map is a table of
* entries that maps integer values to the name string that identifies the
* characters. Unlike fonts character maps, the character map of a master can
* not be modified.
*
* QuesoGLC maps the font files into master objects that are visible through
* the GLC API. A group of font files from a single typeface family will be
* mapped into a single GLC master object that has multiple faces. For
* example, the files \c Courier.pfa, \c Courier-Bold.pfa,
* \c Courier-BoldOblique.pfa, and \c Courier-Oblique.pfa are visible through
* the GLC API as a single master with \c GLC_VENDOR="Adobe",
* \c GLC_FAMILY="Courier", \c GLC_MASTER_FORMAT="Type1", \c GLC_FACE_COUNT=4
* and \c GLC_FACE_LIST=("Regular", "Bold", "Bold Oblique", "Oblique")
*
* Some GLC commands have a parameter \e inMaster. This parameter is an offset
* from the the first element in the GLC master list. The command raises
* \b GLC_PARAMETER_ERROR if \e inMaster is less than zero or is greater than
* or equal to the value of the variable \b GLC_MASTER_COUNT.
*/
#if defined(__WIN32__) || defined(_MSC_VER)
#include <io.h>
#else
#include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include "internal.h"
/* Most master commands need to check that :
* 1. The current thread owns a context state
* 2. The master identifier 'inMaster' is legal
* This internal function does both checks and returns the pointer to the
* __glcMaster object that is identified by 'inMaster'.
*/
__GLCmaster* __glcVerifyMasterParameters(const GLint inMaster)
{
const __GLCcontext *ctx = GLC_GET_CURRENT_CONTEXT();
/* Check if the current thread owns a context state */
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return NULL;
}
/* Verify if the master identifier is in legal bounds */
if (inMaster >= GLC_ARRAY_LENGTH(ctx->masterHashTable)) {
__glcRaiseError(GLC_PARAMETER_ERROR);
return NULL;
}
return __glcMasterCreate(inMaster, ctx);
}
/** \ingroup master
* This command returns a string from a string list that is an attribute of
* the master identified by \e inMaster. The string list is identified by
* \e inAttrib. The command returns the string at offset \e inIndex from the
* first element in this string list. Below are the string list attributes
* associated with each GLC master and font and their element count attributes:
* <center>
* <table>
* <caption>Master/font string list attributes</caption>
* <tr>
* <td>Name</td> <td>Enumerant</td> <td>Element count attribute</td>
* </tr>
* <tr>
* <td><b>GLC_CHAR_LIST</b></td>
* <td>0x0050</td>
* <td><b>GLC_CHAR_COUNT</b></td>
* </tr>
* <tr>
* <td><b>GLC_FACE_LIST</b></td>
* <td>0x0051</td>
* <td><b>GLC_FACE_COUNT</b></td>
* </tr>
* </table>
* </center>
* \n The command raises \b GLC_PARAMETER_ERROR if \e inIndex is less than
* zero or is greater than or equal to the value of the list element count
* attribute.
* \param inMaster Master from which an attribute is required.
* \param inAttrib String list that contains the desired attribute.
* \param inIndex Offset from the first element of the list associated with
* \e inAttrib.
* \return The string at offset \e inIndex from the first element of the
* string list identified by \e inAttrib.
* \sa glcGetMasterMap()
* \sa glcGetMasterc()
* \sa glcGetMasteri()
*/
const GLCchar* APIENTRY glcGetMasterListc(GLint inMaster, GLCenum inAttrib,
GLint inIndex)
{
__GLCcontext *ctx = NULL;
__GLCmaster *master = NULL;
__GLCcharMap *charMap = NULL;
const GLCchar8* string = NULL;
GLCchar8* faceName = NULL;
GLCchar* element = NULL;
GLC_INIT_THREAD();
/* Check some parameters.
* NOTE : the verification of some parameters needs to get the current
* context state but since we are supposed to check parameters
* _before_ the context state, we are done !
*/
switch(inAttrib) {
case GLC_CHAR_LIST:
case GLC_FACE_LIST:
break;
default:
__glcRaiseError(GLC_PARAMETER_ERROR);
return (GLCchar*)GLC_NONE;
}
/* Verify if inIndex is in legal bounds */
if (inIndex < 0) {
__glcRaiseError(GLC_PARAMETER_ERROR);
return (GLCchar*)GLC_NONE;
}
/* Verify that the thread has a current context and that the master
* identified by 'inMaster' exists.
*/
master = __glcVerifyMasterParameters(inMaster);
if (!master)
return (GLCchar*)GLC_NONE;
ctx = GLC_GET_CURRENT_CONTEXT();
/* return the requested attribute */
switch(inAttrib) {
case GLC_CHAR_LIST:
charMap = __glcCharMapCreate(master, ctx);
if (!charMap) {
__glcMasterDestroy(master);
return (GLCchar*)GLC_NONE;
}
string = __glcCharMapGetCharNameByIndex(charMap, inIndex);
if (!string) {
__glcMasterDestroy(master);
__glcCharMapDestroy(charMap);
return (GLCchar*)GLC_NONE;
}
break;
case GLC_FACE_LIST:
/* Get the face name */
faceName = __glcMasterGetFaceName(master, ctx, inIndex);
string = (const GLCchar8*)faceName;
break;
default:
__glcRaiseError(GLC_PARAMETER_ERROR);
return (GLCchar*)GLC_NONE;
}
/* Convert it from UTF-8 to the current string type and return */
element = __glcConvertFromUtf8ToBuffer(ctx, string);
__glcMasterDestroy(master);
if (charMap)
__glcCharMapDestroy(charMap);
else
free(faceName);
return element;
}
/** \ingroup master
* This command returns the string name of the character that the master
* identified by \e inMaster maps \e inCode to.
*
* Every master has associated with it a master map, which is a table of
* entries that map integer values to the name string that identifies the
* character.
*
* Every character code used in QuesoGLC is an element of the Unicode
* Character Database (UCD) defined by the standards ISO/IEC 10646:2003 and
* Unicode 4.0.1 (unless otherwise specified). A Unicode code point is denoted
* as \e U+hexcode, where \e hexcode is a sequence of hexadecimal digits. Each
* Unicode code point corresponds to a character that has a unique name
* string. For example, the code \e U+41 corresponds to the character
* <em>LATIN CAPITAL LETTER A</em>.
*
* If the master does not map \e inCode, the command returns \b GLC_NONE.
* \note While you cannot change the map of a master, you can change the map
* of a font using glcFontMap().
* \param inMaster The integer ID of the master from which to select the
* character.
* \param inCode The integer ID of character in the master map.
* \return The string name of the character that \e inCode is mapped to.
* \sa glcGetMasterListc()
* \sa glcGetMasterc()
* \sa glcGetMasteri()
*/
const GLCchar* APIENTRY glcGetMasterMap(GLint inMaster, GLint inCode)
{
__GLCmaster *master = NULL;
GLC_INIT_THREAD();
master = __glcVerifyMasterParameters(inMaster);
if (master) {
__GLCcontext *ctx = GLC_GET_CURRENT_CONTEXT();
__GLCcharMap* charMap = NULL;
GLCchar* result = NULL;
GLint code = 0;
const GLCchar8* name = NULL;
charMap = __glcCharMapCreate(master, ctx);
__glcMasterDestroy(master);
if (!charMap)
return (GLCchar*)GLC_NONE;
/* Get the character code converted to the UCS-4 format */
code = __glcConvertGLintToUcs4(ctx, inCode);
if (code < 0) {
__glcCharMapDestroy(charMap);
return (GLCchar*)GL_NONE;
}
name = __glcCharMapGetCharName(charMap, code);
__glcCharMapDestroy(charMap);
if (!name)
return (GLCchar*)GLC_NONE;
result = __glcConvertFromUtf8ToBuffer(ctx, name);
return result;
}
else
return (GLCchar*)GLC_NONE;
}
/** \ingroup master
* This command returns a string attribute of the master identified by
* \e inMaster. The table below lists the string attributes that are
* associated with each GLC master and font.
* <center>
* <table>
* <caption>Master/font string attributes</caption>
* <tr>
* <td>Name</td> <td>Enumerant</td>
* </tr>
* <tr>
* <td><b>GLC_FAMILY</b></td> <td>0x0060</td>
* </tr>
* <tr>
* <td><b>GLC_MASTER_FORMAT</b></td> <td>0x0061</td>
* </tr>
* <tr>
* <td><b>GLC_VENDOR</b></td> <td>0x0062</td>
* </tr>
* <tr>
* <td><b>GLC_VERSION</b></td> <td>0x0063</td>
* </tr>
* <tr>
* <td><b>GLC_FULL_NAME_SGI</b></td> <td>0x8002</td>
* </tr>
* </table>
* </center>
* \param inMaster The master for which an attribute value is required.
* \param inAttrib The attribute for which the value is required.
* \return The value that is associated with the attribute \e inAttrib.
* \sa glcGetMasteri()
* \sa glcGetMasterMap()
* \sa glcGetMasterListc()
*/
const GLCchar* APIENTRY glcGetMasterc(GLint inMaster, GLCenum inAttrib)
{
__GLCcontext *ctx = NULL;
const GLCchar *buffer = NULL;
__GLCmaster* master = NULL;
GLC_INIT_THREAD();
/* Check parameter inAttrib */
switch(inAttrib) {
case GLC_FAMILY:
case GLC_MASTER_FORMAT:
case GLC_VENDOR:
case GLC_VERSION:
case GLC_FULL_NAME_SGI:
break;
default:
__glcRaiseError(GLC_PARAMETER_ERROR);
return (GLCchar*)GLC_NONE;
}
/* Verify that the thread has a current context and that the master
* identified by 'inMaster' exists.
*/
master = __glcVerifyMasterParameters(inMaster);
if (!master)
return (GLCchar*)GLC_NONE;
ctx = GLC_GET_CURRENT_CONTEXT();
buffer = __glcMasterGetInfo(master, ctx, inAttrib);
__glcMasterDestroy(master);
return buffer;
}
/** \ingroup master
* This command returns an integer attribute of the master identified by
* \e inMaster. The attribute is identified by \e inAttrib. The table below
* lists the integer attributes that are associated with each GLC master
* and font.
* <center>
* <table>
* <caption>Master/font integer attributes</caption>
* <tr>
* <td>Name</td> <td>Enumerant</td>
* </tr>
* <tr>
* <td><b>GLC_CHAR_COUNT</b></td> <td>0x0070</td>
* </tr>
* <tr>
* <td><b>GLC_FACE_COUNT</b></td> <td>0x0071</td>
* </tr>
* <tr>
* <td><b>GLC_IS_FIXED_PITCH</b></td> <td>0x0072</td>
* </tr>
* <tr>
* <td><b>GLC_MAX_MAPPED_CODE</b></td> <td>0x0073</td>
* </tr>
* <tr>
* <td><b>GLC_MIN_MAPPED_CODE</b></td> <td>0x0074</td>
* </tr>
* </table>
* </center>
* \n If the requested master attribute is \b GLC_IS_FIXED_PITCH then the
* command returns \b GL_TRUE if and only if each face of the master
* identified by \e inMaster has a fixed pitch.
* \param inMaster The master for which an attribute value is required.
* \param inAttrib The attribute for which the value is required.
* \return The value of the attribute \e inAttrib of the master identified
* by \e inMaster.
* \sa glcGetMasterc()
* \sa glcGetMasterMap()
* \sa glcGetMasterListc()
*/
GLint APIENTRY glcGetMasteri(GLint inMaster, GLCenum inAttrib)
{
GLint count = 0;
__GLCmaster *master = NULL;
__GLCcharMap* charMap = NULL;
__GLCcontext* ctx = NULL;
GLC_INIT_THREAD();
/* Check parameter inAttrib */
switch(inAttrib) {
case GLC_CHAR_COUNT:
case GLC_FACE_COUNT:
case GLC_IS_FIXED_PITCH:
case GLC_MAX_MAPPED_CODE:
case GLC_MIN_MAPPED_CODE:
break;
default:
__glcRaiseError(GLC_PARAMETER_ERROR);
return GLC_NONE;
}
/* Verify that the thread has a current context and that the master
* identified by 'inMaster' exists.
*/
master = __glcVerifyMasterParameters(inMaster);
if (!master)
return GLC_NONE;
if (inAttrib == GLC_IS_FIXED_PITCH) {
/* Is this a fixed font ? */
GLboolean fixed = __glcMasterIsFixedPitch(master);
__glcMasterDestroy(master);
return fixed;
}
ctx = GLC_GET_CURRENT_CONTEXT();
if (inAttrib != GLC_FACE_COUNT) {
charMap = __glcCharMapCreate(master, ctx);
if (!charMap) {
__glcMasterDestroy(master);
return GLC_NONE;
}
}
/* return the requested attribute */
switch(inAttrib) {
case GLC_CHAR_COUNT:
count = __glcCharMapGetCount(charMap);
break;
case GLC_FACE_COUNT:
count = __glcMasterFaceCount(master, ctx);
break;
case GLC_MAX_MAPPED_CODE:
count = __glcCharMapGetMaxMappedCode(charMap);
break;
case GLC_MIN_MAPPED_CODE:
count = __glcCharMapGetMinMappedCode(charMap);
break;
}
if (charMap)
__glcCharMapDestroy(charMap);
__glcMasterDestroy(master);
return count;
}
/* Common subroutine to add a catalog to the current context. It is called
* either by glcAppendCatalog() or by glcPrependCatalog().
*/
static void __glcAddCatalog(const GLCchar* inCatalog, const GLboolean inAppend)
{
__GLCcontext *ctx = NULL;
struct stat dirStat;
GLC_INIT_THREAD();
/* If inCatalog is NULL then there is no point in continuing */
if (!inCatalog)
return;
/* Check that 'inCatalog' points to a directory that can be read */
#ifdef __WIN32__
if (_access((const char*)inCatalog, 0)) {
#else
if (access((const char *)inCatalog, R_OK) < 0) {
#endif
/* May be something more explicit should be done ? */
__glcRaiseError(GLC_PARAMETER_ERROR);
return;
}
/* Check that 'inCatalog' is a directory */
if (stat((const char *)inCatalog, &dirStat) < 0) {
__glcRaiseError(GLC_PARAMETER_ERROR);
return;
}
#ifdef __WIN32__
if (!(dirStat.st_mode & _S_IFDIR)) {
#else
if (!S_ISDIR(dirStat.st_mode)) {
#endif
__glcRaiseError(GLC_PARAMETER_ERROR);
return;
}
/* Verify that the thread owns a context */
ctx = GLC_GET_CURRENT_CONTEXT();
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return;
}
if (inAppend)
__glcContextAppendCatalog(ctx, inCatalog);
else
__glcContextPrependCatalog(ctx, inCatalog);
}
/** \ingroup master
* This command appends the string \e inCatalog to the list
* \b GLC_CATALOG_LIST.
*
* The catalog is represented as a zero-terminated string. The interpretation
* of this string is specified by the value that has been set using
* glcStringType().
*
* A catalog is a path to a list of masters. A master is a representation of a
* font that is stored outside QuesoGLC in a standard format such as TrueType
* or Type1.
*
* A catalog defines the list of masters that can be instantiated (that is, be
* used as fonts) in a GLC context.
*
* A font is a styllistically consistent set of glyphs that can be used to
* render some set of characters. Each font has a family name (for example
* Palatino) and a state variable that selects one of the faces (for example
* regular, bold, italic, bold italic) that the font contains. A typeface is
* the combination of a family and a face (for example Palatino Bold).
* \param inCatalog The catalog to append to the list \b GLC_CATALOG_LIST
* \sa glcGetList() with argument \b GLC_CATALOG_LIST
* \sa glcGeti() with argument \b GLC_CATALOG_COUNT
* \sa glcPrependCatalog()
* \sa glcRemoveCatalog()
*/
void APIENTRY glcAppendCatalog(const GLCchar* inCatalog)
{
__glcAddCatalog(inCatalog, GL_TRUE);
}
/** \ingroup master
* This command prepends the string \e inCatalog to the list
* \b GLC_CATALOG_LIST
* \param inCatalog The catalog to prepend to the list \b GLC_CATALOG_LIST
* \sa glcAppendCatalog()
* \sa glcRemoveCatalog()
*/
void APIENTRY glcPrependCatalog(const GLCchar* inCatalog)
{
__glcAddCatalog(inCatalog, GL_FALSE);
}
/** \ingroup master
* This command removes a string from the list \b GLC_CATALOG_LIST. It removes
* the string at offset \e inIndex from the first element in the list. The
* command raises \b GLC_PARAMETER_ERROR if \e inIndex is less than zero or is
* greater than or equal to the value of the variable \b GLC_CATALOG_COUNT.
*
* QuesoGLC also removes the masters that are defined in the corresponding
* catalog.
* \param inIndex The index of the string to remove from the catalog list
* \b GLC_CATALOG_LIST
* \sa glcAppendCatalog()
* \sa glcPrependCatalog()
*/
void APIENTRY glcRemoveCatalog(GLint inIndex)
{
__GLCcontext *ctx = NULL;
GLC_INIT_THREAD();
/* Verify that the thread owns a context */
ctx = GLC_GET_CURRENT_CONTEXT();
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return;
}
/* Verify that the parameter inIndex is in legal bounds */
if (inIndex < 0) {
__glcRaiseError(GLC_PARAMETER_ERROR);
return;
}
__glcContextRemoveCatalog(ctx, inIndex);
}

879
3rdparty/quesoglc/measure.c vendored Normal file
View File

@ -0,0 +1,879 @@
/* 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$ */
/** \file
* defines the so-called "Measurement commands" described in chapter 3.10 of
* the GLC specs.
*/
/** \defgroup measure Measurement commands
* Those commands returns metrics (bounding box, baseline) of character or
* string layouts. Glyphs coordinates are defined in <em>em units</em> and are
* transformed during rendering to produce the desired mapping of the glyph
* shape into the GL window coordinate system. Moreover, GLC can return some
* metrics for a character and string layouts. The table below lists the
* metrics that are available :
* <center>
* <table>
* <caption>Metrics for character and string layout</caption>
* <tr>
* <td>Name</td> <td>Enumerant</td> <td>Vector</td>
* </tr>
* <tr>
* <td><b>GLC_BASELINE</b></td> <td>0x0030</td>
* <td>[ x<sub>l</sub> y<sub>l</sub> x<sub>r</sub> y<sub>r</sub> ]</td>
* </tr>
* <tr>
* <td><b>GLC_BOUNDS</b></td> <td>0x0031</td>
* <td>[ x<sub>lb</sub> y<sub>lb</sub> x<sub>rb</sub> y<sub>rb</sub>
* x<sub>rt</sub> y<sub>rt</sub> x<sub>lt</sub> y<sub>lt</sub> ]</td>
* </tr>
* </table>
* </center>
* \n \b GLC_BASELINE is the line segment from the origin of the layout to the
* origin of the following layout. \b GLC_BOUNDS is the bounding box of the
* layout.
*
* \image html measure.png "Baseline and bounds"
* \image latex measure.eps "Baseline and bounds" width=7cm
* \n Each point <em>(x,y)</em> is computed in em coordinates, with the origin
* of a layout at <em>(0,0)</em>. If the value of the variable
* \b GLC_RENDER_STYLE is \b GLC_BITMAP or GLC_PIXMAP_QSO, each point is
* transformed by the 2x2 \b GLC_BITMAP_MATRIX.
*/
#include "internal.h"
#include <math.h>
/* Multiply a vector by the GLC_BITMAP_MATRIX */
static void __glcTransformVector(GLfloat* outVec, const GLfloat *inMatrix)
{
GLfloat temp = inMatrix[0] * outVec[0] + inMatrix[2] * outVec[1];
outVec[1] = inMatrix[1] * outVec[0] + inMatrix[3] * outVec[1];
outVec[0] = temp;
}
/* Retrieve the metrics of a character identified by 'inCode' in a font
* identified by 'inFont'.
* 'inCode' must be given in UCS-4 format
*/
static void* __glcGetCharMetric(const GLint inCode, const GLint inPrevCode,
const GLboolean inIsRTL,
const __GLCfont* inFont,
__GLCcontext* inContext, const void* inData,
const GLboolean inMultipleChars)
{
GLfloat* outVec = (GLfloat*)inData;
int i = 0;
GLfloat xMin = 0., xMax = 0.;
GLfloat yMin = 0., yMax = 0.;
GLfloat inScaleX = GLC_POINT_SIZE;
GLfloat inScaleY = GLC_POINT_SIZE;
GLfloat temp[4];
assert(inFont);
if (inMultipleChars && ((inContext->renderState.renderStyle == GLC_BITMAP)
|| (inContext->renderState.renderStyle == GLC_PIXMAP_QSO))) {
/* If a string (or several characters) is to be measured, it will be easier
* to perform the calculations in the glyph coordinate system than in the
* screen coordinate system. In order to get the values that already stored
* in outVec back in the glyph coordinate system, we must compute the
* inverse of the transformation matrix.
*/
GLfloat* matrix = inContext->bitmapMatrix;
GLfloat inverseMatrix[4];
GLfloat norm = 0.f;
GLfloat determinant = matrix[0] * matrix[3] - matrix[1] * matrix[2];
for (i = 0; i < 4; i++) {
if (fabs(matrix[i]) > norm)
norm = fabs(matrix[i]);
}
if (determinant >= norm * GLC_EPSILON) {
inverseMatrix[0] = matrix[3] / determinant;
inverseMatrix[1] = -matrix[1] / determinant;
inverseMatrix[2] = -matrix[2] / determinant;
inverseMatrix[3] = matrix[0] / determinant;
}
else
return NULL;
/* Transform the values in outVec from the screen coordinate system to the
* the glyph coordinate system
*/
for (i = 0; i < 7; i++)
__glcTransformVector(&outVec[2*i], inverseMatrix);
}
if (!inMultipleChars) {
outVec[0] = 0.;
outVec[1] = 0.;
outVec[2] = 0.;
outVec[3] = 0.;
}
else {
outVec[2] += outVec[12];
outVec[3] += outVec[13];
}
if (!__glcFontGetBoundingBox(inFont, inCode, temp, inContext, inScaleX,
inScaleY))
return NULL;
/* Take into account the advance of the glyphs that have already been
* measured.
*/
xMin = temp[0] + outVec[2];
yMin = temp[1] + outVec[3];
xMax = temp[2] + outVec[2];
yMax = temp[3] + outVec[3];
/* Update the global bounding box */
if (inMultipleChars) {
outVec[4] = xMin < outVec[4] ? xMin : outVec[4];
outVec[5] = yMin < outVec[5] ? yMin : outVec[5];
outVec[6] = xMax > outVec[6] ? xMax : outVec[6];
outVec[9] = yMax > outVec[9] ? yMax : outVec[9];
}
else {
outVec[4] = xMin;
outVec[5] = yMin;
outVec[6] = xMax;
outVec[9] = yMax;
}
/* Finalize the update of the bounding box coordinates */
outVec[7] = outVec[5];
outVec[8] = outVec[6];
outVec[10] = outVec[4];
outVec[11] = outVec[9];
/* Get the advance of the glyph */
if (!__glcFontGetAdvance(inFont, inCode, temp, inContext, inScaleX, inScaleY))
return NULL;
/* Update the global advance accordingly */
if (inIsRTL) {
outVec[2] -= temp[0];
outVec[3] -= temp[1];
}
else {
outVec[2] += temp[0];
outVec[3] += temp[1];
}
outVec[12] = 0.;
outVec[13] = 0.;
if (inPrevCode && inContext->enableState.kerning) {
GLfloat kerning[2];
const GLint leftCode = inIsRTL ? inCode : inPrevCode;
const GLint rightCode = inIsRTL ? inPrevCode : inCode;
if (__glcFontGetKerning(inFont, leftCode, rightCode, kerning, inContext,
inScaleX, inScaleY)) {
outVec[12] = inIsRTL ? -kerning[0] : kerning[0];
outVec[13] = kerning[1];
}
}
/* Transforms the values into the screen coordinate system if necessary */
if ((inContext->renderState.renderStyle == GLC_BITMAP)
|| (inContext->renderState.renderStyle == GLC_PIXMAP_QSO)){
for (i = 0; i < 7; i++)
__glcTransformVector(&outVec[2*i], inContext->bitmapMatrix);
}
return outVec;
}
/** \ingroup measure
* This command is identical to the command glcRenderChar(), except that
* instead of rendering the character that \e inCode is mapped to, the command
* measures the resulting layout and stores in \e outVec the value of the
* metric identified by \e inMetric. If the command does not raise an error,
* its return value is \e outVec.
*
* \param inCode The character to measure.
* \param inMetric The metric to measure, either \b GLC_BASELINE or
* \b GLC_BOUNDS.
* \param outVec A vector in which to store value of \e inMetric for specified
* character.
* \returns \e outVec if the command succeeds, \b NULL otherwise.
* \sa glcGetMaxCharMetric()
* \sa glcGetStringCharMetric()
* \sa glcMeasureCountedString()
* \sa glcMeasureString()
*/
GLfloat* APIENTRY glcGetCharMetric(GLint inCode, GLCenum inMetric,
GLfloat *outVec)
{
__GLCcontext *ctx = NULL;
GLint code = 0;
GLfloat vector[14];
__GLCcharacter prevCode = { 0, NULL, NULL, {0.f, 0.f}};
GLC_INIT_THREAD();
assert(outVec);
switch(inMetric) {
case GLC_BASELINE:
case GLC_BOUNDS:
break;
default:
__glcRaiseError(GLC_PARAMETER_ERROR);
return NULL;
}
/* Verify if the current thread owns a context state */
ctx = GLC_GET_CURRENT_CONTEXT();
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return NULL;
}
/* Get the character code converted to the UCS-4 format */
code = __glcConvertGLintToUcs4(ctx, inCode);
if (code < 0)
return NULL;
/* Control characters have no metrics */
if (code < 32) {
memset(outVec, 0, ((inMetric == GLC_BOUNDS) ? 8 : 4) * sizeof(GLfloat));
return outVec;
}
/* Call __glcProcessChar that will get a font which maps the code to a glyph
* or issue the replacement code or the character sequence \<xxx> and call
* __glcGetCharMetric()
*/
memset(vector, 0, 14 * sizeof(GLfloat));
if (__glcProcessChar(ctx, code, &prevCode, GL_FALSE, __glcGetCharMetric,
vector)) {
switch(inMetric) {
case GLC_BASELINE:
memcpy(outVec, vector, 4 * sizeof(GLfloat));
return outVec;
case GLC_BOUNDS:
memcpy(outVec, &vector[4], 8 * sizeof(GLfloat));
return outVec;
}
}
return NULL;
}
/** \ingroup measure
* This command measures the layout that would result from rendering all
* mapped characters at the same origin. This contrast with
* glcGetStringCharMetric(), which measures characters as part of a string,
* that is, influenced by kerning, ligatures, and so on.
*
* This command evaluates the metrics of every fonts in the
* \b GLC_CURRENT_FONT_LIST. Fonts that are not listed in
* \b GLC_CURRENT_FONT_LIST are ignored.
*
* The command stores in \e outVec the value of the metric identified by
* \e inMetric. If the command does not raise an error, its return value
* is \e outVec.
*
* \param inMetric The metric to measure, either \b GLC_BASELINE or
* \b GLC_BOUNDS.
* \param outVec A vector in which to store value of \e inMetric for all
* mapped character.
* \returns \e outVec if the command succeeds, \b NULL otherwise.
* \sa glcGetCharMetric()
* \sa glcGetStringCharMetric()
* \sa glcMeasureCountedString()
* \sa glcMeasureString()
*/
GLfloat* APIENTRY glcGetMaxCharMetric(GLCenum inMetric, GLfloat *outVec)
{
__GLCcontext *ctx = NULL;
GLfloat advanceX = 0.f, advanceY = 0.f, yb = 1e4f, yt = -1e4f, xr = -1e4f,
xl = 1e4f;
FT_ListNode node = NULL;
GLfloat inScaleX = GLC_POINT_SIZE;
GLfloat inScaleY = GLC_POINT_SIZE;
GLC_INIT_THREAD();
assert(outVec);
/* Check the parameters */
switch(inMetric) {
case GLC_BASELINE:
case GLC_BOUNDS:
break;
default:
__glcRaiseError(GLC_PARAMETER_ERROR);
return NULL;
}
/* Verify if the current thread owns a context state */
ctx = GLC_GET_CURRENT_CONTEXT();
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return NULL;
}
/* For each font in GLC_CURRENT_FONT_LIST find the maximum values of the
* advance width of the bounding boxes.
*/
for (node = ctx->currentFontList.head; node; node = node->next) {
GLfloat temp[6];
__GLCfont* font = (__GLCfont*)node->data;
if (!__glcFontGetMaxMetric(font, temp, ctx, inScaleX, inScaleY))
return NULL;
advanceX = temp[0] > advanceX ? temp[0] : advanceX;
advanceY = temp[1] > advanceY ? temp[1] : advanceY;
yt = temp[2] > yt ? temp[2] : yt;
yb = temp[3] < yb ? temp[3] : yb;
xr = temp[4] > xr ? temp[4] : xr;
xl = temp[5] < xl ? temp[5] : xl;
}
/* Update and transform, if necessary, the returned value */
switch(inMetric) {
case GLC_BASELINE:
outVec[0] = 0.;
outVec[1] = 0.;
outVec[2] = advanceX;
outVec[3] = advanceY;
if ((ctx->renderState.renderStyle == GLC_BITMAP)
|| (ctx->renderState.renderStyle == GLC_PIXMAP_QSO))
__glcTransformVector(&outVec[2], ctx->bitmapMatrix);
return outVec;
case GLC_BOUNDS:
outVec[0] = xl;
outVec[1] = yb;
outVec[2] = xr;
outVec[3] = yb;
outVec[4] = xr;
outVec[5] = yt;
outVec[6] = xl;
outVec[7] = yt;
if ((ctx->renderState.renderStyle == GLC_BITMAP)
|| (ctx->renderState.renderStyle == GLC_PIXMAP_QSO)) {
int i = 0;
for (i = 0; i < 4; i++)
__glcTransformVector(&outVec[2*i], ctx->bitmapMatrix);
}
return outVec;
}
return NULL;
}
/** \ingroup measure
* This command retrieves a character metric from the GLC measurement buffer
* and stores it in \e outVec. To store a string in the measurement buffer,
* call glcMeasureCountedString() or glcMeasureString().
*
* The character is identified by \e inIndex, and the metric is identified by
* \e inMetric.
*
* The command raises \b GLC_PARAMETER_ERROR if \e inIndex is less than zero
* or is greater than or equal to the value of the variable
* \b GLC_MEASURED_CHAR_COUNT or \e outVec is NULL. If the command does not
* raise an error, its return value is outVec.
* \par Example:
* The following example first calls glcMeasureString() to store the string
* "hello" in the measurement buffer. It then retrieves both the baseline and
* the bounding box for the whole string, then for each individual character.
*
* \code
* GLfloat overallBaseline[4];
* GLfloat overallBoundingBox[8];
*
* GLfloat charBaselines[5][4];
* GLfloat charBoundingBoxes[5][8];
*
* GLint i;
*
* glcMeasureString(GL_TRUE, "hello");
*
* glcGetStringMetric(GLC_BASELINE, overallBaseline);
* glcGetStringMetric(GLC_BOUNDS, overallBoundingBox);
*
* for (i = 0; i < 5; i++) {
* glcGetStringCharMetric(i, GLC_BASELINE, charBaselines[i]);
* glcGetStringCharMetric(i, GLC_BOUNDS, charBoundingBoxes[i]);
* }
* \endcode
* \note
* \e glcGetStringCharMetric is useful if you're interested in the metrics of
* a character as it appears in a string, that is, influenced by kerning,
* ligatures, and so on. To measure the metrics of a character alone, call
* glcGetCharMetric().
* \param inIndex Specifies which element in the string to measure.
* \param inMetric The metric to measure, either \b GLC_BASELINE or
* \b GLC_BOUNDS.
* \param outVec A vector in which to store value of \e inMetric for the
* character identified by \e inIndex.
* \returns \e outVec if the command succeeds, \b NULL otherwise.
* \sa glcGetCharMetric()
* \sa glcGetMaxCharMetric()
* \sa glcMeasureCountedString()
* \sa glcMeasureString()
*/
GLfloat* APIENTRY glcGetStringCharMetric(GLint inIndex, GLCenum inMetric,
GLfloat *outVec)
{
__GLCcontext *ctx = NULL;
GLfloat (*measurementBuffer)[12] = NULL;
GLC_INIT_THREAD();
assert(outVec);
/* Check the parameters */
switch(inMetric) {
case GLC_BASELINE:
case GLC_BOUNDS:
break;
default:
__glcRaiseError(GLC_PARAMETER_ERROR);
return NULL;
}
/* Verify if the current thread owns a context state */
ctx = GLC_GET_CURRENT_CONTEXT();
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return NULL;
}
measurementBuffer = (GLfloat(*)[12])GLC_ARRAY_DATA(ctx->measurementBuffer);
/* Verify that inIndex is in legal bounds */
if ((inIndex < 0)
|| (inIndex >= GLC_ARRAY_LENGTH(ctx->measurementBuffer))) {
__glcRaiseError(GLC_PARAMETER_ERROR);
return NULL;
}
switch(inMetric) {
case GLC_BASELINE:
memcpy(outVec, &measurementBuffer[inIndex][0],
4 * sizeof(GLfloat));
return outVec;
case GLC_BOUNDS:
memcpy(outVec, &measurementBuffer[inIndex][4],
8 * sizeof(GLfloat));
return outVec;
}
return NULL;
}
/** \ingroup measure
* This command retrieves a string metric from the GLC measurement buffer
* and stores it in \e outVec. The metric is identified by \e inMetric. To
* store the metrics of a string in the GLC measurement buffer, call
* glcMeasureCountedString() or glcMeasureString().
*
* If the command does not raise an error, its return value is \e outVec.
* \param inMetric The metric to measure, either \b GLC_BASELINE or
* \b GLC_BOUNDS.
* \param outVec A vector in which to store value of \e inMetric for the
* character identified by \e inIndex.
* \returns \e outVec if the command succeeds, \b NULL otherwise.
* \sa glcGetCharMetric()
* \sa glcGetMaxCharMetric()
* \sa glcGetStringCharMetric()
* \sa glcMeasureCountedString()
* \sa glcMeasureString()
*/
GLfloat* APIENTRY glcGetStringMetric(GLCenum inMetric, GLfloat *outVec)
{
__GLCcontext *ctx = NULL;
GLC_INIT_THREAD();
assert(outVec);
/* Check the parameters */
switch(inMetric) {
case GLC_BASELINE:
case GLC_BOUNDS:
break;
default:
__glcRaiseError(GLC_PARAMETER_ERROR);
return NULL;
}
/* Verify if the current thread owns a context state */
ctx = GLC_GET_CURRENT_CONTEXT();
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return NULL;
}
/* Copy the values requested by the client in outVec */
switch(inMetric) {
case GLC_BASELINE:
memcpy(outVec, ctx->measurementStringBuffer, 4*sizeof(GLfloat));
return outVec;
case GLC_BOUNDS:
memcpy(outVec, &ctx->measurementStringBuffer[4], 8*sizeof(GLfloat));
return outVec;
}
return NULL;
}
/* This function perform the actual work of measuring a string
* It is called by both glcMeasureString() and glcMeasureCountedString()
* The string inString is encoded in UCS4 and is stored in visual order.
*/
static GLint __glcMeasureCountedString(__GLCcontext *inContext,
const GLboolean inMeasureChars,
const GLint inCount,
const GLCchar32* inString,
const GLboolean inIsRTL)
{
GLint i = 0;
GLfloat metrics[14];
const GLCchar32* ptr = NULL;
const GLint storeRenderStyle = inContext->renderState.renderStyle;
GLfloat xMin = 0., xMax = 0.;
GLfloat yMin = 0., yMax = 0.;
GLfloat* outVec = inContext->measurementStringBuffer;
__GLCcharacter prevCode = { 0, NULL, NULL, {0.f, 0.f}};
GLint shift = 1;
if ((inContext->renderState.renderStyle == GLC_BITMAP)
|| (inContext->renderState.renderStyle == GLC_PIXMAP_QSO)) {
/* In order to prevent __glcProcessCharMetric() to transform its results
* with the GLC_MATRIX, ctx->renderStyle must not be GLC_BITMAP (or
* GLC_PIXMAP_QSO)
*/
inContext->renderState.renderStyle = 0;
}
memset(outVec, 0, 12*sizeof(GLfloat));
if (inMeasureChars)
GLC_ARRAY_LENGTH(inContext->measurementBuffer) = 0;
/* For each character of the string, the measurement are performed and
* gathered in the context state
*/
ptr = inString;
if (inIsRTL) {
ptr += inCount - 1;
shift = -1;
}
memset(metrics, 0, 14 * sizeof(GLfloat));
for (i = 0; i < inCount; i++) {
if (*ptr < 32) {
/* Control characters have no metrics. However they must not be skipped
* otherwise the characters indices in the string would be modified and
* this would make troubles when the user calls glcGetStringCharMetric().
*/
memset(metrics, 0, 14 * sizeof(GLfloat));
}
else {
FT_ListNode node = NULL;
if (inContext->enableState.glObjects
&& inContext->renderState.renderStyle) {
__GLCfont* font = NULL;
__GLCglyph* glyph = NULL;
for (node = inContext->currentFontList.head; node ; node = node->next) {
font = (__GLCfont*)node->data;
glyph = __glcCharMapGetGlyph(font->charMap, *ptr);
metrics[0] = 0.;
metrics[1] = 0.;
if (!glyph || !glyph->advanceCached) {
if (!__glcFontGetAdvance(font, *ptr, &metrics[2], inContext,
GLC_POINT_SIZE, GLC_POINT_SIZE))
continue;
}
else {
metrics[2] = glyph->advance[0];
metrics[3] = glyph->advance[1];
}
if (!glyph || !glyph->boundingBoxCached) {
if (!__glcFontGetBoundingBox(font, *ptr, &metrics[4], inContext,
GLC_POINT_SIZE, GLC_POINT_SIZE))
continue;
metrics[9] = metrics[7];
}
else {
metrics[4] = glyph->boundingBox[0];
metrics[5] = glyph->boundingBox[1];
metrics[6] = glyph->boundingBox[2];
metrics[9] = glyph->boundingBox[3];
}
metrics[7] = metrics[5];
metrics[8] = metrics[6];
metrics[10] = metrics[4];
metrics[11] = metrics[9];
if (inContext->enableState.kerning) {
if (prevCode.code && prevCode.font == font) {
const GLint leftCode = inIsRTL ? *ptr : prevCode.code;
const GLint rightCode = inIsRTL ? prevCode.code : *ptr;
if (!__glcFontGetKerning(font, leftCode, rightCode, &metrics[12],
inContext, GLC_POINT_SIZE,
GLC_POINT_SIZE))
memset(&metrics[12], 0, 2*sizeof(GLfloat));
}
}
prevCode.font = font;
prevCode.code = *ptr;
break;
}
}
if (!node) {
__glcProcessChar(inContext, *ptr, &prevCode, inIsRTL,
__glcGetCharMetric, metrics);
}
}
ptr += shift;
/* If characters are to be measured then store the results */
if (inMeasureChars) {
__glcArrayAppend(inContext->measurementBuffer, metrics);
if (i) {
GLfloat (*measurementBuffer)[12] =
(GLfloat(*)[12])GLC_ARRAY_DATA(inContext->measurementBuffer);
GLfloat prevCharAdvance = measurementBuffer[i-1][2] + metrics[12];
int j = 0;
for (j = 0; j < 6; j++)
measurementBuffer[i][2*j] += prevCharAdvance;
}
}
/* Initialize outVec if we are processing the first character of the string
*/
if (!i) {
outVec[0] = metrics[0];
outVec[1] = metrics[1];
outVec[2] = metrics[0];
outVec[3] = metrics[1];
outVec[4] = metrics[4] + metrics[0];
outVec[5] = metrics[5] + metrics[1];
outVec[6] = metrics[6] + metrics[0];
outVec[9] = metrics[9] + metrics[1];
}
else {
/* Takes the kerning into account */
outVec[2] += metrics[12];
outVec[3] += metrics[13];
}
xMin = metrics[4] + outVec[2];
xMax = metrics[6] + outVec[2];
yMin = metrics[5] + outVec[3];
yMax = metrics[9] + outVec[3];
outVec[4] = xMin < outVec[4] ? xMin : outVec[4];
outVec[5] = yMin < outVec[5] ? yMin : outVec[5];
outVec[6] = xMax > outVec[6] ? xMax : outVec[6];
outVec[9] = yMax > outVec[9] ? yMax : outVec[9];
outVec[2] += metrics[2];
outVec[3] += metrics[3];
}
outVec[7] = outVec[5];
outVec[8] = outVec[6];
outVec[10] = outVec[4];
outVec[11] = outVec[9];
/* Transform all the data in the screen coordinate system if the rendering
* style is GLC_BITMAP or GLC_PIXMAP_QSO.
*/
if ((storeRenderStyle == GLC_BITMAP)
|| (storeRenderStyle == GLC_PIXMAP_QSO)) {
inContext->renderState.renderStyle = storeRenderStyle;
for (i = 0; i < 6; i++)
__glcTransformVector(&inContext->measurementStringBuffer[2*i],
inContext->bitmapMatrix);
if (inMeasureChars) {
GLfloat (*measurementBuffer)[12] =
(GLfloat(*)[12])GLC_ARRAY_DATA(inContext->measurementBuffer);
int j = 0;
for (i = 0; i < inCount; i++) {
for (j = 0; j < 6; j++)
__glcTransformVector(&measurementBuffer[i][2*j],
inContext->bitmapMatrix);
}
}
}
/* Return the number of measured characters */
return inCount;
}
/** \ingroup measure
* This command is identical to the command glcRenderCountedString(), except
* that instead of rendering a string, the command measures the resulting
* layout and stores the measurement in the GLC measurement buffer. The
* string comprises the first \e inCount elements of the array \e inString,
* which need not be followed by a zero element.
*
* If the value \e inMeasureChars is nonzero, the command computes metrics for
* each character and for the overall string, and it assigns the value
* \e inCount to the variable \b GLC_MEASURED_CHARACTER_COUNT. Otherwise, the
* command computes metrics only for the overall string, and it assigns the
* value zero to the variable \b GLC_MEASURED_CHARACTER_COUNT.
*
* If the command does not raise an error, its return value is the value of
* the variable \b GLC_MEASURED_CHARACTER_COUNT.
*
* The command raises \b GLC_PARAMETER_ERROR if \e inCount is less than zero.
* \param inMeasureChars Specifies whether to compute metrics only for the
* string or for the characters as well.
* \param inCount The number of elements to measure, starting at the first
* element.
* \param inString The string to be measured.
* \returns The variable \b GLC_MEASURED_CHARACTER_COUNT if the command
* succeeds, zero otherwise.
* \sa glcGeti() with argument GLC_MEASURED_CHAR_COUNT
* \sa glcGetStringCharMetric()
* \sa glcGetStringMetric()
*/
GLint APIENTRY glcMeasureCountedString(GLboolean inMeasureChars, GLint inCount,
const GLCchar* inString)
{
__GLCcontext *ctx = NULL;
GLint count = 0;
GLCchar32* UinString = NULL;
GLboolean isRightToLeft = GL_FALSE;
/* If inString is NULL then there is no point in continuing */
if (!inString)
return 0;
GLC_INIT_THREAD();
/* Check the parameters */
if (inCount < 0) {
__glcRaiseError(GLC_PARAMETER_ERROR);
return 0;
}
/* Verify if the current thread owns a context state */
ctx = GLC_GET_CURRENT_CONTEXT();
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return 0;
}
UinString = __glcConvertCountedStringToVisualUcs4(ctx, &isRightToLeft,
inString, inCount);
if (!UinString)
return 0;
count = __glcMeasureCountedString(ctx, inMeasureChars, inCount, UinString,
isRightToLeft);
return count;
}
/** \ingroup measure
* This command measures the layout that would result from rendering a string
* and stores the measurements in the GLC measurement buffer. This command
* is identical to the command glcMeasureCountedString(), except that
* \e inString is zero terminated, not counted.
*
* If the command does not raise an error, its return value is the value of
* the variable \b GLC_MEASURED_CHARACTER_COUNT.
* \param inMeasureChars Specifies whether to compute metrics only for the
* string or for the characters as well.
* \param inString The string to be measured.
* \returns The variable \b GLC_MEASURED_CHARACTER_COUNT if the command
* succeeds, zero otherwise.
* \sa glcGeti() with argument GLC_MEASURED_CHAR_COUNT
* \sa glcGetStringCharMetric()
* \sa glcGetStringMetric()
*/
GLint APIENTRY glcMeasureString(GLboolean inMeasureChars,
const GLCchar* inString)
{
__GLCcontext *ctx = NULL;
GLCchar32* UinString = NULL;
GLint count = 0;
GLint length = 0;
GLboolean isRightToLeft = GL_FALSE;
/* If inString is NULL then there is no point in continuing */
if (!inString)
return 0;
GLC_INIT_THREAD();
/* Verify if the current thread owns a context state */
ctx = GLC_GET_CURRENT_CONTEXT();
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return 0;
}
UinString = __glcConvertToVisualUcs4(ctx, &isRightToLeft, &length, inString);
if (!UinString)
return 0;
count = __glcMeasureCountedString(ctx, inMeasureChars, length, UinString,
isRightToLeft);
return count;
}

659
3rdparty/quesoglc/misc.c vendored Normal file
View File

@ -0,0 +1,659 @@
/* 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$ */
/** \file
* defines miscellaneous utility routines used throughout QuesoGLC.
*/
#include <math.h>
#include "internal.h"
#ifdef DEBUGMODE
GLuint __glcMemAllocCount = 0;
GLuint __glcMemAllocTrigger = 0;
GLboolean __glcMemAllocFailOnce = GL_TRUE;
/* QuesoGLC own allocation and memory management routines */
void* __glcMalloc(size_t size)
{
__glcMemAllocCount++;
if (__glcMemAllocFailOnce) {
if (__glcMemAllocCount == __glcMemAllocTrigger)
return NULL;
}
else if (__glcMemAllocCount >= __glcMemAllocTrigger)
return NULL;
return malloc(size);
}
void __glcFree(void *ptr)
{
/* Not all implementations of free() accept NULL. Moreover this allows to
* detect useless calls.
*/
assert(ptr);
free(ptr);
}
void* __glcRealloc(void *ptr, size_t size)
{
__glcMemAllocCount++;
if (__glcMemAllocFailOnce) {
if (__glcMemAllocCount == __glcMemAllocTrigger)
return NULL;
}
else if (__glcMemAllocCount >= __glcMemAllocTrigger)
return NULL;
return realloc(ptr, size);
}
#endif
#ifndef HAVE_TLS
/* Each thread has to store specific informations so they can be retrieved
* later. __glcGetThreadArea() returns a struct which contains thread specific
* info for GLC.
* If the '__GLCthreadArea' of the current thread does not exist, it is created
* and initialized.
* IMPORTANT NOTE : __glcGetThreadArea() must never use __glcMalloc() and
* __glcFree() since those functions could use the exceptContextStack
* before it is initialized.
*/
__GLCthreadArea* __glcGetThreadArea(void)
{
__GLCthreadArea *area = NULL;
#ifdef __WIN32__
area = (__GLCthreadArea*)TlsGetValue(__glcCommonArea.threadKey);
#else
area = (__GLCthreadArea*)pthread_getspecific(__glcCommonArea.threadKey);
#endif
if (area)
return area;
area = (__GLCthreadArea*)malloc(sizeof(__GLCthreadArea));
if (!area)
return NULL;
area->currentContext = NULL;
area->errorState = GLC_NONE;
area->lockState = 0;
area->exceptionStack.head = NULL;
area->exceptionStack.tail = NULL;
area->failedTry = GLC_NO_EXC;
#ifdef __WIN32__
if (!TlsSetValue(__glcCommonArea.threadKey, (LPVOID)area)) {
free(area);
return NULL;
}
#else
pthread_setspecific(__glcCommonArea.threadKey, (void*)area);
#endif
#ifdef __WIN32__
if (__glcCommonArea.threadID == GetCurrentThreadId())
#else
if (pthread_equal(__glcCommonArea.threadID, pthread_self()))
#endif
__glcThreadArea = area;
return area;
}
/* Raise an error. This function must be called each time the current error
* of the issuing thread must be set
*/
void __glcRaiseError(GLCenum inError)
{
GLCenum error = GLC_NONE;
__GLCthreadArea *area = NULL;
area = GLC_GET_THREAD_AREA();
assert(area);
/* An error can only be raised if the current error value is GLC_NONE.
* However, when inError == GLC_NONE then we must force the current error
* value to GLC_NONE whatever its previous value was.
*/
error = area->errorState;
if (!error || !inError)
area->errorState = inError;
}
/* Get the current context of the issuing thread */
__GLCcontext* __glcGetCurrent(void)
{
__GLCthreadArea *area = NULL;
area = __glcGetThreadArea(); /* Don't use GLC_GET_THREAD_AREA */
assert(area);
return area->currentContext;
}
#endif /* HAVE_TLS */
/* Process the character in order to find a font that maps the code and to
* render the corresponding glyph. Replacement code and '<hexcode>' format
* are issued if necessary. The previous code is updated accordingly.
* 'inCode' must be given in UCS-4 format
*/
void* __glcProcessChar(__GLCcontext *inContext, const GLint inCode,
__GLCcharacter* inPrevCode, const GLboolean inIsRTL,
const __glcProcessCharFunc inProcessCharFunc,
const void* inProcessCharData)
{
GLint repCode = 0;
__GLCfont* font = NULL;
void* ret = NULL;
if (!inCode)
return NULL;
/* Get a font that maps inCode */
font = __glcContextGetFont(inContext, inCode);
if (font) {
/* A font has been found */
if (font != inPrevCode->font)
inPrevCode->code = 0; /* The font has changed, kerning must be disabled */
ret = inProcessCharFunc(inCode, inPrevCode->code, inIsRTL, font, inContext,
inProcessCharData, GL_FALSE);
inPrevCode->code = inCode;
inPrevCode->font = font;
return ret;
}
/* __glcContextGetFont() can not find a font that maps inCode, we then attempt
* to produce an alternate rendering.
*/
/* If the variable GLC_REPLACEMENT_CODE is nonzero, and __glcContextGetFont()
* finds a font that maps the replacement code, we now render the character
* that the replacement code is mapped to
*/
repCode = inContext->stringState.replacementCode;
font = __glcContextGetFont(inContext, repCode);
if (repCode && font) {
if (font != inPrevCode->font)
inPrevCode->code = 0; /* The font has changed, kerning must be disabled */
ret = inProcessCharFunc(repCode, inPrevCode->code, inIsRTL, font, inContext,
inProcessCharData, GL_FALSE);
inPrevCode->code = repCode;
inPrevCode->font = font;
return ret;
}
else {
/* If we get there, we failed to render both the character that inCode maps
* to and the replacement code. Now, we will try to render the character
* sequence "\<hexcode>", where '\' is the character REVERSE SOLIDUS
* (U+5C), '<' is the character LESS-THAN SIGN (U+3C), '>' is the character
* GREATER-THAN SIGN (U+3E), and 'hexcode' is inCode represented as a
* sequence of hexadecimal digits. The sequence has no leading zeros, and
* alphabetic digits are in upper case. The GLC measurement commands treat
* the sequence as a single character.
*/
char buf[11];
GLint i = 0;
GLint n = 0;
/* Check if a font maps hexadecimal digits */
#ifdef _MSC_VER
n = sprintf_s(buf, 11, "\\<%X>", (int)inCode);
if (n < 0) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
#else
n = snprintf(buf, 11, "\\<%X>", (int)inCode);
#endif
for (i = 0; i < n; i++) {
if (!__glcContextGetFont(inContext, buf[i]))
/* The code is not rendered, the previous code is thus left unchanged */
return NULL;
}
/* Render the '\<hexcode>' sequence */
for (i = 0; i < n; i++) {
GLint pos = inIsRTL ? n-i-1 : i;
font = __glcContextGetFont(inContext, buf[pos]);
if (font != inPrevCode->font)
inPrevCode->code = 0; /*The font has changed, kerning must be disabled*/
ret = inProcessCharFunc(buf[pos], inPrevCode->code, inIsRTL, font,
inContext, inProcessCharData, GL_TRUE);
inPrevCode->code = buf[pos];
inPrevCode->font = font;
}
return ret;
}
}
/* Store an 4x4 identity matrix in 'm' */
static void __glcMakeIdentity(GLfloat* m)
{
memset(m, 0, 16 * sizeof(GLfloat));
m[0] = 1.f;
m[5] = 1.f;
m[10] = 1.f;
m[15] = 1.f;
}
/* Invert a 4x4 matrix stored in inMatrix. The result is stored in outMatrix
* It uses the Gauss-Jordan elimination method
*/
static GLboolean __glcInvertMatrix(const GLfloat* inMatrix, GLfloat* outMatrix)
{
int i, j, k, swap;
GLfloat t;
GLfloat temp[4][4];
for (i=0; i<4; i++) {
for (j=0; j<4; j++) {
temp[i][j] = inMatrix[i*4+j];
}
}
__glcMakeIdentity(outMatrix);
for (i = 0; i < 4; i++) {
/* Look for largest element in column */
swap = i;
for (j = i + 1; j < 4; j++) {
if (fabs(temp[j][i]) > fabs(temp[i][i])) {
swap = j;
}
}
if (swap != i) {
/* Swap rows */
for (k = 0; k < 4; k++) {
t = temp[i][k];
temp[i][k] = temp[swap][k];
temp[swap][k] = t;
t = outMatrix[i*4+k];
outMatrix[i*4+k] = outMatrix[swap*4+k];
outMatrix[swap*4+k] = t;
}
}
if (fabs(temp[i][i]) < GLC_EPSILON) {
/* No non-zero pivot. The matrix is singular, which shouldn't
* happen. This means the user gave us a bad matrix.
*/
return GL_FALSE;
}
t = temp[i][i];
for (k = 0; k < 4; k++) {
temp[i][k] /= t;
outMatrix[i*4+k] /= t;
}
for (j = 0; j < 4; j++) {
if (j != i) {
t = temp[j][i];
for (k = 0; k < 4; k++) {
temp[j][k] -= temp[i][k]*t;
outMatrix[j*4+k] -= outMatrix[i*4+k]*t;
}
}
}
}
return GL_TRUE;
}
/* Mutiply two 4x4 matrices, the operands are stored in inMatrix1 and inMatrix2
* The result is stored in outMatrix which can be neither inMatrix1 nor
* inMatrix2.
*/
static void __glcMultMatrices(const GLfloat* inMatrix1,
const GLfloat* inMatrix2, GLfloat* outMatrix)
{
int i, j;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
outMatrix[i*4+j] =
inMatrix1[i*4+0]*inMatrix2[0*4+j] +
inMatrix1[i*4+1]*inMatrix2[1*4+j] +
inMatrix1[i*4+2]*inMatrix2[2*4+j] +
inMatrix1[i*4+3]*inMatrix2[3*4+j];
}
}
}
/* Compute an optimal size for the glyph to be rendered on the screen if no
* display list is planned to be built.
*/
void __glcGetScale(const __GLCcontext* inContext, GLfloat* outTransformMatrix,
GLfloat* outScaleX, GLfloat* outScaleY)
{
int i = 0;
if ((inContext->renderState.renderStyle != GLC_BITMAP)
&& (inContext->renderState.renderStyle != GLC_PIXMAP_QSO)) {
/* Compute the matrix that transforms object space coordinates to viewport
* coordinates. If we plan to use object space coordinates, this matrix is
* set to identity.
*/
GLfloat projectionMatrix[16];
GLfloat modelviewMatrix[16];
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
glGetFloatv(GL_MODELVIEW_MATRIX, modelviewMatrix);
glGetFloatv(GL_PROJECTION_MATRIX, projectionMatrix);
__glcMultMatrices(modelviewMatrix, projectionMatrix, outTransformMatrix);
if (!inContext->enableState.glObjects && inContext->enableState.hinting) {
GLfloat rs[16], m[16];
/* Get the scale factors in each X, Y and Z direction */
GLfloat sx = sqrt(outTransformMatrix[0] * outTransformMatrix[0]
+outTransformMatrix[1] * outTransformMatrix[1]
+outTransformMatrix[2] * outTransformMatrix[2]);
GLfloat sy = sqrt(outTransformMatrix[4] * outTransformMatrix[4]
+outTransformMatrix[5] * outTransformMatrix[5]
+outTransformMatrix[6] * outTransformMatrix[6]);
GLfloat sz = sqrt(outTransformMatrix[8] * outTransformMatrix[8]
+outTransformMatrix[9] * outTransformMatrix[9]
+outTransformMatrix[10] * outTransformMatrix[10]);
GLfloat x = 0., y = 0.;
memset(rs, 0, 16 * sizeof(GLfloat));
rs[15] = 1.;
for (i = 0; i < 3; i++) {
rs[0+4*i] = outTransformMatrix[0+4*i] / sx;
rs[1+4*i] = outTransformMatrix[1+4*i] / sy;
rs[2+4*i] = outTransformMatrix[2+4*i] / sz;
}
if (!__glcInvertMatrix(rs, rs)) {
*outScaleX = 0.f;
*outScaleY = 0.f;
return;
}
__glcMultMatrices(rs, outTransformMatrix, m);
x = ((m[0] + m[12])/(m[3] + m[15]) - m[12]/m[15]) * viewport[2] * 0.5;
y = ((m[1] + m[13])/(m[3] + m[15]) - m[13]/m[15]) * viewport[3] * 0.5;
*outScaleX = sqrt(x*x+y*y);
x = ((m[4] + m[12])/(m[7] + m[15]) - m[12]/m[15]) * viewport[2] * 0.5;
y = ((m[5] + m[13])/(m[7] + m[15]) - m[13]/m[15]) * viewport[3] * 0.5;
*outScaleY = sqrt(x*x+y*y);
}
else {
*outScaleX = GLC_POINT_SIZE;
*outScaleY = GLC_POINT_SIZE;
}
}
else {
GLfloat determinant = 0., norm = 0.;
GLfloat *transform = inContext->bitmapMatrix;
/* Compute the norm of the transformation matrix */
for (i = 0; i < 4; i++) {
if (fabsf(transform[i]) > norm)
norm = fabsf(transform[i]);
}
determinant = transform[0] * transform[3] - transform[1] * transform[2];
/* If the transformation is degenerated, nothing needs to be rendered */
if (fabsf(determinant) < norm * GLC_EPSILON) {
*outScaleX = 0.f;
*outScaleY = 0.f;
return;
}
if (inContext->enableState.hinting) {
*outScaleX = sqrt(transform[0]*transform[0]+transform[1]*transform[1]);
*outScaleY = sqrt(transform[2]*transform[2]+transform[3]*transform[3]);
}
else {
*outScaleX = GLC_POINT_SIZE;
*outScaleY = GLC_POINT_SIZE;
}
}
}
/* Save the GL State in a structure */
void __glcSaveGLState(__GLCglState* inGLState, const __GLCcontext* inContext,
const GLboolean inAll)
{
if (inAll || inContext->renderState.renderStyle == GLC_TEXTURE) {
inGLState->blend = glIsEnabled(GL_BLEND);
glGetIntegerv(GL_BLEND_SRC, &inGLState->blendSrc);
glGetIntegerv(GL_BLEND_DST, &inGLState->blendDst);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &inGLState->textureID);
glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,
&inGLState->textureEnvMode);
if ((inAll || !inContext->enableState.glObjects)
&& GLEW_ARB_pixel_buffer_object)
glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING_ARB,
&inGLState->pixelBufferObjectID);
}
if (inAll || (inContext->renderState.renderStyle == GLC_BITMAP)
|| (inContext->renderState.renderStyle == GLC_PIXMAP_QSO)) {
glGetIntegerv(GL_UNPACK_LSB_FIRST, &inGLState->unpackLsbFirst);
glGetIntegerv(GL_UNPACK_ROW_LENGTH, &inGLState->unpackRowLength);
glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &inGLState->unpackSkipPixels);
glGetIntegerv(GL_UNPACK_SKIP_ROWS, &inGLState->unpackSkipRows);
glGetIntegerv(GL_UNPACK_ALIGNMENT, &inGLState->unpackAlignment);
if (inAll || (inContext->renderState.renderStyle == GLC_PIXMAP_QSO)) {
if (!inAll) { /* if inAll, already saved in GLC_TEXTURE's block */
inGLState->blend = glIsEnabled(GL_BLEND);
glGetIntegerv(GL_BLEND_SRC, &inGLState->blendSrc);
glGetIntegerv(GL_BLEND_DST, &inGLState->blendDst);
}
glGetFloatv(GL_RED_BIAS, &inGLState->colorBias[0]);
glGetFloatv(GL_GREEN_BIAS, &inGLState->colorBias[1]);
glGetFloatv(GL_BLUE_BIAS, &inGLState->colorBias[2]);
glGetFloatv(GL_ALPHA_BIAS, &inGLState->colorBias[3]);
glGetFloatv(GL_RED_SCALE, &inGLState->colorScale[0]);
glGetFloatv(GL_GREEN_SCALE, &inGLState->colorScale[1]);
glGetFloatv(GL_BLUE_SCALE, &inGLState->colorScale[2]);
glGetFloatv(GL_ALPHA_SCALE, &inGLState->colorScale[3]);
}
}
if ((inAll || (inContext->enableState.glObjects
&& (inContext->renderState.renderStyle != GLC_BITMAP)
&& (inContext->renderState.renderStyle != GLC_PIXMAP_QSO)))
&& GLEW_ARB_vertex_buffer_object) {
glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB,
&inGLState->vertexBufferObjectID);
if (inAll || (inContext->renderState.renderStyle == GLC_TRIANGLE))
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB,
&inGLState->elementBufferObjectID);
}
if (inAll || (inContext->renderState.renderStyle == GLC_TRIANGLE
&& inContext->enableState.glObjects
&& inContext->enableState.extrude))
inGLState->normalize = glIsEnabled(GL_NORMALIZE);
if (inAll || inContext->renderState.renderStyle == GLC_LINE
|| inContext->renderState.renderStyle == GLC_TRIANGLE
|| (inContext->renderState.renderStyle == GLC_TEXTURE
&& inContext->enableState.glObjects
&& GLEW_ARB_vertex_buffer_object)) {
inGLState->vertexArray = glIsEnabled(GL_VERTEX_ARRAY);
glGetIntegerv(GL_VERTEX_ARRAY_SIZE, &inGLState->vertexArraySize);
glGetIntegerv(GL_VERTEX_ARRAY_TYPE, &inGLState->vertexArrayType);
glGetIntegerv(GL_VERTEX_ARRAY_STRIDE, &inGLState->vertexArrayStride);
glGetPointerv(GL_VERTEX_ARRAY_POINTER, &inGLState->vertexArrayPointer);
inGLState->normalArray = glIsEnabled(GL_NORMAL_ARRAY);
inGLState->colorArray = glIsEnabled(GL_COLOR_ARRAY);
inGLState->indexArray = glIsEnabled(GL_INDEX_ARRAY);
inGLState->texCoordArray = glIsEnabled(GL_TEXTURE_COORD_ARRAY);
if (inAll || inContext->renderState.renderStyle == GLC_TEXTURE) {
glGetIntegerv(GL_TEXTURE_COORD_ARRAY_SIZE, &inGLState->texCoordArraySize);
glGetIntegerv(GL_TEXTURE_COORD_ARRAY_TYPE, &inGLState->texCoordArrayType);
glGetIntegerv(GL_TEXTURE_COORD_ARRAY_STRIDE,
&inGLState->texCoordArrayStride);
glGetPointerv(GL_TEXTURE_COORD_ARRAY_POINTER,
&inGLState->texCoordArrayPointer);
}
inGLState->edgeFlagArray = glIsEnabled(GL_EDGE_FLAG_ARRAY);
}
}
/* Restore the GL State from a structure */
void __glcRestoreGLState(const __GLCglState* inGLState,
const __GLCcontext* inContext, const GLboolean inAll)
{
if (inAll || inContext->renderState.renderStyle == GLC_TEXTURE) {
if (!inGLState->blend)
glDisable(GL_BLEND);
glBlendFunc(inGLState->blendSrc, inGLState->blendDst);
glBindTexture(GL_TEXTURE_2D, inGLState->textureID);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, inGLState->textureEnvMode);
if ((inAll || !inContext->enableState.glObjects)
&& GLEW_ARB_pixel_buffer_object)
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB,
inGLState->pixelBufferObjectID);
}
if ((inAll || (inContext->renderState.renderStyle == GLC_BITMAP)
|| (inContext->renderState.renderStyle == GLC_PIXMAP_QSO))) {
glPixelStorei(GL_UNPACK_LSB_FIRST, inGLState->unpackLsbFirst);
glPixelStorei(GL_UNPACK_ROW_LENGTH, inGLState->unpackRowLength);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, inGLState->unpackSkipPixels);
glPixelStorei(GL_UNPACK_SKIP_ROWS, inGLState->unpackSkipRows);
glPixelStorei(GL_UNPACK_ALIGNMENT, inGLState->unpackAlignment);
if (inAll || (inContext->renderState.renderStyle == GLC_PIXMAP_QSO)) {
if (!inAll) { /* if inAll, already restored in GLC_TEXTURE's block */
if (!inGLState->blend)
glDisable(GL_BLEND);
glBlendFunc(inGLState->blendSrc, inGLState->blendDst);
}
glPixelTransferf(GL_RED_BIAS, inGLState->colorBias[0]);
glPixelTransferf(GL_GREEN_BIAS, inGLState->colorBias[1]);
glPixelTransferf(GL_BLUE_BIAS, inGLState->colorBias[2]);
glPixelTransferf(GL_ALPHA_BIAS, inGLState->colorBias[3]);
glPixelTransferf(GL_RED_SCALE, inGLState->colorScale[0]);
glPixelTransferf(GL_GREEN_SCALE, inGLState->colorScale[1]);
glPixelTransferf(GL_BLUE_SCALE, inGLState->colorScale[2]);
glPixelTransferf(GL_ALPHA_SCALE, inGLState->colorScale[3]);
}
}
if ((inAll || (inContext->enableState.glObjects
&& (inContext->renderState.renderStyle != GLC_BITMAP)
&& (inContext->renderState.renderStyle != GLC_PIXMAP_QSO)))
&& GLEW_ARB_vertex_buffer_object) {
glBindBufferARB(GL_ARRAY_BUFFER_ARB, inGLState->vertexBufferObjectID);
if (inAll || (inContext->renderState.renderStyle == GLC_TRIANGLE))
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
inGLState->elementBufferObjectID);
}
if (inAll || (inContext->renderState.renderStyle == GLC_TRIANGLE
&& inContext->enableState.glObjects
&& inContext->enableState.extrude))
if (!inGLState->normalize)
glDisable(GL_NORMALIZE);
if (inAll || inContext->renderState.renderStyle == GLC_LINE
|| inContext->renderState.renderStyle == GLC_TRIANGLE
|| (inContext->renderState.renderStyle == GLC_TEXTURE
&& inContext->enableState.glObjects
&& GLEW_ARB_vertex_buffer_object)) {
if (!inGLState->vertexArray)
glDisableClientState(GL_VERTEX_ARRAY);
glVertexPointer(inGLState->vertexArraySize, inGLState->vertexArrayType,
inGLState->vertexArrayStride,
inGLState->vertexArrayPointer);
if (!inGLState->normalArray)
glDisableClientState(GL_NORMAL_ARRAY);
if (!inGLState->colorArray)
glDisableClientState(GL_COLOR_ARRAY);
if (!inGLState->indexArray)
glDisableClientState(GL_INDEX_ARRAY);
if (!inGLState->texCoordArray)
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
if (inAll || inContext->renderState.renderStyle == GLC_TEXTURE)
glTexCoordPointer(inGLState->texCoordArraySize,
inGLState->texCoordArrayType,
inGLState->texCoordArrayStride,
inGLState->texCoordArrayPointer);
if (!inGLState->edgeFlagArray)
glDisableClientState(GL_EDGE_FLAG_ARRAY);
}
}
#ifdef GLEW_MX
/* Function for GLEW so that it can get a context */
GLEWContext* __glcGetGlewContext(void)
{
__GLCcontext* ctx = GLC_GET_CURRENT_CONTEXT();
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return NULL;
}
return &ctx->glewContext;
}
#endif
/* This function initializes the thread management of QuesoGLC when TLS is not
* available. It must be called once (see the macro GLC_INIT_THREAD)
*/
#ifndef HAVE_TLS
void __glcInitThread(void) {
#ifdef __WIN32__
__glcCommonArea.threadID = GetCurrentThreadId();
#else
__glcCommonArea.threadID = pthread_self();
#endif /* __WIN32__ */
}
#endif /* HAVE_TLS */

220
3rdparty/quesoglc/oarray.c vendored Normal file
View File

@ -0,0 +1,220 @@
/* 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$ */
/** \file
* defines the object __GLCarray which is an array which size can grow as some
* new elements are added to it.
*/
/* This object heavily uses the realloc() which means that it must not be
* assumed that the data are always stored at the same address. The safer way
* to handle that is to *always* assume the address of the data has changed
* *every* time a method of __GLCarray is called ; whatever the method is.
*/
#include "internal.h"
#define GLC_ARRAY_BLOCK_SIZE 16
/* Constructor of the object : it allocates memory and initializes the member
* of the new object.
* The user must give the size of an element of the array.
*/
__GLCarray* __glcArrayCreate(const int inElementSize)
{
__GLCarray* This = NULL;
This = (__GLCarray*)__glcMalloc(sizeof(__GLCarray));
if (!This) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
memset(This, 0, sizeof(__GLCarray));
This->data = (char*)__glcMalloc(GLC_ARRAY_BLOCK_SIZE * inElementSize);
if (!This->data) {
__glcFree(This);
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
This->allocated = GLC_ARRAY_BLOCK_SIZE;
This->elementSize = inElementSize;
return This;
}
/* Destructor of the object */
void __glcArrayDestroy(__GLCarray* This)
{
if (This->data) {
assert(This->allocated);
__glcFree(This->data);
}
__glcFree(This);
}
/* Allocate a new block of elements in the array 'This'. The function returns
* NULL if it fails and raises an error accordingly. However the original
* array is not lost and is kept untouched.
*/
static __GLCarray* __glcArrayUpdateSize(__GLCarray* This)
{
char* data = NULL;
data = (char*)__glcRealloc(This->data,
(This->allocated + GLC_ARRAY_BLOCK_SIZE) * This->elementSize);
if (!data) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
This->data = data;
This->allocated += GLC_ARRAY_BLOCK_SIZE;
return This;
}
/* Append a value to the array. The function may allocate some more room if
* necessary
*/
__GLCarray* __glcArrayAppend(__GLCarray* This, const void* inValue)
{
/* Update the room if needed */
if (This->length == This->allocated) {
if (!__glcArrayUpdateSize(This))
return NULL;
}
/* Append the new element */
memcpy(This->data + This->length*This->elementSize, inValue,
This->elementSize);
This->length++;
return This;
}
/* Insert a value in the array at the rank inRank. The function may allocate
* some more room if necessary
*/
__GLCarray* __glcArrayInsert(__GLCarray* This, const int inRank,
const void* inValue)
{
/* Update the room if needed */
if (This->length == This->allocated) {
if (!__glcArrayUpdateSize(This))
return NULL;
}
/* Insert the new element */
if (This->length > inRank)
memmove(This->data + (inRank+1) * This->elementSize,
This->data + inRank * This->elementSize,
(This->length - inRank) * This->elementSize);
memcpy(This->data + inRank*This->elementSize, inValue, This->elementSize);
This->length++;
return This;
}
/* Remove an element from the array. For performance reasons, this function
* does not release memory.
*/
void __glcArrayRemove(__GLCarray* This, const int inRank)
{
if (inRank < This->length-1)
memmove(This->data + inRank * This->elementSize,
This->data + (inRank+1) * This->elementSize,
(This->length - inRank - 1) * This->elementSize);
This->length--;
}
/* Insert some room in the array at rank 'inRank' and leave it as is.
* The difference between __glcArrayInsertCell() and __glcArrayInsert() is that
* __glcArrayInsert() copy a value in the new element array while
* __glcArrayInsertCell() does not. Moreover __glcArrayInsertCell() can insert
* several cells in a row which is faster than calling __glcArrayInsert()
* several times in a row.
* This function is used to optimize performance in certain configurations.
*/
void* __glcArrayInsertCell(__GLCarray* This, const int inRank,
const int inCells)
{
char* newCell = NULL;
assert(inCells < GLC_ARRAY_BLOCK_SIZE);
if ((This->length + inCells) > This->allocated) {
if (!__glcArrayUpdateSize(This))
return NULL;
}
newCell = This->data + inRank * This->elementSize;
if (This->length > inRank)
memmove(newCell + inCells * This->elementSize, newCell,
(This->length - inRank) * This->elementSize);
This->length += inCells;
return (void*)newCell;
}
/* Duplicate an array */
__GLCarray* __glcArrayDuplicate(__GLCarray* This)
{
__GLCarray* duplicate = NULL;
duplicate = (__GLCarray*)__glcMalloc(sizeof(__GLCarray));
if (!duplicate) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
memcpy(duplicate, This, sizeof(__GLCarray));
duplicate->data = (char*)__glcMalloc(This->allocated * This->elementSize);
if (!duplicate->data) {
__glcFree(duplicate);
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
memcpy(duplicate->data, This->data, This->allocated * This->elementSize);
return duplicate;
}

51
3rdparty/quesoglc/oarray.h vendored Normal file
View File

@ -0,0 +1,51 @@
/* 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$ */
/** \file
* header of the object __GLCarray which is an array which size can grow as
* some new elements are added to it.
*/
#ifndef __glc_oarray_h
#define __glc_oarray_h
#define GLC_ARRAY_DATA(array) ((array)->data)
#define GLC_ARRAY_LENGTH(array) ((array)->length)
#define GLC_ARRAY_SIZE(array) (((array)->length) * ((array)->elementSize))
typedef struct __GLCarrayRec __GLCarray;
struct __GLCarrayRec {
char* data;
int allocated;
int length;
int elementSize;
};
__GLCarray* __glcArrayCreate(int inElementSize);
void __glcArrayDestroy(__GLCarray* This);
__GLCarray* __glcArrayAppend(__GLCarray* This, const void* inValue);
__GLCarray* __glcArrayInsert(__GLCarray* This, const int inRank,
const void* inValue);
void __glcArrayRemove(__GLCarray* This, const int inRank);
void* __glcArrayInsertCell(__GLCarray* This, const int inRank,
const int inCells);
__GLCarray* __glcArrayDuplicate(__GLCarray* This);
#endif

599
3rdparty/quesoglc/ocharmap.c vendored Normal file
View File

@ -0,0 +1,599 @@
/* QuesoGLC
* A free implementation of the OpenGL Character Renderer (GLC)
* Copyright (c) 2002, 2004-2008, 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$ */
/** \file
* defines the object __GLCcharMap which manage the charmaps of both the fonts
* and the masters. One of the purpose of this object is to encapsulate the
* FcCharSet structure from Fontconfig and to add it some more functionalities.
* It also allows to centralize the character map management for easier
* maintenance.
*/
#include "internal.h"
/* Constructor of the object : it allocates memory and initializes the member
* of the new object.
* The user must give the FcPattern of the font or the master (which may be NULL
* in which case the character map will be empty).
*/
__GLCcharMap* __glcCharMapCreate(const __GLCmaster* inMaster,
const __GLCcontext* inContext)
{
__GLCcharMap* This = NULL;
assert(inContext);
This = (__GLCcharMap*)__glcMalloc(sizeof(__GLCcharMap));
if (!This) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
memset(This, 0, sizeof(__GLCcharMap));
This->charSet = FcCharSetCreate();
if (!This->charSet) {
__glcRaiseError(GLC_RESOURCE_ERROR);
__glcFree(This);
return NULL;
}
if (inMaster) {
FcCharSet* charSet = NULL;
FcFontSet* fontSet = NULL;
int i = 0;
FcObjectSet* objectSet = NULL;
FcPattern* pattern = FcPatternCreate();
if (!pattern) {
__glcRaiseError(GLC_RESOURCE_ERROR);
FcCharSetDestroy(This->charSet);
__glcFree(This);
return NULL;
}
objectSet = FcObjectSetBuild(FC_FAMILY, FC_FOUNDRY, FC_SPACING, FC_OUTLINE,
FC_CHARSET, NULL);
if (!objectSet) {
__glcRaiseError(GLC_RESOURCE_ERROR);
FcPatternDestroy(pattern);
FcCharSetDestroy(This->charSet);
__glcFree(This);
return NULL;
}
fontSet = FcFontList(inContext->config, pattern, objectSet);
FcObjectSetDestroy(objectSet);
FcPatternDestroy(pattern);
if (!fontSet) {
__glcRaiseError(GLC_RESOURCE_ERROR);
FcCharSetDestroy(This->charSet);
__glcFree(This);
return NULL;
}
for (i = 0; i < fontSet->nfont; i++) {
FcChar8* family = NULL;
int fixed = 0;
FcChar8* foundry = NULL;
FcBool outline = FcFalse;
FcBool equal = FcFalse;
#ifdef DEBUGMODE
FcResult result = FcResultMatch;
result = FcPatternGetBool(fontSet->fonts[i], FC_OUTLINE, 0, &outline);
assert(result != FcResultTypeMismatch);
#else
FcPatternGetBool(fontSet->fonts[i], FC_OUTLINE, 0, &outline);
#endif
/* Check whether the glyphs are outlines */
if (!outline)
continue;
#ifdef DEBUGMODE
result = FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &family);
assert(result != FcResultTypeMismatch);
result = FcPatternGetString(fontSet->fonts[i], FC_FOUNDRY, 0, &foundry);
assert(result != FcResultTypeMismatch);
result = FcPatternGetInteger(fontSet->fonts[i], FC_SPACING, 0, &fixed);
assert(result != FcResultTypeMismatch);
#else
FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &family);
FcPatternGetString(fontSet->fonts[i], FC_FOUNDRY, 0, &foundry);
FcPatternGetInteger(fontSet->fonts[i], FC_SPACING, 0, &fixed);
#endif
if (foundry)
pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, family,
FC_FOUNDRY, FcTypeString, foundry, FC_SPACING,
FcTypeInteger, fixed, NULL);
else
pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, family,
FC_SPACING, FcTypeInteger, fixed, NULL);
if (!pattern) {
__glcRaiseError(GLC_RESOURCE_ERROR);
FcCharSetDestroy(This->charSet);
FcFontSetDestroy(fontSet);
__glcFree(This);
return NULL;
}
equal = FcPatternEqual(pattern, inMaster->pattern);
FcPatternDestroy(pattern);
if (equal) {
FcCharSet* newCharSet = NULL;
#ifdef DEBUGMODE
result = FcPatternGetCharSet(fontSet->fonts[i], FC_CHARSET, 0,
&charSet);
assert(result != FcResultTypeMismatch);
#else
FcPatternGetCharSet(fontSet->fonts[i], FC_CHARSET, 0, &charSet);
#endif
newCharSet = FcCharSetUnion(This->charSet, charSet);
if (!newCharSet) {
__glcRaiseError(GLC_RESOURCE_ERROR);
FcCharSetDestroy(This->charSet);
FcFontSetDestroy(fontSet);
__glcFree(This);
return NULL;
}
FcCharSetDestroy(This->charSet);
This->charSet = newCharSet;
}
}
FcFontSetDestroy(fontSet);
}
/* The array 'map' will contain the actual character map */
This->map = __glcArrayCreate(sizeof(__GLCcharMapElement));
if (!This->map) {
FcCharSetDestroy(This->charSet);
__glcFree(This);
return NULL;
}
return This;
}
/* Destructor of the object */
void __glcCharMapDestroy(__GLCcharMap* This)
{
if (This->map)
__glcArrayDestroy(This->map);
FcCharSetDestroy(This->charSet);
__glcFree(This);
}
/* Add a given character to the character map. Afterwards, the character map
* will associate the glyph 'inGlyph' to the Unicode codepoint 'inCode'.
*/
void __glcCharMapAddChar(__GLCcharMap* This, const GLint inCode,
__GLCglyph* inGlyph)
{
__GLCcharMapElement* element = NULL;
__GLCcharMapElement* newElement = NULL;
int start = 0, middle = 0, end = 0;
assert(This);
assert(This->map);
assert(GLC_ARRAY_DATA(This->map));
assert(inCode >= 0);
/* Characters are stored by ascending order of their mapped code */
element = (__GLCcharMapElement*)GLC_ARRAY_DATA(This->map);
end = GLC_ARRAY_LENGTH(This->map) - 1;
/* Parse the array by dichotomy to look for the place where to add the new
* character.
*/
while (start <= end) {
middle = (start + end) >> 1;
/* If the character map already contains the new character then update the
* glyph then return.
*/
if (element[middle].mappedCode == (GLCulong)inCode) {
element[middle].glyph = inGlyph;
return;
}
else if (element[middle].mappedCode > (GLCulong)inCode)
end = middle - 1;
else
start = middle + 1;
}
/* If we have reached the end of the array then update the rank 'middle'
* accordingly.
*/
if ((end >= 0) && (element[middle].mappedCode < (GLCulong)inCode))
middle++;
/* Insert the new character in the character map */
newElement = (__GLCcharMapElement*)__glcArrayInsertCell(This->map, middle, 1);
if (!newElement)
return;
newElement->mappedCode = inCode;
newElement->glyph = inGlyph;
return;
}
/* Remove a character from the character map */
void __glcCharMapRemoveChar(__GLCcharMap* This, const GLint inCode)
{
__GLCcharMapElement* element = NULL;
int start = 0, middle = 0, end = 0;
assert(This);
assert(This->map);
assert(GLC_ARRAY_DATA(This->map));
assert(inCode >= 0);
/* Characters are stored by ascending order of their mapped code */
element = (__GLCcharMapElement*)GLC_ARRAY_DATA(This->map);
end = GLC_ARRAY_LENGTH(This->map) - 1;
/* Parse the array by dichotomy to look for the place where to add the new
* character.
*/
while (start <= end) {
middle = (start + end) >> 1;
/* When the character is found remove it from the array and return */
if (element[middle].mappedCode == (GLCulong)inCode) {
__glcArrayRemove(This->map, middle);
break;
}
else if (element[middle].mappedCode > (GLCulong)inCode)
end = middle - 1;
else
start = middle + 1;
}
}
/* Get the Unicode character name of the character which codepoint is inCode.
* Note : since the character maps of the fonts can be altered, this function
* can return 'LATIN CAPITAL LETTER B' whereas inCode contained 65 (which is
* the Unicode code point of 'LATIN CAPITAL LETTER A').
*/
const GLCchar8* __glcCharMapGetCharName(const __GLCcharMap* This,
const GLint inCode)
{
__GLCcharMapElement* element = NULL;
int start = 0, middle = 0, end = 0;
GLint code = 0;
assert(This);
assert(This->map);
assert(GLC_ARRAY_DATA(This->map));
assert(inCode >= 0);
/* Characters are stored by ascending order of their mapped code */
element = (__GLCcharMapElement*)GLC_ARRAY_DATA(This->map);
end = GLC_ARRAY_LENGTH(This->map) - 1;
/* Parse the array by dichotomy to look for the Unicode codepoint that the
* request character maps to.
*/
while (start <= end) {
middle = (start + end) >> 1;
if (element[middle].mappedCode == (GLCulong)inCode) {
code = element[middle].glyph->codepoint;
break;
}
else if (element[middle].mappedCode > (GLCulong)inCode)
end = middle - 1;
else
start = middle + 1;
}
if (!code) {
if (FcCharSetHasChar(This->charSet, inCode))
code = inCode;
else
return NULL;
}
return __glcNameFromCode(code);
}
/* Get the glyph corresponding to codepoint 'inCode' */
__GLCglyph* __glcCharMapGetGlyph(const __GLCcharMap* This, const GLint inCode)
{
__GLCcharMapElement* element = NULL;
int start = 0, middle = 0, end = 0;
assert(This);
assert(This->map);
assert(GLC_ARRAY_DATA(This->map));
assert(inCode >= 0);
/* Characters are stored by ascending order of their mapped code */
element = (__GLCcharMapElement*)GLC_ARRAY_DATA(This->map);
end = GLC_ARRAY_LENGTH(This->map) - 1;
/* Parse the array by dichotomy to find the glyph of the requested
* character.
*/
while (start <= end) {
middle = (start + end) >> 1;
if (element[middle].mappedCode == (GLCulong)inCode)
/* When the character is found return the corresponding glyph */
return element[middle].glyph;
else if (element[middle].mappedCode > (GLCulong)inCode)
end = middle - 1;
else
start = middle + 1;
}
/* No glyph has been defined yet for the requested character */
return NULL;
}
/* Check if a character is in the character map */
GLboolean __glcCharMapHasChar(const __GLCcharMap* This, const GLint inCode)
{
__GLCcharMapElement* element = NULL;
int start = 0, middle = 0, end = 0;
assert(This);
assert(This->map);
assert(GLC_ARRAY_DATA(This->map));
assert(inCode >= 0);
/* Characters are stored by ascending order of their mapped code */
element = (__GLCcharMapElement*)GLC_ARRAY_DATA(This->map);
end = GLC_ARRAY_LENGTH(This->map) - 1;
/* Parse the array by dichotomy to find the requested character. */
while (start <= end) {
middle = (start + end) >> 1;
/* The character has been found : return GL_TRUE */
if (element[middle].mappedCode == (GLCulong)inCode)
return GL_TRUE;
else if (element[middle].mappedCode > (GLCulong)inCode)
end = middle - 1;
else
start = middle + 1;
}
/* Check if the character identified by inCode exists in the font */
return FcCharSetHasChar(This->charSet, inCode);
}
/* This function counts the number of bits that are set in c1
* Copied from Keith Packard's fontconfig
*/
static GLCchar32 __glcCharSetPopCount(const GLCchar32 c1)
{
/* hackmem 169 */
GLCchar32 c2 = (c1 >> 1) & 033333333333;
c2 = c1 - c2 - ((c2 >> 1) & 033333333333);
return (((c2 + (c2 >> 3)) & 030707070707) % 077);
}
/* Get the name of the character which is stored at rank 'inIndex' in the
* FcCharSet of the face.
*/
const GLCchar8* __glcCharMapGetCharNameByIndex(const __GLCcharMap* This,
const GLint inIndex)
{
int i = 0;
int j = 0;
/* In Fontconfig the map in FcCharSet is organized as an array of integers.
* Each integer corresponds to a page of 32 characters (since it uses 32 bits
* integer). If a bit is set then the corresponding character is in the
* character map otherwise it is not.
* In order not to store pages of 0's, the character map begins at the
* character which codepoint is 'base'.
* Pages are also gathered in blocks of 'FC_CHARSET_MAP_SIZE' pages in order
* to prevent Fontconfig to store heaps of 0's if the character codes are
* sparsed.
*
* The codepoint of a character located at bit 'j' of page 'i' is :
* 'base + (i << 5) + j'.
*/
GLCchar32 map[FC_CHARSET_MAP_SIZE];
GLCchar32 next = 0;
GLCchar32 base = 0;
GLCchar32 count = 1;
GLCchar32 value = 0;
assert(This);
assert(inIndex >= 0);
base = FcCharSetFirstPage(This->charSet, map, &next);
do {
/* Parse the pages in FcCharSet */
for (i = 0; i < FC_CHARSET_MAP_SIZE; i++) {
/* Get the number of character located in the current page */
value = __glcCharSetPopCount(map[i]);
/* Check if the character we are looking for is in the current page */
if (count + value >= (GLCchar32)inIndex) {
for (j = 0; j < 32; j++) {
/* Parse the page bit by bit */
if ((map[i] >> j) & 1) {
count++; /* A character is set at bit j */
/* Check if we have reached the rank inIndex */
if (count == (GLCchar32)inIndex) {
/* Get the character name */
return __glcNameFromCode(base + (i << 5) + j);
}
}
}
}
/* Add the number of characters of the current page to the count and
* check the next page.
*/
count += value;
}
/* The current block is finished, check the next one */
base = FcCharSetNextPage(This->charSet, map, &next);
} while (base != FC_CHARSET_DONE);
/* The character has not been found */
__glcRaiseError(GLC_PARAMETER_ERROR);
return GLC_NONE;
}
/* Get the maximum mapped code of a character set */
GLint __glcCharMapGetMaxMappedCode(const __GLCcharMap* This)
{
GLCchar32 base = 0;
GLCchar32 next = 0;
GLCchar32 prev_base = 0;
GLCchar32 map[FC_CHARSET_MAP_SIZE];
int i = 0, j = 0;
GLCulong maxMappedCode = 0;
__GLCcharMapElement* element = NULL;
int length = 0;
assert(This);
assert(This->map);
assert(GLC_ARRAY_DATA(This->map));
/* Look for the last block of pages of the FcCharSet structure */
base = FcCharSetFirstPage(This->charSet, map, &next);
assert(base != FC_CHARSET_DONE);
do {
prev_base = base;
base = FcCharSetNextPage(This->charSet, map, &next);
} while (base != FC_CHARSET_DONE);
/* Parse the pages in descending order to find the last page that contains
* one character.
*/
for (i = FC_CHARSET_MAP_SIZE - 1; i >= 0; i--)
if (map[i]) break;
/* If the map contains no char then something went wrong... */
assert(i >= 0);
/* Parse the bits of the last page in descending order to find the last
* character of the page
*/
for (j = 31; j >= 0; j--)
if ((map[i] >> j) & 1) break;
assert(j >= 0);
/* Calculate the max mapped code */
maxMappedCode = prev_base + (i << 5) + j;
/* Check that a code greater than the one found in the FcCharSet is not
* stored in the array 'map'.
*/
element = (__GLCcharMapElement*)GLC_ARRAY_DATA(This->map);
length = GLC_ARRAY_LENGTH(This->map);
/* Return the greater of the code of both the FcCharSet and the array 'map'*/
if (length)
return element[length-1].mappedCode > maxMappedCode ?
element[length-1].mappedCode : maxMappedCode;
else
return maxMappedCode;
}
/* Get the minimum mapped code of a character set */
GLint __glcCharMapGetMinMappedCode(const __GLCcharMap* This)
{
GLCchar32 base = 0;
GLCchar32 next = 0;
GLCchar32 map[FC_CHARSET_MAP_SIZE];
int i = 0, j = 0;
GLCulong minMappedCode = 0xffffffff;
__GLCcharMapElement* element = NULL;
int length = 0;
assert(This);
assert(This->map);
assert(GLC_ARRAY_DATA(This->map));
/* Get the first block of pages of the FcCharSet structure */
base = FcCharSetFirstPage(This->charSet, map, &next);
assert(base != FC_CHARSET_DONE);
/* Parse the pages in ascending order to find the first page that contains
* one character.
*/
for (i = 0; i < FC_CHARSET_MAP_SIZE; i++)
if (map[i]) break;
/* If the map contains no char then something went wrong... */
assert(i >= 0);
/* Parse the bits of the first page in ascending order to find the first
* character of the page
*/
for (j = 0; j < 32; j++)
if ((map[i] >> j) & 1) break;
assert(j < 32);
minMappedCode = base + (i << 5) + j;
/* Check that a code lower than the one found in the FcCharSet is not
* stored in the array 'map'.
*/
element = (__GLCcharMapElement*)GLC_ARRAY_DATA(This->map);
length = GLC_ARRAY_LENGTH(This->map);
/* Return the lower of the code of both the FcCharSet and the array 'map'*/
if (length)
return element[0].mappedCode < minMappedCode ?
element[0].mappedCode : minMappedCode;
else
return minMappedCode;
}

67
3rdparty/quesoglc/ocharmap.h vendored Normal file
View File

@ -0,0 +1,67 @@
/* QuesoGLC
* A free implementation of the OpenGL Character Renderer (GLC)
* Copyright (c) 2002, 2004-2008, 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$ */
/** \file
* header of the object __GLCcharMap which manage the charmaps of both the fonts
* and the masters.
*/
#ifndef __glc_ocharmap_h
#define __glc_ocharmap_h
#include "ocontext.h"
#include "oglyph.h"
typedef struct __GLCcharMapElementRec __GLCcharMapElement;
typedef struct __GLCcharMapRec __GLCcharMap;
typedef struct __GLCmasterRec __GLCmaster;
struct __GLCcharMapElementRec {
GLCulong mappedCode;
__GLCglyph* glyph;
};
struct __GLCcharMapRec {
FcCharSet* charSet;
__GLCarray* map;
};
__GLCcharMap* __glcCharMapCreate(const __GLCmaster* inMaster,
const __GLCcontext* inContext);
void __glcCharMapDestroy(__GLCcharMap* This);
void __glcCharMapAddChar(__GLCcharMap* This, const GLint inCode,
__GLCglyph* inGlyph);
void __glcCharMapRemoveChar(__GLCcharMap* This, const GLint inCode);
const GLCchar8* __glcCharMapGetCharName(const __GLCcharMap* This,
const GLint inCode);
__GLCglyph* __glcCharMapGetGlyph(const __GLCcharMap* This, const GLint inCode);
GLboolean __glcCharMapHasChar(const __GLCcharMap* This, const GLint inCode);
const GLCchar8* __glcCharMapGetCharNameByIndex(const __GLCcharMap* This,
const GLint inIndex);
/* Return the number of characters in the character map */
static inline GLint __glcCharMapGetCount(const __GLCcharMap* This)
{
assert(This);
assert(This->charSet);
return FcCharSetCount(This->charSet);
}
GLint __glcCharMapGetMaxMappedCode(const __GLCcharMap* This);
GLint __glcCharMapGetMinMappedCode(const __GLCcharMap* This);
#endif

917
3rdparty/quesoglc/ocontext.c vendored Normal file
View File

@ -0,0 +1,917 @@
/* 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$ */
/** \file
* defines the object __GLCcontext which is used to manage the contexts.
*/
#if defined(__WIN32__) || defined(_MSC_VER)
#include <io.h>
#else
#include <unistd.h>
#endif
#include <sys/stat.h>
#include "internal.h"
#include "texture.h"
#include FT_MODULE_H
__GLCcommonArea __glcCommonArea;
#ifdef HAVE_TLS
__thread __GLCthreadArea __glcTlsThreadArea;
#else
__GLCthreadArea* __glcThreadArea = NULL;
#endif
static GLboolean __glcContextUpdateHashTable(__GLCcontext *This);
/* Find a token in a list of tokens separated by 'separator' */
static GLCchar8* __glcFindIndexList(GLCchar8* inString, const GLuint inIndex,
const GLCchar8* inSeparator)
{
GLuint occurence = 0;
GLCchar8* s = inString;
const GLCchar8* sep = inSeparator;
if (!inIndex)
return s;
for (; *s != '\0'; s++) {
if (*s == *sep) {
occurence++;
if (occurence == inIndex)
break;
}
}
return (GLCchar8 *) s;
}
/* Constructor of the object : it allocates memory and initializes the member
* of the new object.
*/
__GLCcontext* __glcContextCreate(const GLint inContext)
{
__GLCcontext *This = NULL;
This = (__GLCcontext*)__glcMalloc(sizeof(__GLCcontext));
if (!This) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
memset(This, 0, sizeof(__GLCcontext));
if (FT_New_Library(&__glcCommonArea.memoryManager, &This->library)) {
__glcRaiseError(GLC_RESOURCE_ERROR);
__glcFree(This);
return NULL;
}
FT_Add_Default_Modules(This->library);
#ifdef GLC_FT_CACHE
if (FTC_Manager_New(This->library, 0, 0, 0, __glcFileOpen, NULL,
&This->cache)) {
__glcRaiseError(GLC_RESOURCE_ERROR);
FT_Done_Library(This->library);
__glcFree(This);
return NULL;
}
#endif
__glcLock();
This->config = FcInitLoadConfigAndFonts();
__glcUnlock();
if (!This->config) {
__glcRaiseError(GLC_RESOURCE_ERROR);
#ifdef GLC_FT_CACHE
FTC_Manager_Done(This->cache);
#endif
FT_Done_Library(This->library);
__glcFree(This);
return NULL;
}
This->catalogList = __glcArrayCreate(sizeof(GLCchar8*));
if (!This->catalogList) {
#ifdef GLC_FT_CACHE
FTC_Manager_Done(This->cache);
#endif
FT_Done_Library(This->library);
FcConfigDestroy(This->config);
__glcFree(This);
return NULL;
}
This->masterHashTable = __glcArrayCreate(sizeof(GLCchar32));
if (!This->masterHashTable) {
__glcArrayDestroy(This->catalogList);
#ifdef GLC_FT_CACHE
FTC_Manager_Done(This->cache);
#endif
FT_Done_Library(This->library);
FcConfigDestroy(This->config);
__glcFree(This);
return NULL;
}
if (!__glcContextUpdateHashTable(This)) {
__glcArrayDestroy(This->masterHashTable);
__glcArrayDestroy(This->catalogList);
#ifdef GLC_FT_CACHE
FTC_Manager_Done(This->cache);
#endif
FT_Done_Library(This->library);
FcConfigDestroy(This->config);
__glcFree(This);
return NULL;
}
This->currentFontList.head = NULL;
This->currentFontList.tail = NULL;
This->fontList.head = NULL;
This->fontList.tail = NULL;
This->genFontList.head = NULL;
This->genFontList.tail = NULL;
This->isCurrent = GL_FALSE;
This->isInGlobalCommand = GL_FALSE;
This->id = inContext;
This->pendingDelete = GL_FALSE;
This->stringState.callback = (GLCfunc)GLC_NONE;
This->stringState.dataPointer = (void*)GLC_NONE;
This->stringState.stringType = GLC_UCS1;
This->enableState.autoFont = GL_TRUE;
This->enableState.glObjects = GL_TRUE;
This->enableState.mipmap = GL_TRUE;
This->enableState.hinting = GL_FALSE;
This->enableState.extrude = GL_FALSE;
This->enableState.kerning = GL_FALSE;
This->renderState.resolution = 72.;
This->renderState.renderStyle = GLC_BITMAP;
This->renderState.tolerance = 0.005;
This->bitmapMatrixStackDepth = 1;
This->bitmapMatrix = This->bitmapMatrixStack;
This->bitmapMatrix[0] = 1.;
This->bitmapMatrix[3] = 1.;
This->measurementBuffer = __glcArrayCreate(12 * sizeof(GLfloat));
if (!This->measurementBuffer) {
__glcArrayDestroy(This->masterHashTable);
__glcArrayDestroy(This->catalogList);
#ifdef GLC_FT_CACHE
FTC_Manager_Done(This->cache);
#endif
FT_Done_Library(This->library);
FcConfigDestroy(This->config);
__glcFree(This);
return NULL;
}
This->isInCallbackFunc = GL_FALSE;
This->vertexArray = __glcArrayCreate(2 * sizeof(GLfloat));
if (!This->vertexArray) {
__glcArrayDestroy(This->measurementBuffer);
__glcArrayDestroy(This->masterHashTable);
__glcArrayDestroy(This->catalogList);
#ifdef GLC_FT_CACHE
FTC_Manager_Done(This->cache);
#endif
FT_Done_Library(This->library);
FcConfigDestroy(This->config);
__glcFree(This);
return NULL;
}
This->controlPoints = __glcArrayCreate(5 * sizeof(GLfloat));
if (!This->controlPoints) {
__glcArrayDestroy(This->vertexArray);
__glcArrayDestroy(This->measurementBuffer);
__glcArrayDestroy(This->masterHashTable);
__glcArrayDestroy(This->catalogList);
#ifdef GLC_FT_CACHE
FTC_Manager_Done(This->cache);
#endif
FT_Done_Library(This->library);
FcConfigDestroy(This->config);
__glcFree(This);
return NULL;
}
This->endContour = __glcArrayCreate(sizeof(int));
if (!This->endContour) {
__glcArrayDestroy(This->controlPoints);
__glcArrayDestroy(This->vertexArray);
__glcArrayDestroy(This->measurementBuffer);
__glcArrayDestroy(This->masterHashTable);
__glcArrayDestroy(This->catalogList);
#ifdef GLC_FT_CACHE
FTC_Manager_Done(This->cache);
#endif
FT_Done_Library(This->library);
FcConfigDestroy(This->config);
__glcFree(This);
return NULL;
}
This->vertexIndices = __glcArrayCreate(sizeof(GLuint));
if (!This->vertexIndices) {
__glcArrayDestroy(This->endContour);
__glcArrayDestroy(This->controlPoints);
__glcArrayDestroy(This->vertexArray);
__glcArrayDestroy(This->measurementBuffer);
__glcArrayDestroy(This->masterHashTable);
__glcArrayDestroy(This->catalogList);
#ifdef GLC_FT_CACHE
FTC_Manager_Done(This->cache);
#endif
FT_Done_Library(This->library);
FcConfigDestroy(This->config);
__glcFree(This);
return NULL;
}
This->geomBatches = __glcArrayCreate(sizeof(__GLCgeomBatch));
if (!This->geomBatches) {
__glcArrayDestroy(This->vertexIndices);
__glcArrayDestroy(This->endContour);
__glcArrayDestroy(This->controlPoints);
__glcArrayDestroy(This->vertexArray);
__glcArrayDestroy(This->measurementBuffer);
__glcArrayDestroy(This->masterHashTable);
__glcArrayDestroy(This->catalogList);
#ifdef GLC_FT_CACHE
FTC_Manager_Done(This->cache);
#endif
FT_Done_Library(This->library);
FcConfigDestroy(This->config);
__glcFree(This);
return NULL;
}
/* The environment variable GLC_PATH is an alternate way to allow QuesoGLC
* to access to fonts catalogs/directories.
*/
/*Check if the GLC_PATH environment variables are exported */
if (getenv("GLC_CATALOG_LIST") || getenv("GLC_PATH")) {
GLCchar8 *path = NULL;
GLCchar8 *begin = NULL;
GLCchar8 *sepPos = NULL;
const GLCchar8 *separator = (GLCchar8*)getenv("GLC_LIST_SEPARATOR");
/* Get the list separator */
if (!separator) {
#ifdef __WIN32__
/* Windows can not use a colon-separated list since the colon sign is
* used after the drive letter. The semicolon is used by Windows for its
* PATH variable, so we use it for consistency.
*/
separator = (const GLCchar8*)";";
#else
/* POSIX platforms use colon-separated lists for the paths variables
* so we keep with it for consistency.
*/
separator = (const GLCchar8*)":";
#endif
}
/* Read the paths of fonts file.
* First, try GLC_CATALOG_LIST...
*/
if (getenv("GLC_CATALOG_LIST"))
#ifdef __WIN32__
path = (GLCchar8*)_strdup(getenv("GLC_CATALOG_LIST"));
#else
path = (GLCchar8*)strdup(getenv("GLC_CATALOG_LIST"));
#endif
/* Then try GLC_PATH */
else if (getenv("GLC_PATH")) {
#ifdef __WIN32__
path = (GLCchar8*)_strdup(getenv("GLC_PATH"));
#else
path = (GLCchar8*)strdup(getenv("GLC_PATH"));
#endif
}
if (path) {
/* Get each path and add the corresponding masters to the current
* context */
GLCchar8* duplicated = NULL;
begin = path;
do {
sepPos = __glcFindIndexList(begin, 1, separator);
if (*sepPos)
*(sepPos++) = 0;
#ifdef __WIN32__
duplicated = (GLCchar8*)_strdup((char*)begin);
#else
duplicated = (GLCchar8*)strdup((char*)begin);
#endif
if (!duplicated) {
__glcRaiseError(GLC_RESOURCE_ERROR);
}
else {
if (!__glcArrayAppend(This->catalogList, &duplicated))
free(duplicated);
else if (!FcConfigAppFontAddDir(This->config,
(const unsigned char*)begin)) {
__glcArrayRemove(This->catalogList,
GLC_ARRAY_LENGTH(This->catalogList));
__glcRaiseError(GLC_RESOURCE_ERROR);
free(duplicated);
}
else if (!__glcContextUpdateHashTable(This)) {
/* For some reason the update of the master hash table has failed :
* the new catalog must then be removed from GLC_CATALOG_LIST.
*/
__glcContextRemoveCatalog(This,
GLC_ARRAY_LENGTH(This->catalogList));
}
}
begin = sepPos;
} while (*sepPos);
free(path);
}
else {
/* strdup has failed to allocate memory to duplicate GLC_PATH => ERROR */
__glcRaiseError(GLC_RESOURCE_ERROR);
}
}
return This;
}
#ifndef GLC_FT_CACHE
/* This function is called from FT_List_Finalize() to close all the fonts
* of the GLC_CURRENT_FONT_LIST
*/
static void __glcFontClosure(FT_Memory GLC_UNUSED_ARG(inMemory), void* inData,
void* GLC_UNUSED_ARG(inUser))
{
__GLCfont *font = (__GLCfont*)inData;
assert(font);
__glcFontClose(font);
}
#endif
/* This function is called from FT_List_Finalize() to destroy all
* remaining fonts
*/
static void __glcFontDestructor(FT_Memory GLC_UNUSED_ARG(inMemory),
void* inData, void* inUser)
{
__GLCfont *font = (__GLCfont*)inData;
__GLCcontext* ctx = (__GLCcontext*)inUser;
assert(ctx);
assert(font);
__glcFontDestroy(font, ctx);
}
/* Destructor of the object : it first destroys all the GLC objects that have
* been created during the life of the context. Then it releases the memory
* occupied by the GLC state struct.
* It does not destroy GL objects associated with the GLC context since we can
* not be sure that the current GL context is the GL context that contains the
* GL objects built by the GLC context that we are destroying. This could
* happen if the user calls glcDeleteContext() after the GL context has been
* destroyed or after the user has changed the current GL context.
*/
void __glcContextDestroy(__GLCcontext *This)
{
int i = 0;
assert(This);
/* Destroy the list of catalogs */
for (i = 0; i < GLC_ARRAY_LENGTH(This->catalogList); i++) {
GLCchar8* string = ((GLCchar8**)GLC_ARRAY_DATA(This->catalogList))[i];
assert(string);
free(string);
}
__glcArrayDestroy(This->catalogList);
/* Destroy GLC_CURRENT_FONT_LIST */
#ifdef GLC_FT_CACHE
FT_List_Finalize(&This->currentFontList, NULL,
&__glcCommonArea.memoryManager, NULL);
#else
FT_List_Finalize(&This->currentFontList, __glcFontClosure,
&__glcCommonArea.memoryManager, NULL);
#endif
/* Destroy GLC_FONT_LIST */
FT_List_Finalize(&This->fontList, __glcFontDestructor,
&__glcCommonArea.memoryManager, This);
/* Destroy empty fonts generated by glcGenFontID() */
FT_List_Finalize(&This->genFontList, __glcFontDestructor,
&__glcCommonArea.memoryManager, This);
if (This->masterHashTable)
__glcArrayDestroy(This->masterHashTable);
FT_List_Finalize(&This->atlasList, NULL,
&__glcCommonArea.memoryManager, NULL);
if (This->bufferSize)
__glcFree(This->buffer);
if (This->measurementBuffer)
__glcArrayDestroy(This->measurementBuffer);
if (This->vertexArray)
__glcArrayDestroy(This->vertexArray);
if (This->controlPoints)
__glcArrayDestroy(This->controlPoints);
if (This->endContour)
__glcArrayDestroy(This->endContour);
if (This->vertexIndices)
__glcArrayDestroy(This->vertexIndices);
if (This->geomBatches)
__glcArrayDestroy(This->geomBatches);
#ifdef GLC_FT_CACHE
FTC_Manager_Done(This->cache);
#endif
FT_Done_Library(This->library);
FcConfigDestroy(This->config);
__glcFree(This);
}
/* Return the first font in GLC_CURRENT_FONT_LIST that maps 'inCode'.
* If there is no such font, the function returns NULL.
* 'inCode' must be given in UCS-4 format.
*/
static __GLCfont* __glcLookupFont(const FT_List fontList, const GLint inCode)
{
FT_ListNode node = NULL;
for (node = fontList->head; node; node = node->next) {
__GLCfont* font = (__GLCfont*)node->data;
/* Check if the character identified by inCode exists in the font */
if (__glcFontHasChar(font, inCode))
return font;
}
return NULL;
}
/* Calls the callback function (does various tests to determine if it is
* possible) and returns GL_TRUE if it has succeeded or GL_FALSE otherwise.
* 'inCode' must be given in UCS-4 format.
*/
static GLboolean __glcCallCallbackFunc(__GLCcontext *inContext,
const GLint inCode)
{
GLCfunc callbackFunc = NULL;
GLboolean result = GL_FALSE;
GLint aCode = 0;
/* Recursivity is not allowed */
if (inContext->isInCallbackFunc)
return GL_FALSE;
callbackFunc = inContext->stringState.callback;
if (!callbackFunc)
return GL_FALSE;
/* Convert the character code back to the current string type */
aCode = __glcConvertUcs4ToGLint(inContext, inCode);
/* Check if the character has been converted */
if (aCode < 0)
return GL_FALSE;
inContext->isInCallbackFunc = GL_TRUE;
/* Call the callback function with the character converted to the current
* string type.
*/
result = (*callbackFunc)(aCode);
inContext->isInCallbackFunc = GL_FALSE;
return result;
}
/* Returns the ID of the first font in GLC_CURRENT_FONT_LIST that maps
* 'inCode'. If there is no such font and GLC_AUTO_FONT is enabled, the
* function attempts to append a new font from GLC_FONT_LIST (or from a master)
* to GLC_CURRENT_FONT_LIST. If the attempt fails the function returns zero.
* 'inCode' must be given in UCS-4 format.
*/
__GLCfont* __glcContextGetFont(__GLCcontext *This, const GLint inCode)
{
__GLCfont* font = NULL;
/* Look for a font in the current font list */
font = __glcLookupFont(&This->currentFontList, inCode);
/* If a font has been found return */
if (font)
return font;
/* If a callback function is defined for GLC_OP_glcUnmappedCode then call it.
* The callback function should return GL_TRUE if it succeeds in appending to
* GLC_CURRENT_FONT_LIST the ID of a font that maps 'inCode'.
*/
if (__glcCallCallbackFunc(This, inCode)) {
font = __glcLookupFont(&This->currentFontList, inCode);
if (font)
return font;
}
/* If the value of the boolean variable GLC_AUTOFONT is GL_TRUE then search
* GLC_FONT_LIST for the first font that maps 'inCode'. If the search
* succeeds, then append the font's ID to GLC_CURRENT_FONT_LIST.
*/
if (This->enableState.autoFont) {
__GLCmaster* master = NULL;
font = __glcLookupFont(&This->fontList, inCode);
if (font) {
__glcAppendFont(This, font);
return font;
}
master = __glcMasterMatchCode(This, inCode);
if (!master)
return NULL;
font = __glcNewFontFromMaster(__glcGenFontID(This), master, This, inCode);
__glcMasterDestroy(master);
if (font) {
/* Add the font to the GLC_CURRENT_FONT_LIST */
__glcAppendFont(This, font);
return font;
}
}
return NULL;
}
/* Sometimes informations may need to be stored temporarily by a thread.
* The so-called 'buffer' is created for that purpose. Notice that it is a
* component of the GLC state struct hence its lifetime is the same as the
* GLC state's lifetime.
* __glcContextQueryBuffer() should be called whenever the buffer is to be used
* The function checks that the buffer is big enough to store the required data
* and returns a pointer to the buffer.
* Note that the only memory management function used below is 'realloc' which
* means that the buffer goes bigger and bigger until it is freed. No function
* is provided to reduce its size so it should be freed and re-allocated
* manually in case of emergency ;-)
*/
GLCchar* __glcContextQueryBuffer(__GLCcontext *This, const size_t inSize)
{
GLCchar* buffer = This->buffer;
if (inSize > This->bufferSize) {
buffer = (GLCchar*)__glcRealloc(This->buffer, inSize);
if (!buffer) {
__glcRaiseError(GLC_RESOURCE_ERROR);
}
else {
This->buffer = buffer;
This->bufferSize = inSize;
}
}
return buffer;
}
/* Update the hash table that which is used to convert master IDs into
* FontConfig patterns.
*/
static GLboolean __glcContextUpdateHashTable(__GLCcontext *This)
{
FcPattern* pattern = NULL;
FcObjectSet* objectSet = NULL;
FcFontSet *fontSet = NULL;
int i = 0;
__GLCarray *updatedHashTable = NULL;
/* Use Fontconfig to get the default font files */
pattern = FcPatternCreate();
if (!pattern) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return GL_FALSE;
}
objectSet = FcObjectSetBuild(FC_FAMILY, FC_FOUNDRY, FC_OUTLINE, FC_SPACING,
NULL);
if (!objectSet) {
__glcRaiseError(GLC_RESOURCE_ERROR);
FcPatternDestroy(pattern);
return GL_FALSE;
}
fontSet = FcFontList(This->config, pattern, objectSet);
FcPatternDestroy(pattern);
FcObjectSetDestroy(objectSet);
if (!fontSet) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return GL_FALSE;
}
updatedHashTable = __glcArrayDuplicate(This->masterHashTable);
if (!updatedHashTable) {
FcFontSetDestroy(fontSet);
return GL_FALSE;
}
/* Parse the font set looking for fonts that are not already registered in the
* hash table.
*/
for (i = 0; i < fontSet->nfont; i++) {
GLCchar32 hashValue = 0;
int j = 0;
const int length = GLC_ARRAY_LENGTH(updatedHashTable);
GLCchar32* hashTable = (GLCchar32*)GLC_ARRAY_DATA(updatedHashTable);
FcBool outline = FcFalse;
FcChar8* family = NULL;
int fixed = 0;
FcChar8* foundry = NULL;
#ifdef DEBUGMODE
FcResult result = FcResultMatch;
result = FcPatternGetBool(fontSet->fonts[i], FC_OUTLINE, 0, &outline);
assert(result != FcResultTypeMismatch);
#else
FcPatternGetBool(fontSet->fonts[i], FC_OUTLINE, 0, &outline);
#endif
/* Check whether the glyphs are outlines */
if (!outline)
continue;
#ifdef DEBUGMODE
result = FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &family);
assert(result != FcResultTypeMismatch);
result = FcPatternGetString(fontSet->fonts[i], FC_FOUNDRY, 0, &foundry);
assert(result != FcResultTypeMismatch);
result = FcPatternGetInteger(fontSet->fonts[i], FC_SPACING, 0, &fixed);
assert(result != FcResultTypeMismatch);
#else
FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &family);
FcPatternGetString(fontSet->fonts[i], FC_FOUNDRY, 0, &foundry);
FcPatternGetInteger(fontSet->fonts[i], FC_SPACING, 0, &fixed);
#endif
if (foundry)
pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, family,
FC_FOUNDRY, FcTypeString, foundry, FC_SPACING,
FcTypeInteger, fixed, NULL);
else
pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, family,
FC_SPACING, FcTypeInteger, fixed, NULL);
if (!pattern) {
__glcRaiseError(GLC_RESOURCE_ERROR);
FcFontSetDestroy(fontSet);
__glcArrayDestroy(updatedHashTable);
return GL_FALSE;
}
/* Check if the font is already registered in the hash table */
hashValue = FcPatternHash(pattern);
FcPatternDestroy(pattern);
for (j = 0; j < length; j++) {
if (hashTable[j] == hashValue)
break;
}
/* If the font is already registered then parse the next one */
if (j != length)
continue;
/* Register the font (i.e. append its hash value to the hash table) */
if (!__glcArrayAppend(updatedHashTable, &hashValue)) {
FcFontSetDestroy(fontSet);
__glcArrayDestroy(updatedHashTable);
return GL_FALSE;
}
}
FcFontSetDestroy(fontSet);
__glcArrayDestroy(This->masterHashTable);
This->masterHashTable = updatedHashTable;
return GL_TRUE;
}
/* Append a catalog to the context catalog list */
void __glcContextAppendCatalog(__GLCcontext* This, const GLCchar* inCatalog)
{
#ifdef __WIN32__
GLCchar8* duplicated = (GLCchar8*)_strdup((const char*)inCatalog);
#else
GLCchar8* duplicated = (GLCchar8*)strdup((const char*)inCatalog);
#endif
if (!duplicated) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return;
}
if (!__glcArrayAppend(This->catalogList, &duplicated)) {
free(duplicated);
return;
}
if (!FcConfigAppFontAddDir(This->config, (const unsigned char*)inCatalog)) {
__glcArrayRemove(This->catalogList, GLC_ARRAY_LENGTH(This->catalogList));
__glcRaiseError(GLC_RESOURCE_ERROR);
free(duplicated);
return;
}
if (!__glcContextUpdateHashTable(This)) {
/* For some reason the update of the master hash table has failed : the
* new catalog must then be removed from GLC_CATALOG_LIST.
*/
__glcContextRemoveCatalog(This, GLC_ARRAY_LENGTH(This->catalogList));
return;
}
}
/* Prepend a catalog to the context catalog list */
void __glcContextPrependCatalog(__GLCcontext* This, const GLCchar* inCatalog)
{
#ifdef __WIN32__
GLCchar8* duplicated = (GLCchar8*)_strdup((const char*)inCatalog);
#else
GLCchar8* duplicated = (GLCchar8*)strdup((const char*)inCatalog);
#endif
if (!duplicated) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return;
}
if (!__glcArrayInsert(This->catalogList, 0, &duplicated)) {
free(duplicated);
return;
}
if (!FcConfigAppFontAddDir(This->config, (const unsigned char*)inCatalog)) {
__glcArrayRemove(This->catalogList, 0);
__glcRaiseError(GLC_RESOURCE_ERROR);
free(duplicated);
return;
}
if (!__glcContextUpdateHashTable(This)) {
/* For some reason the update of the master hash table has failed : the
* new catalog must then be removed from GLC_CATALOG_LIST.
*/
__glcContextRemoveCatalog(This, 0);
return;
}
}
/* Get the path of the catalog identified by inIndex */
GLCchar8* __glcContextGetCatalogPath(const __GLCcontext* This,
const GLint inIndex)
{
if (inIndex >= GLC_ARRAY_LENGTH(This->catalogList)) {
__glcRaiseError(GLC_PARAMETER_ERROR);
return NULL;
}
return ((GLCchar8**)GLC_ARRAY_DATA(This->catalogList))[inIndex];
}
/* This function must be called each time that a command destroys
* a font. __glcContextDeleteFont removes, if necessary, the font identified by
* inFont from the list GLC_CURRENT_FONT_LIST and then delete the font.
*/
void __glcContextDeleteFont(__GLCcontext* inContext, __GLCfont* font)
{
FT_ListNode node = NULL;
/* Look for the font into GLC_CURRENT_FONT_LIST */
node = FT_List_Find(&inContext->currentFontList, font);
/* If the font has been found, remove it from the list */
if (node) {
FT_List_Remove(&inContext->currentFontList, node);
#ifndef GLC_FT_CACHE
__glcFontClose(font);
#endif
__glcFree(node);
}
__glcFontDestroy(font, inContext);
}
/* Remove a catalog from the context catalog list */
void __glcContextRemoveCatalog(__GLCcontext* This, const GLint inIndex)
{
FT_ListNode node = NULL;
GLCchar8* catalog = NULL;
int i = 0;
if (inIndex >= GLC_ARRAY_LENGTH(This->catalogList)) {
__glcRaiseError(GLC_PARAMETER_ERROR);
return;
}
FcConfigAppFontClear(This->config);
catalog = ((GLCchar8**)GLC_ARRAY_DATA(This->catalogList))[inIndex];
assert(catalog);
__glcArrayRemove(This->catalogList, inIndex);
free(catalog);
for (i = 0; i < GLC_ARRAY_LENGTH(This->catalogList); i++) {
catalog = ((GLCchar8**)GLC_ARRAY_DATA(This->catalogList))[i];
assert(catalog);
if (!FcConfigAppFontAddDir(This->config, catalog)) {
__glcRaiseError(GLC_RESOURCE_ERROR);
__glcArrayRemove(This->catalogList, i);
free(catalog);
/* After the removal of the problematic catalog , indices are shifted by 1
*/
if (i > 0) i--;
}
}
/* Re-create the hash table from scratch */
GLC_ARRAY_LENGTH(This->masterHashTable) = 0;
__glcContextUpdateHashTable(This);
/* Remove from GLC_FONT_LIST the fonts that were defined in the catalog that
* has been removed. This task has to be done even if the call to
* __glcContextUpdateHashTable() has failed !!!
*/
for (node = This->fontList.head; node; node = node->next) {
__GLCfont* font = (__GLCfont*)(node->data);
GLCchar32 hashValue = 0;
GLCchar32* hashTable = (GLCchar32*)GLC_ARRAY_DATA(This->masterHashTable);
const int length = GLC_ARRAY_LENGTH(This->masterHashTable);
__GLCmaster* master = __glcMasterCreate(font->parentMasterID, This);
if (!master)
continue;
/* Check if the hash value of the master is in the hash table */
hashValue = GLC_MASTER_HASH_VALUE(master);
for (i = 0; i < length; i++) {
if (hashValue == hashTable[i])
break;
}
/* The font is not contained in the hash table => remove it */
if (i == length) {
FT_List_Remove(&This->fontList, node);
__glcContextDeleteFont(This, font);
}
__glcMasterDestroy(master);
}
}

235
3rdparty/quesoglc/ocontext.h vendored Normal file
View File

@ -0,0 +1,235 @@
/* QuesoGLC
* A free implementation of the OpenGL Character Renderer (GLC)
* Copyright (c) 2002, 2004-2008, 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$ */
/** \file
* header of the object __GLCcontext which is used to manage the contexts.
*/
#ifndef __glc_ocontext_h
#define __glc_ocontext_h
#ifndef __WIN32__
#include <pthread.h>
#else
#include <windows.h>
#endif
#include <ft2build.h>
#include FT_FREETYPE_H
#ifdef GLC_FT_CACHE
#include FT_CACHE_H
#endif
#include FT_LIST_H
#include "oarray.h"
#include "except.h"
#define GLC_MAX_MATRIX_STACK_DEPTH 32
#define GLC_MAX_ATTRIB_STACK_DEPTH 16
typedef struct __GLCcontextRec __GLCcontext;
typedef struct __GLCtextureRec __GLCtexture;
typedef struct __GLCenableStateRec __GLCenableState;
typedef struct __GLCrenderStateRec __GLCrenderState;
typedef struct __GLCstringStateRec __GLCstringState;
typedef struct __GLCglStateRec __GLCglState;
typedef struct __GLCattribStackLevelRec __GLCattribStackLevel;
typedef struct __GLCthreadAreaRec __GLCthreadArea;
typedef struct __GLCcommonAreaRec __GLCcommonArea;
typedef struct __GLCfontRec __GLCfont;
struct __GLCtextureRec {
GLuint id;
GLsizei width;
GLsizei height;
GLuint bufferObjectID;
};
struct __GLCenableStateRec {
GLboolean autoFont; /* GLC_AUTO_FONT */
GLboolean glObjects; /* GLC_GLOBJECTS */
GLboolean mipmap; /* GLC_MIPMAP */
GLboolean hinting; /* GLC_HINTING_QSO */
GLboolean extrude; /* GLC_EXTRUDE_QSO */
GLboolean kerning; /* GLC_KERNING_QSO */
};
struct __GLCrenderStateRec {
GLfloat resolution; /* GLC_RESOLUTION */
GLint renderStyle; /* GLC_RENDER_STYLE */
GLfloat tolerance; /* GLC_PARAMETRIC_TOLERANCE_QSO */
};
struct __GLCstringStateRec {
GLint replacementCode; /* GLC_REPLACEMENT_CODE */
GLint stringType; /* GLC_STRING_TYPE */
GLCfunc callback; /* Callback function GLC_OP_glcUnmappedCode */
GLvoid* dataPointer; /* GLC_DATA_POINTER */
};
struct __GLCglStateRec {
GLint textureID;
GLint textureEnvMode;
GLint pixelBufferObjectID;
GLint vertexBufferObjectID;
GLint elementBufferObjectID;
GLboolean blend;
GLboolean normalize;
GLboolean vertexArray;
GLboolean normalArray;
GLboolean colorArray;
GLboolean indexArray;
GLboolean texCoordArray;
GLboolean edgeFlagArray;
GLint blendSrc;
GLint blendDst;
GLint vertexArraySize;
GLint vertexArrayType;
GLint vertexArrayStride;
GLvoid* vertexArrayPointer;
GLint texCoordArraySize;
GLint texCoordArrayType;
GLint texCoordArrayStride;
GLvoid* texCoordArrayPointer;
GLint unpackLsbFirst;
GLint unpackRowLength;
GLint unpackSkipPixels;
GLint unpackSkipRows;
GLint unpackAlignment;
GLfloat colorBias[4];
GLfloat colorScale[4];
};
struct __GLCattribStackLevelRec {
GLbitfield attribBits;
__GLCrenderState renderState;
__GLCstringState stringState;
__GLCglState glState;
__GLCenableState enableState;
};
struct __GLCcontextRec {
FT_ListNodeRec node;
GLCchar *buffer;
size_t bufferSize;
FT_Library library;
#ifdef GLC_FT_CACHE
FTC_Manager cache;
#endif
FcConfig *config;
GLint id; /* Context ID */
GLboolean isInGlobalCommand; /* Is in a global command ? */
GLboolean pendingDelete; /* Is there a pending deletion ? */
__GLCenableState enableState;
__GLCrenderState renderState;
__GLCstringState stringState;
FT_ListRec currentFontList; /* GLC_CURRENT_FONT_LIST */
FT_ListRec fontList; /* GLC_FONT_LIST */
FT_ListRec genFontList; /* Fonts generated by glcGenFontID() */
__GLCarray* masterHashTable;
__GLCarray* catalogList; /* GLC_CATALOG_LIST */
__GLCarray* measurementBuffer;
GLfloat measurementStringBuffer[12];
__GLCarray* vertexArray; /* Array of vertices */
__GLCarray* controlPoints; /* Array of control points */
__GLCarray* endContour; /* Array of contour limits */
__GLCarray* vertexIndices; /* Array of vertex indices */
__GLCarray* geomBatches; /* Array of geometric batches */
#ifdef GLEW_MX
GLEWContext glewContext; /* GLEW context for OpenGL extensions */
#endif
__GLCtexture texture; /* Texture for immediate mode rendering */
__GLCtexture atlas;
FT_ListRec atlasList;
int atlasWidth;
int atlasHeight;
int atlasCount;
GLfloat* bitmapMatrix; /* GLC_BITMAP_MATRIX */
GLfloat bitmapMatrixStack[4*GLC_MAX_MATRIX_STACK_DEPTH];
GLint bitmapMatrixStackDepth;
__GLCattribStackLevel attribStack[GLC_MAX_ATTRIB_STACK_DEPTH];
GLint attribStackDepth;
GLboolean isCurrent;
GLboolean isInCallbackFunc; /* Is a callback function executing ? */
};
struct __GLCthreadAreaRec {
__GLCcontext* currentContext;
GLCenum errorState;
GLint lockState;
FT_ListRec exceptionStack;
__glcException failedTry;
};
struct __GLCcommonAreaRec {
GLint versionMajor; /* GLC_VERSION_MAJOR */
GLint versionMinor; /* GLC_VERSION_MINOR */
FT_ListRec contextList;
#ifndef __WIN32__
pthread_mutex_t mutex; /* For concurrent accesses to the common
area */
#ifndef HAVE_TLS
pthread_key_t threadKey;
pthread_t threadID;
pthread_once_t __glcInitThreadOnce;
#endif /* HAVE_TLS */
#else /* __WIN32__ */
CRITICAL_SECTION section;
DWORD threadKey;
DWORD threadID;
LONG __glcInitThreadOnce;
#endif
/* Evil hack : we use the FT_MemoryRec_ structure definition which is
* supposed not to be exported by FreeType headers. So this definition may
* fail if the guys of FreeType decide not to expose FT_MemoryRec_ anymore.
* However, this has not happened yet so we still rely on FT_MemoryRec_ ...
*/
struct FT_MemoryRec_ memoryManager;
};
extern __GLCcommonArea __glcCommonArea;
#ifdef HAVE_TLS
extern __thread __GLCthreadArea __glcTlsThreadArea
__attribute__((tls_model("initial-exec")));
#else
extern __GLCthreadArea* __glcThreadArea;
#endif
__GLCcontext* __glcContextCreate(const GLint inContext);
void __glcContextDestroy(__GLCcontext *This);
__GLCfont* __glcContextGetFont(__GLCcontext *This, const GLint code);
GLCchar* __glcContextQueryBuffer(__GLCcontext *This, const size_t inSize);
void __glcContextAppendCatalog(__GLCcontext* This, const GLCchar* inCatalog);
void __glcContextPrependCatalog(__GLCcontext* This, const GLCchar* inCatalog);
void __glcContextRemoveCatalog(__GLCcontext* This, const GLint inIndex);
GLCchar8* __glcContextGetCatalogPath(const __GLCcontext* This,
const GLint inIndex);
void __glcContextDeleteFont(__GLCcontext* inContext, __GLCfont* font);
#endif /* __glc_ocontext_h */

1319
3rdparty/quesoglc/ofacedesc.c vendored Normal file

File diff suppressed because it is too large Load Diff

106
3rdparty/quesoglc/ofacedesc.h vendored Normal file
View File

@ -0,0 +1,106 @@
/* 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$ */
/** \file
* header of the object __GLCfaceDescriptor that contains the description of a
* face.
*/
#ifndef __glc_ofacedesc_h
#define __glc_ofacedesc_h
#include "omaster.h"
typedef struct __GLCrendererDataRec __GLCrendererData;
typedef struct __GLCfaceDescriptorRec __GLCfaceDescriptor;
struct __GLCfaceDescriptorRec {
FT_ListNodeRec node;
FcPattern* pattern;
FT_Face face;
#ifndef GLC_FT_CACHE
int faceRefCount;
#endif
FT_ListRec glyphList;
};
__GLCfaceDescriptor* __glcFaceDescCreate(const __GLCmaster* inMaster,
const GLCchar8* inFace,
const __GLCcontext* inContext,
const GLint inCode);
void __glcFaceDescDestroy(__GLCfaceDescriptor* This, __GLCcontext* inContext);
#ifndef GLC_FT_CACHE
FT_Face __glcFaceDescOpen(__GLCfaceDescriptor* This,
__GLCcontext* inContext);
void __glcFaceDescClose(__GLCfaceDescriptor* This);
#endif
__GLCglyph* __glcFaceDescGetGlyph(__GLCfaceDescriptor* This,
const GLint inCode,
const __GLCcontext* inContext);
void __glcFaceDescDestroyGLObjects(const __GLCfaceDescriptor* This,
__GLCcontext* inContext);
GLboolean __glcFaceDescPrepareGlyph(__GLCfaceDescriptor* This,
const __GLCcontext* inContext,
const GLfloat inScaleX,
const GLfloat inScaleY,
const GLCulong inGlyphIndex);
GLfloat* __glcFaceDescGetBoundingBox(__GLCfaceDescriptor* This,
const GLCulong inGlyphIndex,
GLfloat* outVec, const GLfloat inScaleX,
const GLfloat inScaleY,
const __GLCcontext* inContext);
GLfloat* __glcFaceDescGetAdvance(__GLCfaceDescriptor* This,
const GLCulong inGlyphIndex, GLfloat* outVec,
const GLfloat inScaleX, const GLfloat inScaleY,
const __GLCcontext* inContext);
const GLCchar8* __glcFaceDescGetFontFormat(const __GLCfaceDescriptor* This,
const __GLCcontext* inContext,
const GLCenum inAttrib);
GLfloat* __glcFaceDescGetMaxMetric(__GLCfaceDescriptor* This, GLfloat* outVec,
const __GLCcontext* inContext,
const GLfloat inScaleX,
const GLfloat inScaleY);
GLfloat* __glcFaceDescGetKerning(__GLCfaceDescriptor* This,
const GLCuint inGlyphIndex,
const GLCuint inPrevGlyphIndex,
const GLfloat inScaleX, const GLfloat inScaleY,
GLfloat* outVec,
const __GLCcontext* inContext);
GLCchar8* __glcFaceDescGetStyleName(__GLCfaceDescriptor* This);
GLboolean __glcFaceDescIsFixedPitch(__GLCfaceDescriptor* This);
GLboolean __glcFaceDescOutlineDecompose(const __GLCfaceDescriptor* This,
__GLCrendererData* inData,
const __GLCcontext* inContext);
GLboolean __glcFaceDescGetBitmapSize(const __GLCfaceDescriptor* This,
GLint* outWidth, GLint *outHeight,
const GLfloat inScaleX,
const GLfloat inScaleY,
GLint* outPixBoundingBox,
const int inFactor,
const __GLCcontext* inContext);
GLboolean __glcFaceDescGetBitmap(const __GLCfaceDescriptor* This,
const GLint inWidth, const GLint inHeight,
const void* inBuffer,
const __GLCcontext* inContext);
GLboolean __glcFaceDescOutlineEmpty(__GLCfaceDescriptor* This);
__GLCcharMap* __glcFaceDescGetCharMap(__GLCfaceDescriptor* This,
__GLCcontext* inContext);
#endif /* __glc_ofacedesc_h */

353
3rdparty/quesoglc/ofont.c vendored Normal file
View File

@ -0,0 +1,353 @@
/* 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;
}

132
3rdparty/quesoglc/ofont.h vendored Normal file
View File

@ -0,0 +1,132 @@
/* 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$ */
/** \file
* header of the object __GLCfont which manage the fonts
*/
#ifndef __glc_ofont_h
#define __glc_ofont_h
#include "ofacedesc.h"
/* It seems that Visual C++ does not recognize the inline keyword !?! */
#ifdef _MSC_VER
#define inline
#endif
struct __GLCfontRec {
GLint id;
__GLCfaceDescriptor* faceDesc;
GLint parentMasterID;
__GLCcharMap* charMap;
GLfloat maxMetric[6];
GLboolean maxMetricCached;
};
__GLCfont* __glcFontCreate(GLint id, __GLCmaster* inMaster,
__GLCcontext* inContext, GLint inCode);
void __glcFontDestroy(__GLCfont *This, __GLCcontext* inContext);
__GLCglyph* __glcFontGetGlyph(const __GLCfont *This, const GLint inCode,
const __GLCcontext* inContext);
GLfloat* __glcFontGetBoundingBox(const __GLCfont *This, const GLint inCode,
GLfloat* outVec, const __GLCcontext* inContext,
const GLfloat inScaleX,
const GLfloat inScaleY);
GLfloat* __glcFontGetAdvance(const __GLCfont *This, const GLint inCode,
GLfloat* outVec, const __GLCcontext* inContext,
const GLfloat inScaleX, const GLfloat inScaleY);
GLfloat* __glcFontGetKerning(const __GLCfont* This, const GLint inCode,
const GLint inPrevCode, GLfloat* outVec,
const __GLCcontext* inContext,
const GLfloat inScaleX, const GLfloat inScaleY);
GLboolean __glcFontPrepareGlyph(const __GLCfont* This,
const __GLCcontext* inContext,
const GLfloat inScaleX, const GLfloat inScaleY,
const GLCulong inGlyphIndex);
GLfloat* __glcFontGetMaxMetric(__GLCfont* This, GLfloat* outVec,
const __GLCcontext* inContext,
const GLfloat inScaleX, const GLfloat inScaleY);
/* Inline functions definitions */
#ifndef GLC_FT_CACHE
/* Open the font file */
static inline void* __glcFontOpen(__GLCfont* This, __GLCcontext* inContext)
{
return __glcFaceDescOpen(This->faceDesc, inContext);
}
/* Close the font file */
static inline void __glcFontClose(__GLCfont* This)
{
__glcFaceDescClose(This->faceDesc);
}
#endif
/* Get the size of the bitmap in which the glyph will be rendered */
static inline GLboolean __glcFontGetBitmapSize(const __GLCfont* This,
GLint* outWidth,
GLint* outHeight,
const GLfloat inScaleX,
const GLfloat inScaleY,
const int inFactor,
GLint* outPixBoundingBox,
const __GLCcontext* inContext)
{
return __glcFaceDescGetBitmapSize(This->faceDesc, outWidth, outHeight,
inScaleX, inScaleY, outPixBoundingBox,
inFactor, inContext);
}
/* Decompose the outline of a glyph */
static inline GLboolean __glcFontOutlineDecompose(const __GLCfont* This,
__GLCrendererData* inData,
const __GLCcontext* inContext)
{
return __glcFaceDescOutlineDecompose(This->faceDesc, inData, inContext);
}
/* Render the glyph in a bitmap */
static inline GLboolean __glcFontGetBitmap(const __GLCfont* This,
const GLint inWidth,
const GLint inHeight,
const void* inBuffer,
const __GLCcontext* inContext)
{
return __glcFaceDescGetBitmap(This->faceDesc, inWidth, inHeight, inBuffer,
inContext);
}
/* Chek if the outline of the glyph is empty (which means it is a spacing
* character).
*/
static inline GLboolean __glcFontOutlineEmpty(const __GLCfont* This)
{
return __glcFaceDescOutlineEmpty(This->faceDesc);
}
static inline GLboolean __glcFontHasChar(const __GLCfont* This,
const GLint inCode)
{
return __glcCharMapHasChar(This->charMap, inCode);
}
#endif /* __glc_ofont_h */

233
3rdparty/quesoglc/oglyph.c vendored Normal file
View File

@ -0,0 +1,233 @@
/* QuesoGLC
* A free implementation of the OpenGL Character Renderer (GLC)
* Copyright (c) 2002, 2004-2008, 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 glyphs */
/** \file
* defines the object __GLCglyph which caches all the data needed for a given
* glyph : display list, texture, bounding box, advance, index in the font
* file, etc.
*/
#include "internal.h"
#include "texture.h"
/* Constructor of the object : it allocates memory and initializes the member
* of the new object.
* The user must give the index of the glyph in the font file and its Unicode
* codepoint.
*/
__GLCglyph* __glcGlyphCreate(const GLCulong inIndex, const GLCulong inCode)
{
__GLCglyph* This = NULL;
This = (__GLCglyph*)__glcMalloc(sizeof(__GLCglyph));
if (!This) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
memset(This, 0, sizeof(__GLCglyph));
This->node.data = This;
This->index = inIndex;
This->codepoint = inCode;
This->isSpacingChar = GL_FALSE;
This->advanceCached = GL_FALSE;
This->boundingBoxCached = GL_FALSE;
return This;
}
/* Destructor of the object */
void __glcGlyphDestroy(__GLCglyph* This, __GLCcontext* inContext)
{
__glcGlyphDestroyGLObjects(This, inContext);
__glcFree(This);
}
/* Remove all GL objects related to the texture of the glyph */
void __glcGlyphDestroyTexture(__GLCglyph* This, const __GLCcontext* inContext)
{
if (!inContext->isInGlobalCommand && !GLEW_ARB_vertex_buffer_object)
glDeleteLists(This->glObject[1], 1);
This->glObject[1] = 0;
This->textureObject = NULL;
}
/* This function destroys the display lists and the texture objects that
* are associated with a glyph.
*/
void __glcGlyphDestroyGLObjects(__GLCglyph* This, __GLCcontext* inContext)
{
if (This->glObject[1]) {
__glcReleaseAtlasElement(This->textureObject, inContext);
__glcGlyphDestroyTexture(This, inContext);
}
if (!inContext->isInGlobalCommand) {
if (This->glObject[0]) {
if (GLEW_ARB_vertex_buffer_object) {
glDeleteBuffersARB(1, &This->glObject[0]);
if (This->contours)
__glcFree(This->contours);
This->nContour = 0;
This->contours = NULL;
}
else
glDeleteLists(This->glObject[0], 1);
}
if (This->glObject[2]) {
if (GLEW_ARB_vertex_buffer_object) {
glDeleteBuffersARB(1, &This->glObject[2]);
if (This->geomBatches)
__glcFree(This->geomBatches);
This->nGeomBatch = 0;
This->geomBatches = NULL;
}
else
glDeleteLists(This->glObject[2], 1);
}
if (This->glObject[3]) {
if (GLEW_ARB_vertex_buffer_object)
glDeleteBuffersARB(1, &This->glObject[3]);
else
glDeleteLists(This->glObject[3], 1);
}
memset(This->glObject, 0, 4 * sizeof(GLuint));
}
}
/* Returns the number of display that has been built for a glyph */
int __glcGlyphGetDisplayListCount(const __GLCglyph* This)
{
int i = 0;
int count = 0;
if (GLEW_ARB_vertex_buffer_object)
return 0;
for (i = 0; i < 4; i++) {
if (This->glObject[i])
count++;
}
return count;
}
/* Returns the ID of the inCount-th display list that has been built for a
* glyph.
*/
GLuint __glcGlyphGetDisplayList(const __GLCglyph* This, const int inCount)
{
int i = 0;
int count = inCount;
assert(inCount >= 0);
assert(inCount < __glcGlyphGetDisplayListCount(This));
if (GLEW_ARB_vertex_buffer_object)
return 0;
for (i = 0; i < 4; i++) {
GLuint displayList = This->glObject[i];
if (displayList) {
if (!count)
return displayList;
count--;
}
}
/* The program is not supposed to reach the end of the function.
* The following return is there to prevent the compiler to issue
* a warning about 'control reaching the end of a non-void function'.
*/
return 0xdeadbeef;
}
/* Returns the number of buffer objects that has been built for a glyph */
int __glcGlyphGetBufferObjectCount(const __GLCglyph* This)
{
int i = 0;
int count = 0;
assert(GLEW_ARB_vertex_buffer_object);
for (i = 0; i < 4; i++) {
if (i == 1)
continue;
if (This->glObject[i])
count++;
}
return count;
}
/* Returns the ID of the inCount-th buffer object that has been built for a
* glyph.
*/
GLuint __glcGlyphGetBufferObject(const __GLCglyph* This, const int inCount)
{
int i = 0;
int count = inCount;
assert(GLEW_ARB_vertex_buffer_object);
assert(inCount >= 0);
assert(inCount < __glcGlyphGetBufferObjectCount(This));
for (i = 0; i < 4; i++) {
GLuint bufferObject = This->glObject[i];
if (i == 1)
continue;
if (bufferObject) {
if (!count)
return bufferObject;
count--;
}
}
/* The program is not supposed to reach the end of the function.
* The following return is there to prevent the compiler to issue
* a warning about 'control reaching the end of a non-void function'.
*/
return 0xdeadbeef;
}

62
3rdparty/quesoglc/oglyph.h vendored Normal file
View File

@ -0,0 +1,62 @@
/* QuesoGLC
* A free implementation of the OpenGL Character Renderer (GLC)
* Copyright (c) 2002, 2004-2008, 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$ */
/** \file
* header of the object __GLCglyph which caches all the data needed for a given
* glyph : display list, texture, bounding box, advance, index in the font
* file, etc.
*/
#ifndef __glc_oglyph_h
#define __glc_oglyph_h
typedef struct __GLCglyphRec __GLCglyph;
typedef struct __GLCatlasElementRec __GLCatlasElement;
typedef struct __GLCgeomBatchRec __GLCgeomBatch;
struct __GLCglyphRec {
FT_ListNodeRec node;
GLCulong index;
GLCulong codepoint;
/* GL objects management */
__GLCatlasElement* textureObject;
GLuint glObject[4];
GLint nContour;
GLint* contours;
GLint nGeomBatch;
__GLCgeomBatch* geomBatches;
/* Measurement infos */
GLfloat boundingBox[4];
GLfloat advance[2];
GLboolean advanceCached;
GLboolean boundingBoxCached;
GLboolean isSpacingChar;
};
__GLCglyph* __glcGlyphCreate(const GLCulong inIndex, const GLCulong inCode);
void __glcGlyphDestroy(__GLCglyph* This, __GLCcontext* inContext);
void __glcGlyphDestroyTexture(__GLCglyph* This, const __GLCcontext* inContext);
void __glcGlyphDestroyGLObjects(__GLCglyph* This, __GLCcontext* inContext);
int __glcGlyphGetDisplayListCount(const __GLCglyph* This);
GLuint __glcGlyphGetDisplayList(const __GLCglyph* This, const int inCount);
int __glcGlyphGetBufferObjectCount(const __GLCglyph* This);
GLuint __glcGlyphGetBufferObject(const __GLCglyph* This, const int inCount);
#endif

618
3rdparty/quesoglc/omaster.c vendored Normal file
View File

@ -0,0 +1,618 @@
/* 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$ */
/** \file
* defines the object __GLCmaster which manage the masters
*/
#include "internal.h"
#include <string.h>
typedef GLboolean (*__glcPatternProcess)(FcFontSet* inFontSet,
FcPattern* inPattern, int inFont,
void* inData);
struct __GLCdataRec {
const __GLCmaster* master;
GLint* index;
};
typedef struct __GLCdataRec __GLCdata;
static int __glcScanFonts(const __GLCcontext* inContext, FcFontSet** outFontSet,
FcPattern** outPattern,
__glcPatternProcess inPatternProcess, void* inData)
{
int font = 0;
FcObjectSet* objectSet = NULL;
FcFontSet *fontSet = NULL;
FcPattern *pattern = FcPatternCreate();
/* Use Fontconfig to get the default font files */
if (!pattern) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return -1;
}
objectSet = FcObjectSetBuild(FC_FAMILY, FC_FOUNDRY, FC_OUTLINE, FC_SPACING,
FC_STYLE, NULL);
if (!objectSet) {
__glcRaiseError(GLC_RESOURCE_ERROR);
FcPatternDestroy(pattern);
return -1;
}
fontSet = FcFontList(inContext->config, pattern, objectSet);
FcObjectSetDestroy(objectSet);
FcPatternDestroy(pattern);
if (!fontSet) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return -1;
}
/* Parse the font set looking for a font with an outline and which hash value
* matches the hash value of the master we are looking for.
*/
for (font = 0; font < fontSet->nfont; font++) {
FcBool outline = FcFalse;
FcChar8* family = NULL;
int fixed = 0;
FcChar8* foundry = NULL;
#ifdef DEBUGMODE
FcResult result = FcResultMatch;
result = FcPatternGetBool(fontSet->fonts[font], FC_OUTLINE, 0, &outline);
assert(result != FcResultTypeMismatch);
#else
FcPatternGetBool(fontSet->fonts[font], FC_OUTLINE, 0, &outline);
#endif
if (!outline)
continue;
#ifdef DEBUGMODE
result = FcPatternGetString(fontSet->fonts[font], FC_FAMILY, 0, &family);
assert(result != FcResultTypeMismatch);
result = FcPatternGetString(fontSet->fonts[font], FC_FOUNDRY, 0, &foundry);
assert(result != FcResultTypeMismatch);
result = FcPatternGetInteger(fontSet->fonts[font], FC_SPACING, 0, &fixed);
assert(result != FcResultTypeMismatch);
#else
FcPatternGetString(fontSet->fonts[font], FC_FAMILY, 0, &family);
FcPatternGetString(fontSet->fonts[font], FC_FOUNDRY, 0, &foundry);
FcPatternGetInteger(fontSet->fonts[font], FC_SPACING, 0, &fixed);
#endif
if (foundry)
pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, family,
FC_FOUNDRY, FcTypeString, foundry, FC_SPACING,
FcTypeInteger, fixed, NULL);
else
pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, family,
FC_SPACING, FcTypeInteger, fixed, NULL);
if (!pattern) {
__glcRaiseError(GLC_RESOURCE_ERROR);
FcFontSetDestroy(fontSet);
return -1;
}
if (inPatternProcess(fontSet, pattern, font, inData)) {
*outPattern = pattern;
*outFontSet = fontSet;
return font;
}
FcPatternDestroy(pattern);
}
*outPattern = NULL;
*outFontSet = fontSet;
return font;
}
static GLboolean __glcCheckHashValue(FcFontSet* GLC_UNUSED_ARG(inFontSet),
FcPattern* inPattern,
int GLC_UNUSED_ARG(inFont), void* inData)
{
GLCchar32 hashValue = *((GLCchar32*)inData);
if (hashValue == FcPatternHash(inPattern))
return GL_TRUE;
return GL_FALSE;
}
/* Constructor of the object : it allocates memory and initializes the member
* of the new object.
*/
__GLCmaster* __glcMasterCreate(const GLint inMaster,
const __GLCcontext* inContext)
{
__GLCmaster* This = NULL;
GLCchar32 hashValue =
((GLCchar32*)GLC_ARRAY_DATA(inContext->masterHashTable))[inMaster];
FcFontSet *fontSet = NULL;
FcPattern *pattern = NULL;
int font = __glcScanFonts(inContext, &fontSet, &pattern, __glcCheckHashValue,
&hashValue);
assert(font < fontSet->nfont);
FcFontSetDestroy(fontSet);
if (font < 0)
return NULL;
This = (__GLCmaster*)__glcMalloc(sizeof(__GLCmaster));
if (!This) {
__glcRaiseError(GLC_RESOURCE_ERROR);
FcPatternDestroy(pattern);
return NULL;
}
memset(This, 0, sizeof(__GLCmaster));
/* Duplicate the pattern of the found font (otherwise it will be deleted with
* the font set).
*/
This->pattern = pattern;
return This;
}
/* Destructor of the object */
void __glcMasterDestroy(__GLCmaster* This)
{
FcPatternDestroy(This->pattern);
__glcFree(This);
}
static GLboolean __glcFindMasterIndex(FcFontSet* GLC_UNUSED_ARG(inFontSet),
FcPattern* inPattern,
int GLC_UNUSED_ARG(inFont), void* inData)
{
const __GLCmaster* This = ((__GLCdata*)inData)->master;
GLint *idx = ((__GLCdata*)inData)->index;
FcBool equal = FcPatternEqual(inPattern, This->pattern);
if (equal) {
if (*idx)
(*idx)--;
else
return GL_TRUE;
}
return GL_FALSE;
}
/* Get the style name of the face identified by inIndex */
GLCchar8* __glcMasterGetFaceName(const __GLCmaster* This,
const __GLCcontext* inContext,
const GLint inIndex)
{
FcFontSet *fontSet = NULL;
FcPattern *pattern = NULL;
GLCchar8* string = NULL;
GLCchar8* faceName;
GLint idx = inIndex;
__GLCdata data = {NULL, NULL};
int font = 0;
#ifdef DEBUGMODE
FcResult result = FcResultMatch;
#endif
data.master = This;
data.index = &idx;
font = __glcScanFonts(inContext, &fontSet, &pattern, __glcFindMasterIndex,
&data);
FcPatternDestroy(pattern);
if (font < 0) {
FcFontSetDestroy(fontSet);
return NULL;
}
if (font == fontSet->nfont) {
__glcRaiseError(GLC_PARAMETER_ERROR);
FcFontSetDestroy(fontSet);
return NULL;
}
#ifdef DEBUGMODE
result = FcPatternGetString(fontSet->fonts[font], FC_STYLE, 0, &string);
assert(result != FcResultTypeMismatch);
#else
FcPatternGetString(fontSet->fonts[font], FC_STYLE, 0, &string);
#endif
#ifdef __WIN32__
faceName = (GLCchar8*)_strdup((const char*)string);
#else
faceName = (GLCchar8*)strdup((const char*)string);
#endif
FcFontSetDestroy(fontSet);
if (!faceName) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
return faceName;
}
/* Is this a fixed font ? */
GLboolean __glcMasterIsFixedPitch(const __GLCmaster* This)
{
int fixed = 0;
#ifdef DEBUGMODE
FcResult result = FcResultMatch;
result = FcPatternGetInteger(This->pattern, FC_SPACING, 0, &fixed);
assert(result != FcResultTypeMismatch);
#else
FcPatternGetInteger(This->pattern, FC_SPACING, 0, &fixed);
#endif
return fixed ? GL_TRUE: GL_FALSE;
}
static GLboolean __glcCountFaces(FcFontSet* GLC_UNUSED_ARG(inFontSet),
FcPattern* inPattern,
int GLC_UNUSED_ARG(inFont), void* inData)
{
const __GLCmaster* This = ((__GLCdata*)inData)->master;
GLint *count = ((__GLCdata*)inData)->index;
FcBool equal = FcPatternEqual(inPattern, This->pattern);
if (equal)
(*count)++;
return GL_FALSE;
}
/* Get the face count of the master */
GLint __glcMasterFaceCount(const __GLCmaster* This,
const __GLCcontext* inContext)
{
FcFontSet *fontSet = NULL;
GLint count = 0;
FcPattern* pattern = NULL;
__GLCdata data = {NULL, NULL};
int font = 0;
data.master = This;
data.index = &count;
font = __glcScanFonts(inContext, &fontSet, &pattern, __glcCountFaces, &data);
FcFontSetDestroy(fontSet);
if (font < 0)
return 0;
return count;
}
/* This subroutine is called whenever the user wants to access to informations
* that have not been loaded from the font files yet. In order to reduce disk
* accesses, informations such as the master format, full name or version are
* read "just in time" i.e. only when the user requests them.
*/
const GLCchar8* __glcMasterGetInfo(const __GLCmaster* This,
__GLCcontext* inContext,
const GLCenum inAttrib)
{
__GLCfaceDescriptor* faceDesc = NULL;
#ifdef DEBUGMODE
FcResult result = FcResultMatch;
#endif
GLCchar8 *string = NULL;
const GLCchar8* info = NULL;
const GLCchar8 *buffer = NULL;
/* Get the Unicode string which corresponds to the requested attribute */
switch(inAttrib) {
case GLC_FAMILY:
#ifdef DEBUGMODE
result = FcPatternGetString(This->pattern, FC_FAMILY, 0, &string);
assert(result != FcResultTypeMismatch);
#else
FcPatternGetString(This->pattern, FC_FAMILY, 0, &string);
#endif
return string;
case GLC_VENDOR:
#ifdef DEBUGMODE
result = FcPatternGetString(This->pattern, FC_FOUNDRY, 0, &string);
assert(result != FcResultTypeMismatch);
#else
FcPatternGetString(This->pattern, FC_FOUNDRY, 0, &string);
#endif
return string;
case GLC_VERSION:
case GLC_FULL_NAME_SGI:
case GLC_MASTER_FORMAT:
faceDesc = __glcFaceDescCreate(This, NULL, inContext, 0);
if (!faceDesc)
return NULL;
#ifndef GLC_FT_CACHE
if (!__glcFaceDescOpen(faceDesc, inContext)) {
__glcFaceDescDestroy(faceDesc, inContext);
return NULL;
}
#endif
info = __glcFaceDescGetFontFormat(faceDesc, inContext, inAttrib);
if (info) {
/* Convert the string and store it in the context buffer */
buffer = (const GLCchar8*)__glcConvertFromUtf8ToBuffer(inContext, info);
}
else
__glcRaiseError(GLC_RESOURCE_ERROR);
if (faceDesc) {
#ifndef GLC_FT_CACHE
__glcFaceDescClose(faceDesc);
#endif
__glcFaceDescDestroy(faceDesc, inContext);
}
return buffer;
}
/* The program is not supposed to reach the end of the function.
* The following return is there to prevent the compiler to issue
* a warning about 'control reaching the end of a non-void function'.
*/
return (const GLCchar8*)"";
}
static GLboolean __glcFindFamily(FcFontSet* inFontSet,
FcPattern* GLC_UNUSED_ARG(inPattern),
int inFont, void* inData)
{
FcChar8* family = NULL;
#ifdef DEBUGMODE
FcResult result = FcPatternGetString(inFontSet->fonts[inFont], FC_FAMILY, 0,
&family);
assert(result != FcResultTypeMismatch);
#else
FcPatternGetString(inFontSet->fonts[inFont], FC_FAMILY, 0, &family);
#endif
if (strcmp((const char*)family, (const char*)inData))
return GL_FALSE;
return GL_TRUE;
}
/* Create a master on the basis of the family name */
__GLCmaster* __glcMasterFromFamily(const __GLCcontext* inContext,
const GLCchar8* inFamily)
{
FcFontSet *fontSet = NULL;
FcPattern* pattern = NULL;
__GLCmaster* This = NULL;
int font = __glcScanFonts(inContext, &fontSet, &pattern, __glcFindFamily,
(void*)inFamily);
if (font < 0) {
if (pattern)
FcPatternDestroy(pattern);
FcFontSetDestroy(fontSet);
return NULL;
}
assert(fontSet);
if (font == fontSet->nfont) {
__glcRaiseError(GLC_PARAMETER_ERROR);
if (pattern)
FcPatternDestroy(pattern);
FcFontSetDestroy(fontSet);
return NULL;
}
assert(pattern);
This = (__GLCmaster*)__glcMalloc(sizeof(__GLCmaster));
if (!This) {
__glcRaiseError(GLC_RESOURCE_ERROR);
FcFontSetDestroy(fontSet);
FcPatternDestroy(pattern);
return NULL;
}
memset(This, 0, sizeof(__GLCmaster));
This->pattern = pattern;
FcFontSetDestroy(fontSet);
return This;
}
/* Create a master which contains at least a font which math the character
* identified by inCode.
*/
__GLCmaster* __glcMasterMatchCode(const __GLCcontext* inContext,
const GLint inCode)
{
__GLCmaster* This = NULL;
FcPattern* pattern = NULL;
FcFontSet* fontSet = NULL;
FcFontSet* fontSet2 = NULL;
FcObjectSet* objectSet = NULL;
FcResult result = FcResultMatch;
int f = 0;
FcChar8* family = NULL;
int fixed = 0;
FcChar8* foundry = NULL;
FcCharSet* charSet = FcCharSetCreate();
if (!charSet)
return NULL;
if (!FcCharSetAddChar(charSet, inCode)) {
FcCharSetDestroy(charSet);
return NULL;
}
pattern = FcPatternBuild(NULL, FC_CHARSET, FcTypeCharSet, charSet,
FC_OUTLINE, FcTypeBool, FcTrue, NULL);
FcCharSetDestroy(charSet);
if (!pattern) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
if (!FcConfigSubstitute(inContext->config, pattern, FcMatchPattern)) {
__glcRaiseError(GLC_RESOURCE_ERROR);
FcPatternDestroy(pattern);
return NULL;
}
FcDefaultSubstitute(pattern);
fontSet = FcFontSort(inContext->config, pattern, FcFalse, NULL, &result);
FcPatternDestroy(pattern);
if ((!fontSet) || (result == FcResultTypeMismatch)) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
for (f = 0; f < fontSet->nfont; f++) {
FcBool outline = FcFalse;
#ifdef DEBUGMODE
result = FcPatternGetBool(fontSet->fonts[f], FC_OUTLINE, 0, &outline);
assert(result != FcResultTypeMismatch);
result = FcPatternGetCharSet(fontSet->fonts[f], FC_CHARSET, 0, &charSet);
assert(result != FcResultTypeMismatch);
#else
FcPatternGetBool(fontSet->fonts[f], FC_OUTLINE, 0, &outline);
FcPatternGetCharSet(fontSet->fonts[f], FC_CHARSET, 0, &charSet);
#endif
if (outline && FcCharSetHasChar(charSet, inCode))
break;
}
if (f == fontSet->nfont) {
FcFontSetDestroy(fontSet);
return NULL;
}
/* Ugly hack to extract a subset of the pattern fontSet->fonts[f]
* (otherwise the hash value will not match any value of the hash table).
*/
objectSet = FcObjectSetBuild(FC_FAMILY, FC_FOUNDRY, FC_OUTLINE, FC_SPACING,
NULL);
if (!objectSet) {
__glcRaiseError(GLC_RESOURCE_ERROR);
FcFontSetDestroy(fontSet);
return NULL;
}
fontSet2 = FcFontList(inContext->config, fontSet->fonts[f], objectSet);
FcObjectSetDestroy(objectSet);
if (!fontSet2) {
__glcRaiseError(GLC_RESOURCE_ERROR);
FcFontSetDestroy(fontSet);
return NULL;
}
assert(fontSet2->nfont);
This = (__GLCmaster*)__glcMalloc(sizeof(__GLCmaster));
if (!This) {
__glcRaiseError(GLC_RESOURCE_ERROR);
FcFontSetDestroy(fontSet);
FcFontSetDestroy(fontSet2);
return NULL;
}
memset(This, 0, sizeof(__GLCmaster));
/* Duplicate the pattern of the found font (otherwise it will be deleted with
* the font set).
*/
#ifdef DEBUGMODE
result = FcPatternGetString(fontSet2->fonts[0], FC_FAMILY, 0, &family);
assert(result != FcResultTypeMismatch);
result = FcPatternGetString(fontSet2->fonts[0], FC_FOUNDRY, 0, &foundry);
assert(result != FcResultTypeMismatch);
result = FcPatternGetInteger(fontSet2->fonts[0], FC_SPACING, 0, &fixed);
assert(result != FcResultTypeMismatch);
#else
FcPatternGetString(fontSet2->fonts[0], FC_FAMILY, 0, &family);
FcPatternGetString(fontSet2->fonts[0], FC_FOUNDRY, 0, &foundry);
FcPatternGetInteger(fontSet2->fonts[0], FC_SPACING, 0, &fixed);
#endif
if (foundry)
pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, family, FC_FOUNDRY,
FcTypeString, foundry, FC_SPACING, FcTypeInteger,
fixed, NULL);
else
pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, family, FC_SPACING,
FcTypeInteger, fixed, NULL);
FcFontSetDestroy(fontSet2);
FcFontSetDestroy(fontSet);
if (!pattern) {
__glcRaiseError(GLC_RESOURCE_ERROR);
__glcFree(This);
return NULL;
}
This->pattern = pattern;
return This;
}
GLint __glcMasterGetID(const __GLCmaster* This, const __GLCcontext* inContext)
{
GLCchar32 hashValue = GLC_MASTER_HASH_VALUE(This);
GLint i = 0;
GLCchar32* hashTable = (GLCchar32*)GLC_ARRAY_DATA(inContext->masterHashTable);
for (i = 0; i < GLC_ARRAY_LENGTH(inContext->masterHashTable); i++) {
if (hashValue == hashTable[i])
break;
}
assert(i < GLC_ARRAY_LENGTH(inContext->masterHashTable));
return i;
}

55
3rdparty/quesoglc/omaster.h vendored Normal file
View File

@ -0,0 +1,55 @@
/* QuesoGLC
* A free implementation of the OpenGL Character Renderer (GLC)
* Copyright (c) 2002, 2004-2008, 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$ */
/** \file
* header of the object __GLCmaster which manage the masters
*/
#ifndef __glc_omaster_h
#define __glc_omaster_h
#include <fontconfig/fontconfig.h>
#include "ocharmap.h"
#define GLC_MASTER_HASH_VALUE(master) FcPatternHash((master)->pattern)
struct __GLCmasterRec {
FcPattern* pattern;
};
__GLCmaster* __glcMasterCreate(const GLint inMaster,
const __GLCcontext* inContext);
void __glcMasterDestroy(__GLCmaster* This);
GLCchar8* __glcMasterGetFaceName(const __GLCmaster* This,
const __GLCcontext* inContext,
const GLint inIndex);
GLboolean __glcMasterIsFixedPitch(const __GLCmaster* This);
GLint __glcMasterFaceCount(const __GLCmaster* This,
const __GLCcontext* inContext);
const GLCchar8* __glcMasterGetInfo(const __GLCmaster* This,
__GLCcontext* inContext,
const GLCenum inAttrib);
__GLCmaster* __glcMasterFromFamily(const __GLCcontext* inContext,
const GLCchar8* inFamily);
__GLCmaster* __glcMasterMatchCode(const __GLCcontext* inContext,
const GLint inCode);
GLint __glcMasterGetID(const __GLCmaster* This, const __GLCcontext* inContext);
#endif

24
3rdparty/quesoglc/qglc_config.h vendored Normal file
View File

@ -0,0 +1,24 @@
/* Name of package */
#define PACKAGE "quesoglc"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "quesoglc-general@lists.sourceforge.net"
/* Define to the full name of this package. */
#define PACKAGE_NAME "QuesoGLC"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "QuesoGLC custom"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "quesoglc"
/* Define to the home page for this package. */
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "9999"
/* Version number of package */
#define VERSION "9999"

996
3rdparty/quesoglc/render.c vendored Normal file
View File

@ -0,0 +1,996 @@
/* 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$ */
/** \file
* defines the so-called "Rendering commands" described in chapter 3.9 of the
* GLC specs.
*/
/** \defgroup render Rendering commands
* These are the commands that render characters to a GL render target. Those
* commands gather glyph datas according to the parameters that has been set in
* the state machine of GLC, and issue GL commands to render the characters
* layout to the GL render target.
*
* When it renders a character, GLC finds a font that maps the character code
* to a character such as LATIN CAPITAL LETTER A, then uses one or more glyphs
* from the font to create a graphical layout that represents the character.
* Finally, GLC issues a sequence of GL commands to draw the layout. Glyph
* coordinates are defined in EM units and are transformed during rendering to
* produce the desired mapping of the glyph shape into the GL window coordinate
* system.
*
* If GLC cannot find a font that maps the character code in the list
* \b GLC_CURRENT_FONT_LIST, it attemps to produce an alternate rendering. If
* the value of the boolean variable \b GLC_AUTO_FONT is set to \b GL_TRUE, GLC
* searches for a font that has the character that maps the character code. If
* the search succeeds, the font's ID is appended to \b GLC_CURRENT_FONT_LIST
* and the character is rendered.
*
* If there are fonts in the list \b GLC_CURRENT_FONT_LIST, but a match for
* the character code cannot be found in any of those fonts, GLC goes through
* the following steps :
* -# If the value of the variable \b GLC_REPLACEMENT_CODE is nonzero,
* GLC finds a font that maps the replacement code, and renders the character
* that the replacement code is mapped to.
* -# If the variable \b GLC_REPLACEMENT_CODE is zero, or if the replacement
* code does not result in a match, GLC checks whether a callback function is
* defined. If a callback function is defined for \b GLC_OP_glcUnmappedCode,
* GLC calls the function. The callback function provides the character code to
* the user and allows loading of the appropriate font. After the callback
* returns, GLC tries to render the character code again.
* -# Otherwise, the command attemps to render the character sequence
* <em>\\\<hexcode\></em>, where \\ is the character REVERSE SOLIDUS (U+5C),
* \< is the character LESS-THAN SIGN (U+3C), \> is the character GREATER-THAN
* SIGN (U+3E), and \e hexcode is the character code represented as a sequence
* of hexadecimal digits. The sequence has no leading zeros, and alphabetic
* digits are in upper case. The GLC measurement commands treat the sequence
* as a single character.
*
* \note The rendering commands may issue GL commands, hence a GL context must
* be bound to the current thread such that the GLC commands produce the desired
* result. It is the responsibility of the GLC client to set up the underlying
* GL implementation.
*
* \note Some rendering commands create and/or use display lists and/or
* textures. The IDs of those display lists and textures are stored in the
* current GLC context but the display lists and the textures themselves are
* managed by the current GL context. In order not to impact the performance of
* error-free programs, QuesoGLC does not check if the current GL context is
* the same than the one where the display lists and the textures were actually
* created. If the current GL context has changed meanwhile, the result of
* commands that refer to the corresponding display lists or textures is
* undefined.
*/
#include "internal.h"
#if defined __APPLE__ && defined __MACH__
#include <OpenGL/glu.h>
#else
#include <GL/glu.h>
#endif
#include <math.h>
#include "texture.h"
/* This internal function renders a glyph using the GLC_BITMAP format */
/* TODO : Render Bitmap fonts */
static void __glcRenderCharBitmap(const __GLCfont* inFont,
const __GLCcontext* inContext,
const GLfloat inScaleX,
const GLfloat inScaleY,
const GLfloat* inAdvance,
const GLboolean inIsRTL)
{
GLfloat *transform = inContext->bitmapMatrix;
GLint pixWidth = 0, pixHeight = 0;
GLubyte* pixBuffer = NULL;
GLint pixBoundingBox[4] = {0, 0, 0, 0};
__glcFontGetBitmapSize(inFont, &pixWidth, &pixHeight, inScaleX, inScaleY, 0,
pixBoundingBox, inContext);
pixBuffer = (GLubyte *)__glcMalloc(pixWidth * pixHeight);
if (!pixBuffer) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return;
}
/* render the glyph */
if (!__glcFontGetBitmap(inFont, pixWidth, pixHeight, pixBuffer, inContext)) {
__glcFree(pixBuffer);
return;
}
/* Do the actual GL rendering */
if (inIsRTL) {
glBitmap(0, 0, 0, 0,
inAdvance[1] * transform[2] - inAdvance[0] * transform[0],
inAdvance[1] * transform[3] - inAdvance[0] * transform[1],
NULL);
glBitmap(pixWidth, pixHeight, - pixBoundingBox[0] >> 6,
-pixBoundingBox[1] >> 6, 0., 0., pixBuffer);
}
else
glBitmap(pixWidth, pixHeight, -pixBoundingBox[0] >> 6,
-pixBoundingBox[1] >> 6,
inAdvance[0] * transform[0] + inAdvance[1] * transform[2],
inAdvance[0] * transform[1] + inAdvance[1] * transform[3],
pixBuffer);
__glcFree(pixBuffer);
}
/* This internal function renders a glyph using the GLC_PIXMAP_QSO format */
static void __glcRenderCharPixmap(const __GLCfont* inFont,
const __GLCcontext* inContext,
const GLfloat scaleX, const GLfloat scaleY,
const GLfloat* advance,
const GLboolean inIsRTL)
{
GLfloat *transform = inContext->bitmapMatrix;
GLint pixWidth = 0, pixHeight = 0;
GLubyte* pixBuffer = NULL;
GLint pixBoundingBox[4] = {0, 0, 0, 0};
__glcFontGetBitmapSize(inFont, &pixWidth, &pixHeight, scaleX, scaleY, 0,
pixBoundingBox, inContext);
pixBuffer = (GLubyte *)__glcMalloc(pixWidth * pixHeight);
if (!pixBuffer) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return;
}
/* render the glyph */
if (!__glcFontGetBitmap(inFont, pixWidth, pixHeight, pixBuffer, inContext)) {
__glcFree(pixBuffer);
return;
}
/* Do the actual GL rendering */
if (inIsRTL) {
glBitmap(0, 0, 0.f, 0.f,
advance[1] * transform[2] - advance[0] * transform[0] +
(pixBoundingBox[0] >> 6),
advance[1] * transform[3] - advance[0] * transform[1] +
(pixBoundingBox[1] >> 6),
NULL);
glDrawPixels(pixWidth, pixHeight, GL_ALPHA, GL_UNSIGNED_BYTE, pixBuffer);
glBitmap(0, 0, 0.f, 0.f,
-(pixBoundingBox[0] >> 6),
-(pixBoundingBox[1] >> 6),
NULL);
}
else {
glBitmap(0, 0, 0.f, 0.f,
pixBoundingBox[0] >> 6,
pixBoundingBox[1] >> 6,
NULL);
glDrawPixels(pixWidth, pixHeight, GL_ALPHA, GL_UNSIGNED_BYTE, pixBuffer);
glBitmap(0, 0, 0.f, 0.f,
advance[0] * transform[0] + advance[1] * transform[2] -
(pixBoundingBox[0] >> 6),
advance[0] * transform[1] + advance[1] * transform[3] -
(pixBoundingBox[1] >> 6),
NULL);
}
__glcFree(pixBuffer);
}
/* Internal function that is called to do the actual rendering :
* 'inCode' must be given in UCS-4 format
*/
static void* __glcRenderChar(const GLint inCode, const GLint inPrevCode,
const GLboolean inIsRTL, const __GLCfont* inFont,
__GLCcontext* inContext,
const void* GLC_UNUSED_ARG(inData),
const GLboolean GLC_UNUSED_ARG(inMultipleChars))
{
GLfloat transformMatrix[16];
GLfloat scaleX = GLC_POINT_SIZE;
GLfloat scaleY = GLC_POINT_SIZE;
__GLCglyph* glyph = NULL;
GLfloat sx64 = 0., sy64 = 0.;
GLfloat advance[2] = {0., 0.};
assert(inFont);
__glcGetScale(inContext, transformMatrix, &scaleX, &scaleY);
if ((fabs(scaleX) < GLC_EPSILON) || (fabs(scaleY) < GLC_EPSILON))
return NULL;
#ifndef GLC_FT_CACHE
if (!__glcFontOpen(inFont, inContext))
return NULL;
#endif
if (inPrevCode && inContext->enableState.kerning) {
GLfloat kerning[2];
GLint leftCode = inIsRTL ? inCode : inPrevCode;
GLint rightCode = inIsRTL ? inPrevCode : inCode;
if (__glcFontGetKerning(inFont, leftCode, rightCode, kerning, inContext,
scaleX, scaleY)) {
if (inIsRTL)
kerning[0] = -kerning[0];
if ((inContext->renderState.renderStyle == GLC_BITMAP)
|| (inContext->renderState.renderStyle == GLC_PIXMAP_QSO))
glBitmap(0, 0, 0, 0,
kerning[0] * inContext->bitmapMatrix[0]
+ kerning[1] * inContext->bitmapMatrix[2],
kerning[0] * inContext->bitmapMatrix[1]
+ kerning[1] * inContext->bitmapMatrix[3],
NULL);
else
glTranslatef(kerning[0], kerning[1], 0.f);
}
}
if (!__glcFontGetAdvance(inFont, inCode, advance, inContext, scaleX,
scaleY)) {
#ifndef GLC_FT_CACHE
__glcFontClose(inFont);
#endif
return NULL;
}
/* Get and load the glyph which unicode code is identified by inCode */
glyph = __glcFontGetGlyph(inFont, inCode, inContext);
if (inContext->enableState.glObjects
&& !__glcFontPrepareGlyph(inFont, inContext, scaleX, scaleY,
glyph->index)) {
#ifndef GLC_FT_CACHE
__glcFontClose(inFont);
#endif
return NULL;
}
sx64 = 64. * scaleX;
sy64 = 64. * scaleY;
if ((inContext->renderState.renderStyle != GLC_BITMAP)
&& (inContext->renderState.renderStyle != GLC_PIXMAP_QSO)) {
if (inIsRTL)
glTranslatef(-advance[0], advance[1], 0.f);
/* If the outline contains no point then the glyph represents a space
* character and there is no need to continue the process of rendering.
*/
if (!__glcFontOutlineEmpty(inFont)) {
/* Update the advance and return */
if (!inIsRTL)
glTranslatef(advance[0], advance[1], 0.f);
if (inContext->enableState.glObjects)
glyph->isSpacingChar = GL_TRUE;
#ifndef GLC_FT_CACHE
__glcFontClose(inFont);
#endif
return NULL;
}
/* coordinates are given in 26.6 fixed point integer hence we
* divide the scale by 2^6
*/
if (!inContext->enableState.glObjects)
glScalef(1. / sx64, 1. / sy64, 1.f);
}
/* Call the appropriate function depending on the rendering mode */
switch(inContext->renderState.renderStyle) {
case GLC_BITMAP:
__glcRenderCharBitmap(inFont, inContext, scaleX, scaleY, advance,
inIsRTL);
break;
case GLC_PIXMAP_QSO:
__glcRenderCharPixmap(inFont, inContext, scaleX, scaleY, advance,
inIsRTL);
break;
case GLC_TEXTURE:
__glcRenderCharTexture(inFont, inContext, scaleX, scaleY, glyph);
break;
case GLC_LINE:
__glcRenderCharScalable(inFont, inContext, transformMatrix, scaleX,
scaleY, glyph);
break;
case GLC_TRIANGLE:
__glcRenderCharScalable(inFont, inContext, transformMatrix, scaleX,
scaleY, glyph);
break;
default:
__glcRaiseError(GLC_PARAMETER_ERROR);
}
if ((inContext->renderState.renderStyle != GLC_BITMAP)
&& (inContext->renderState.renderStyle != GLC_PIXMAP_QSO)) {
if (!inContext->enableState.glObjects)
glScalef(sx64, sy64, 1.);
if (!inIsRTL)
glTranslatef(advance[0], advance[1], 0.f);
}
#ifndef GLC_FT_CACHE
__glcFontClose(inFont);
#endif
return NULL;
}
/* This internal function is used by both glcRenderString() and
* glcRenderCountedString(). The string 'inString' must be sorted in visual
* order and stored using UCS4 format.
*/
static void __glcRenderCountedString(__GLCcontext* inContext,
const GLCchar32* inString,
const GLboolean inIsRightToLeft,
const GLint inCount)
{
GLint listIndex = 0;
GLint i = 0;
const GLCchar32* ptr = NULL;
__GLCglState GLState;
__GLCcharacter prevCode = {0, NULL, NULL, {0.f, 0.f}};
GLboolean saveGLObjects = GL_FALSE;
GLint shift = 1;
__GLCcharacter* chars = NULL;
GLfloat pixmapColor[4];
/* Disable the internal management of GL objects when the user is currently
* building a display list.
*/
glGetIntegerv(GL_LIST_INDEX, &listIndex);
if (listIndex) {
saveGLObjects = inContext->enableState.glObjects;
inContext->enableState.glObjects = GL_FALSE;
}
/* Allocate a buffer to store the glyphes informations of the string to be
* rendered.
*/
if (inContext->enableState.glObjects
&& (inContext->renderState.renderStyle != GLC_BITMAP)
&& (inContext->renderState.renderStyle != GLC_PIXMAP_QSO)) {
chars = (__GLCcharacter*)__glcMalloc(inCount * sizeof(__GLCcharacter));
if (!chars) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return;
}
}
/* Save the value of the GL parameters */
__glcSaveGLState(&GLState, inContext, GL_FALSE);
/* Set the vertex arrays parameters for GLC_LINE and GLC_TRIANGLE rendering
* styles when GLC_GL_OBJECTS is enabled.
*/
if (inContext->renderState.renderStyle == GLC_LINE ||
(inContext->renderState.renderStyle == GLC_TRIANGLE
&& !(inContext->enableState.glObjects
&& inContext->enableState.extrude))) {
glEnableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_INDEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_EDGE_FLAG_ARRAY);
}
if (inContext->renderState.renderStyle == GLC_TRIANGLE
&& inContext->enableState.glObjects && inContext->enableState.extrude)
glEnable(GL_NORMALIZE);
/* Set the texture environment if the render style is GLC_TEXTURE */
if (inContext->renderState.renderStyle == GLC_TEXTURE) {
/* Set the new values of the parameters */
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
if (inContext->enableState.glObjects) {
if (inContext->atlas.id)
glBindTexture(GL_TEXTURE_2D, inContext->atlas.id);
if (GLEW_ARB_vertex_buffer_object) {
if (inContext->atlas.bufferObjectID) {
glBindBufferARB(GL_ARRAY_BUFFER_ARB, inContext->atlas.bufferObjectID);
glInterleavedArrays(GL_T2F_V3F, 0, NULL);
}
}
}
else if (inContext->texture.id) {
glBindTexture(GL_TEXTURE_2D, inContext->texture.id);
if (GLEW_ARB_pixel_buffer_object && inContext->texture.bufferObjectID)
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER,
inContext->texture.bufferObjectID);
}
}
if ((inContext->renderState.renderStyle == GLC_BITMAP)
|| (inContext->renderState.renderStyle == GLC_PIXMAP_QSO)) {
glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
if (inContext->renderState.renderStyle == GLC_PIXMAP_QSO) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glGetFloatv(GL_CURRENT_RASTER_COLOR, pixmapColor);
glPixelTransferf(GL_RED_BIAS, pixmapColor[0]);
glPixelTransferf(GL_GREEN_BIAS, pixmapColor[1]);
glPixelTransferf(GL_BLUE_BIAS, pixmapColor[2]);
glPixelTransferf(GL_ALPHA_BIAS, 0.f);
glPixelTransferf(GL_RED_SCALE, 1.f);
glPixelTransferf(GL_GREEN_SCALE, 1.f);
glPixelTransferf(GL_BLUE_SCALE, 1.f);
glPixelTransferf(GL_ALPHA_SCALE, pixmapColor[3]);
}
}
/* Render the string */
ptr = inString;
if (inIsRightToLeft) {
ptr += inCount - 1;
shift = -1;
}
if (inContext->enableState.glObjects
&& (inContext->renderState.renderStyle != GLC_BITMAP)
&& (inContext->renderState.renderStyle != GLC_PIXMAP_QSO)) {
__GLCfont* font = NULL;
__GLCglyph* glyph = NULL;
int length = 0;
int j = 0;
GLuint GLObjectIndex = inContext->renderState.renderStyle - 0x101;
FT_ListNode node = NULL;
float resolution = inContext->renderState.resolution / 72.;
GLfloat orientation = 1.f;
if (inContext->renderState.renderStyle == GLC_TRIANGLE
&& inContext->enableState.extrude) {
GLfloat transformMatrix[16];
GLfloat scaleX = GLC_POINT_SIZE;
GLfloat scaleY = GLC_POINT_SIZE;
__glcGetScale(inContext, transformMatrix, &scaleX, &scaleY);
if ((fabs(scaleX) < GLC_EPSILON) || (fabs(scaleY) < GLC_EPSILON))
return;
orientation = -transformMatrix[11];
GLObjectIndex++;
}
glNormal3f(0.f, 0.f, 1.f / resolution);
for (i = 0; i < inCount; i++) {
if (*ptr >= 32) {
for (node = inContext->currentFontList.head; node ; node = node->next) {
font = (__GLCfont*)node->data;
glyph = __glcCharMapGetGlyph(font->charMap, *ptr);
if (glyph) {
if (!glyph->glObject[GLObjectIndex] && !glyph->isSpacingChar)
continue;
if (!glyph->isSpacingChar
&& (inContext->renderState.renderStyle == GLC_TEXTURE))
FT_List_Up(&inContext->atlasList,
(FT_ListNode)glyph->textureObject);
chars[length].glyph = glyph;
chars[length].advance[0] = glyph->advance[0];
chars[length].advance[1] = glyph->advance[1];
if (inContext->enableState.kerning) {
if (prevCode.code && prevCode.font == font) {
GLfloat kerning[2];
GLint leftCode = inIsRightToLeft ? *ptr : prevCode.code;
GLint rightCode = inIsRightToLeft ? prevCode.code : *ptr;
if (__glcFontGetKerning(font, leftCode, rightCode, kerning,
inContext, GLC_POINT_SIZE,
GLC_POINT_SIZE)) {
if (inIsRightToLeft)
kerning[0] = -kerning[0];
if (length) {
chars[length - 1].advance[0] += kerning[0];
chars[length - 1].advance[1] += kerning[1];
}
else
glTranslatef(kerning[0], kerning[1], 0.f);
}
}
}
prevCode.font = font;
prevCode.code = *ptr;
if (glyph->isSpacingChar)
chars[length].code = 32;
else
chars[length].code = *ptr;
length++;
break;
}
}
}
if(!node || (i == inCount-1)) {
glScalef(resolution, resolution, 1.f);
for (j = 0; j < length; j++) {
if (inIsRightToLeft)
glTranslatef(-chars[j].advance[0], chars[j].advance[1], 0.);
if (chars[j].code != 32) {
glyph = chars[j].glyph;
switch(inContext->renderState.renderStyle) {
case GLC_TEXTURE:
if (GLEW_ARB_vertex_buffer_object)
glDrawArrays(GL_QUADS, glyph->textureObject->position * 4, 4);
else
glCallList(glyph->glObject[1]);
break;
case GLC_LINE:
if (GLEW_ARB_vertex_buffer_object) {
int k = 0;
glBindBufferARB(GL_ARRAY_BUFFER_ARB, glyph->glObject[0]);
glVertexPointer(2, GL_FLOAT, 0, NULL);
for (k = 0; k < glyph->nContour; k++)
glDrawArrays(GL_LINE_LOOP, glyph->contours[k],
glyph->contours[k+1] - glyph->contours[k]);
break;
}
glCallList(glyph->glObject[0]);
break;
case GLC_TRIANGLE:
if (GLEW_ARB_vertex_buffer_object) {
int k = 0;
GLboolean extrude = GL_FALSE;
glBindBufferARB(GL_ARRAY_BUFFER_ARB, glyph->glObject[0]);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
glyph->glObject[2]);
glVertexPointer(2, GL_FLOAT, 0, NULL);
do {
GLuint* vertexIndices = NULL;
if (orientation > 0.f) {
for (k = 0; k < glyph->nGeomBatch; k++) {
glDrawRangeElements(glyph->geomBatches[k].mode,
glyph->geomBatches[k].start,
glyph->geomBatches[k].end,
glyph->geomBatches[k].length,
GL_UNSIGNED_INT, vertexIndices);
vertexIndices += glyph->geomBatches[k].length;
}
}
if (inContext->enableState.extrude) {
if (extrude) {
glTranslatef(0.f, 0.f, 1.f);
glBindBufferARB(GL_ARRAY_BUFFER_ARB,
glyph->glObject[3]);
glInterleavedArrays(GL_N3F_V3F, 0, NULL);
for (k = 0; k < glyph->nContour; k++)
glDrawArrays(GL_TRIANGLE_STRIP, glyph->contours[k] * 2,
(glyph->contours[k+1] - glyph->contours[k]
+ 1) * 2);
glNormal3f(0.f, 0.f, 1.f / resolution);
}
else {
glNormal3f(0.f, 0.f, -1.f / resolution);
glTranslatef(0.f, 0.f, -1.f);
orientation = -orientation;
}
extrude = (!extrude);
}
} while(extrude);
}
else
glCallList(glyph->glObject[GLObjectIndex]);
break;
}
}
if (!inIsRightToLeft)
glTranslatef(chars[j].advance[0], chars[j].advance[1], 0.);
}
if (!node)
__glcProcessChar(inContext, *ptr, &prevCode, inIsRightToLeft,
__glcRenderChar, NULL);
glScalef(1./resolution, 1./resolution, 1.f);
length = 0;
}
ptr += shift;
}
}
else {
glNormal3f(0.f, 0.f, 1.f);
for (i = 0; i < inCount; i++) {
if (*ptr >= 32)
__glcProcessChar(inContext, *ptr, &prevCode, inIsRightToLeft,
__glcRenderChar, NULL);
ptr += shift;
}
}
/* Restore the values of the GL state if needed */
__glcRestoreGLState(&GLState, inContext, GL_FALSE);
if ((inContext->renderState.renderStyle != GLC_BITMAP)
&& (inContext->renderState.renderStyle != GLC_PIXMAP_QSO)
&& inContext->enableState.glObjects)
__glcFree(chars);
if (listIndex)
inContext->enableState.glObjects = saveGLObjects;
}
/** \ingroup render
* This command renders the character that \e inCode is mapped to.
* \param inCode The character to render
* \sa glcRenderString()
* \sa glcRenderCountedString()
* \sa glcReplacementCode()
* \sa glcRenderStyle()
* \sa glcCallbackFunc()
*/
void APIENTRY glcRenderChar(GLint inCode)
{
__GLCcontext *ctx = NULL;
GLint code = 0;
GLC_INIT_THREAD();
/* Check if the current thread owns a context state */
ctx = GLC_GET_CURRENT_CONTEXT();
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return;
}
/* Get the character code converted to the UCS-4 format */
code = __glcConvertGLintToUcs4(ctx, inCode);
if (code < 32)
return; /* Skip control characters and unknown characters */
__glcRenderCountedString(ctx, (GLCchar32*)&code, GL_FALSE, 1);
}
/** \ingroup render
* This command is identical to the command glcRenderChar(), except that it
* renders a string of characters. The string comprises the first \e inCount
* elements of the array \e inString, which need not be followed by a zero
* element.
*
* The command raises \b GLC_PARAMETER_ERROR if \e inCount is less than zero.
* \param inCount The number of elements in the string to be rendered
* \param inString The array of characters from which to render \e inCount
* elements.
* \sa glcRenderChar()
* \sa glcRenderString()
*/
void APIENTRY glcRenderCountedString(GLint inCount, const GLCchar *inString)
{
__GLCcontext *ctx = NULL;
GLCchar32* UinString = NULL;
GLboolean isRightToLeft = GL_FALSE;
GLC_INIT_THREAD();
/* Check if inCount is positive */
if (inCount < 0) {
__glcRaiseError(GLC_PARAMETER_ERROR);
return;
}
/* Check if the current thread owns a context state */
ctx = GLC_GET_CURRENT_CONTEXT();
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return;
}
/* If inString is NULL then there is no point in continuing */
if (!inString)
return;
/* Creates a Unicode string based on the current string type. Basically,
* that means that inString is read in the current string format.
*/
UinString = __glcConvertCountedStringToVisualUcs4(ctx, &isRightToLeft,
inString, inCount);
if (!UinString)
return;
__glcRenderCountedString(ctx, UinString, isRightToLeft, inCount);
}
/** \ingroup render
* This command is identical to the command glcRenderCountedString(), except
* that \e inString is zero terminated, not counted.
* \param inString A zero-terminated string of characters.
* \sa glcRenderChar()
* \sa glcRenderCountedString()
*/
void APIENTRY glcRenderString(const GLCchar *inString)
{
__GLCcontext *ctx = NULL;
GLCchar32* UinString = NULL;
GLboolean isRightToLeft = GL_FALSE;
GLint length = 0;
GLC_INIT_THREAD();
/* Check if the current thread owns a context state */
ctx = GLC_GET_CURRENT_CONTEXT();
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return;
}
/* If inString is NULL then there is no point in continuing */
if (!inString)
return;
/* Creates a Unicode string based on the current string type. Basically,
* that means that inString is read in the current string format.
*/
UinString = __glcConvertToVisualUcs4(ctx, &isRightToLeft, &length, inString);
if (!UinString)
return;
__glcRenderCountedString(ctx, UinString, isRightToLeft, length);
}
/** \ingroup render
* This command assigns the value \e inStyle to the variable
* \b GLC_RENDER_STYLE. Legal values for \e inStyle are defined in the table
* below :
* <center>
* <table>
* <caption>Rendering styles</caption>
* <tr>
* <td>Name</td> <td>Enumerant</td>
* </tr>
* <tr>
* <td><b>GLC_BITMAP</b></td> <td>0x0100</td>
* </tr>
* <tr>
* <td><b>GLC_LINE</b></td> <td>0x0101</td>
* </tr>
* <tr>
* <td><b>GLC_TEXTURE</b></td> <td>0x0102</td>
* </tr>
* <tr>
* <td><b>GLC_TRIANGLE</b></td> <td>0x0103</td>
* </tr>
* <tr>
* <td><b>GLC_PIXMAP_QSO</b></td> <td>0x8011</td>
* </tr>
* </table>
* </center>
* \param inStyle The value to assign to the variable \b GLC_RENDER_STYLE.
* \sa glcGeti() with argument \b GLC_RENDER_STYLE
*/
void APIENTRY glcRenderStyle(GLCenum inStyle)
{
__GLCcontext *ctx = NULL;
GLC_INIT_THREAD();
/* Check if inStyle has a legal value */
switch(inStyle) {
case GLC_BITMAP:
case GLC_LINE:
case GLC_TEXTURE:
case GLC_TRIANGLE:
case GLC_PIXMAP_QSO:
break;
default:
__glcRaiseError(GLC_PARAMETER_ERROR);
return;
}
/* Check if the current thread owns a current state */
ctx = GLC_GET_CURRENT_CONTEXT();
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return;
}
/* Stores the rendering style */
ctx->renderState.renderStyle = inStyle;
return;
}
/** \ingroup render
* This command assigns the value \e inCode to the variable
* \b GLC_REPLACEMENT_CODE. The replacement code is the code which is used
* whenever glcRenderChar() can not find a font that owns a character which
* the parameter \e inCode of glcRenderChar() maps to.
* \param inCode An integer to assign to \b GLC_REPLACEMENT_CODE.
* \sa glcGeti() with argument \b GLC_REPLACEMENT_CODE
* \sa glcRenderChar()
*/
void APIENTRY glcReplacementCode(GLint inCode)
{
__GLCcontext *ctx = NULL;
GLint code = 0;
GLC_INIT_THREAD();
/* Check if the current thread owns a current state */
ctx = GLC_GET_CURRENT_CONTEXT();
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return;
}
/* Get the replacement character converted to the UCS-4 format */
code = __glcConvertGLintToUcs4(ctx, inCode);
if (code < 0)
return;
/* Stores the replacement code */
ctx->stringState.replacementCode = code;
return;
}
/** \ingroup render
* This command assigns the value \e inVal to the variable \b GLC_RESOLUTION.
* It is used to compute the size of characters in pixels from the size in
* points.
*
* The resolution is given in \e dpi (dots per inch). If \e inVal is zero, the
* resolution defaults to 72 dpi.
*
* The command raises \b GLC_PARAMETER_ERROR if \e inVal is negative.
* \param inVal A floating point number to be used as resolution.
* \sa glcGetf() with argument GLC_RESOLUTION
*/
void APIENTRY glcResolution(GLfloat inVal)
{
__GLCcontext *ctx = NULL;
FT_ListNode node = NULL;
GLC_INIT_THREAD();
/* Negative resolutions are illegal */
if (inVal < 0) {
__glcRaiseError(GLC_PARAMETER_ERROR);
return;
}
/* Check if the current thread owns a current state */
ctx = GLC_GET_CURRENT_CONTEXT();
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return;
}
/* Stores the resolution */
ctx->renderState.resolution = (inVal < GLC_EPSILON) ? 72. : inVal;
/* Force the measurement caches to be updated */
for (node = ctx->fontList.head; node; node = node->next) {
__GLCfont* font = (__GLCfont*)node->data;
__GLCfaceDescriptor* faceDesc = font->faceDesc;
FT_ListNode glyphNode = NULL;
font->maxMetricCached = GL_FALSE;
for (glyphNode = faceDesc->glyphList.head; glyphNode;
glyphNode = glyphNode->next) {
__GLCglyph* glyph = (__GLCglyph*)glyphNode->data;
glyph->advanceCached = GL_FALSE;
glyph->boundingBoxCached = GL_FALSE;
}
}
return;
}
/** \ingroup render
* This command assigns the value \b inVal to the floating point variable
* identified by \e inAttrib which must be chosen in the table below.
*
* - \b GLC_PARAMETRIC_TOLERANCE_QSO specifies the maximum distance, in object
* space, between the tesselation line contours and the curves they
* approximate. This parameter is only relevant for the \b GLC_LINE and
* \b GLC_TRIANGLE rendering types.
*
* \param inAttrib A symbolic constant indicating a GLC attribute.
* \param inValue A floating point number to be used as tolerance.
* \sa glcGetf() with argument GLC_PARAMETRIC_TOLERANCE_QSO
*/
void APIENTRY glcRenderParameterfQSO(GLenum inAttrib, GLfloat inVal)
{
__GLCcontext *ctx = NULL;
GLC_INIT_THREAD();
/* Check if inAttrib has a legal value */
switch(inAttrib) {
case GLC_PARAMETRIC_TOLERANCE_QSO:
break;
default:
__glcRaiseError(GLC_PARAMETER_ERROR);
return;
}
if (inVal <= 0.f) {
__glcRaiseError(GLC_PARAMETER_ERROR);
return;
}
/* Check if the current thread owns a current state */
ctx = GLC_GET_CURRENT_CONTEXT();
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return;
}
/* Stores the tolerance */
ctx->renderState.tolerance = inVal;
return;
}

921
3rdparty/quesoglc/scalable.c vendored Normal file
View File

@ -0,0 +1,921 @@
/* 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$ */
/** \file
* defines the routines used to render characters with lines and triangles.
*/
#include "internal.h"
#if defined __APPLE__ && defined __MACH__
#include <OpenGL/glu.h>
#else
#include <GL/glu.h>
#endif
#include <math.h>
#define GLC_MAX_ITER 50
/* Transform the object coordinates in the array 'inCoord' in screen
* coordinates. The function updates 'inCoord' according to :
* inCoord[0..1] contains the 2D glyph coordinates in the object space
* inCoord[2..4] contains the 2D homogeneous coordinates in observer space
*/
static void __glcComputePixelCoordinates(GLfloat* inCoord,
const __GLCrendererData* inData)
{
GLfloat x = inCoord[0] * inData->transformMatrix[0]
+ inCoord[1] * inData->transformMatrix[4]
+ inData->transformMatrix[12];
GLfloat y = inCoord[0] * inData->transformMatrix[1]
+ inCoord[1] * inData->transformMatrix[5]
+ inData->transformMatrix[13];
GLfloat w = inCoord[0] * inData->transformMatrix[3]
+ inCoord[1] * inData->transformMatrix[7]
+ inData->transformMatrix[15];
GLfloat norm = x * x + y * y;
/* If w is very small compared to x, y and z this probably means that the
* transformation matrix is ill-conditioned (i.e. its determinant is
* numerically null)
*/
if (w * w < norm * GLC_EPSILON * GLC_EPSILON) {
/* Ugly hack to handle the singularity of w */
w = sqrt(norm) * GLC_EPSILON;
}
inCoord[2] = x;
inCoord[3] = y;
inCoord[4] = w;
}
/* __glcdeCasteljauConic :
* renders conic Bezier curves using the de Casteljau subdivision algorithm
*
* This function creates a piecewise linear curve which is close enough
* to the real Bezier curve. The piecewise linear curve is built so that
* the chordal distance is lower than a tolerance value.
* The chordal distance is taken to be the perpendicular distance from each
* control point to the chord. This may not always be correct, but, in the small
* lengths which are being considered, this is good enough.
* A second simplifying assumption is that when too large a chordal distance is
* encountered, the chord is split at the parametric midpoint, rather than
* guessing the exact location of the best chord. This could lead to slightly
* sub-optimal lines, but it provides a fast method for choosing the
* subdivision point. This guess can be refined by lengthening the lines.
*/
int __glcdeCasteljauConic(void *inUserData)
{
__GLCrendererData *data = (__GLCrendererData *) inUserData;
GLfloat* vector = data->vector;
GLfloat(*controlPoint)[5] = NULL;
GLint nArc = 1, arc = 0, rank = 0;
int iter = 0;
GLfloat* cp = (GLfloat*)__glcArrayInsertCell(data->controlPoints,
GLC_ARRAY_LENGTH(data->controlPoints), 3);
if (!cp) {
GLC_ARRAY_LENGTH(data->controlPoints) = 0;
return 1;
}
/* Append the control points to the vertex array */
memcpy(cp, vector, 2 * sizeof(GLfloat));
__glcComputePixelCoordinates(cp, data);
/* Append the first vertex of the curve to the vertex array */
rank = GLC_ARRAY_LENGTH(data->vertexArray);
if (!__glcArrayAppend(data->vertexArray, cp)) {
GLC_ARRAY_LENGTH(data->controlPoints) = 0;
return 1;
}
/* Build the array of the control points */
for (iter = 0; iter < 2; iter++) {
cp += 5;
vector += 2;
memcpy(cp, vector, 2 * sizeof(GLfloat));
__glcComputePixelCoordinates(cp, data);
}
/* controlPoint[] must be computed there because
* GLC_ARRAY_DATA(data->controlPoints) may have been modified by a realloc()
* in __glcArrayInsert().
*/
controlPoint = (GLfloat(*)[5])GLC_ARRAY_DATA(data->controlPoints);
/* Here the de Casteljau algorithm begins */
for (iter = 0; (iter < GLC_MAX_ITER) && (arc != nArc); iter++) {
GLfloat ax = controlPoint[0][2];
GLfloat ay = controlPoint[0][3];
GLfloat aw = controlPoint[0][4];
GLfloat abx = controlPoint[2][2]*aw - ax*controlPoint[2][4];
GLfloat aby = controlPoint[2][3]*aw - ay*controlPoint[2][4];
/* For the middle control point, compute its chordal distance that is its
* distance from the segment AB
*/
GLfloat mw = controlPoint[1][4];
GLfloat s = ((controlPoint[1][2]*aw - ax*mw) * aby
- (controlPoint[1][3]*aw - ay*mw) * abx)
/ (aw * mw);
GLfloat dmax = s * s;
if (dmax < data->tolerance * (abx * abx + aby *aby)) {
arc++; /* Process the next arc */
controlPoint = ((GLfloat(*)[5])GLC_ARRAY_DATA(data->controlPoints))+2*arc;
/* Update the place where new vertices will be inserted in the vertex
* array
*/
rank++;
}
else {
/* Split an arc into two smaller arcs (this is the actual de Casteljau
* algorithm)
*/
GLfloat *p1, *p2;
GLfloat *pm = (GLfloat*)__glcArrayInsertCell(data->controlPoints,
2*arc+1, 2);
if (!pm) {
GLC_ARRAY_LENGTH(data->controlPoints) = 0;
return 1;
}
/* controlPoint[] must be updated there because
* data->controlPoints->data may have been modified by a realloc() in
* __glcArrayInsert()
*/
controlPoint = ((GLfloat(*)[5])GLC_ARRAY_DATA(data->controlPoints))+2*arc;
p1 = controlPoint[0];
p2 = controlPoint[3];
pm = controlPoint[1];
pm[0] = 0.5*(p1[0]+p2[0]);
pm[1] = 0.5*(p1[1]+p2[1]);
pm[2] = 0.5*(p1[2]+p2[2]);
pm[3] = 0.5*(p1[3]+p2[3]);
pm[4] = 0.5*(p1[4]+p2[4]);
p1 = controlPoint[3];
p2 = controlPoint[4];
pm = controlPoint[3];
pm[0] = 0.5*(p1[0]+p2[0]);
pm[1] = 0.5*(p1[1]+p2[1]);
pm[2] = 0.5*(p1[2]+p2[2]);
pm[3] = 0.5*(p1[3]+p2[3]);
pm[4] = 0.5*(p1[4]+p2[4]);
p1 = controlPoint[1];
p2 = controlPoint[3];
pm = controlPoint[2];
pm[0] = 0.5*(p1[0]+p2[0]);
pm[1] = 0.5*(p1[1]+p2[1]);
pm[2] = 0.5*(p1[2]+p2[2]);
pm[3] = 0.5*(p1[3]+p2[3]);
pm[4] = 0.5*(p1[4]+p2[4]);
/* The point in pm[] is a point located on the Bezier curve : it must be
* added to the vertex array
*/
if (!__glcArrayInsert(data->vertexArray, rank+1, pm)) {
GLC_ARRAY_LENGTH(data->controlPoints) = 0;
return 1;
}
nArc++; /* A new arc has been defined */
}
}
/* The array of control points must be emptied in order to be ready for the
* next call to the de Casteljau routine
*/
GLC_ARRAY_LENGTH(data->controlPoints) = 0;
return 0;
}
/* __glcdeCasteljauCubic :
* renders cubic Bezier curves using the de Casteljau subdivision algorithm
*
* See also remarks about __glcdeCasteljauConic.
*/
int __glcdeCasteljauCubic(void *inUserData)
{
__GLCrendererData *data = (__GLCrendererData *) inUserData;
GLfloat* vector = data->vector;
GLfloat(*controlPoint)[5] = NULL;
GLint nArc = 1, arc = 0, rank = 0;
int iter = 0;
GLfloat* cp = (GLfloat*)__glcArrayInsertCell(data->controlPoints,
GLC_ARRAY_LENGTH(data->controlPoints), 4);
if (!cp) {
GLC_ARRAY_LENGTH(data->controlPoints) = 0;
return 1;
}
/* Append the control points to the vertex array */
memcpy(cp, vector, 2 * sizeof(GLfloat));
__glcComputePixelCoordinates(cp, data);
/* Append the first vertex of the curve to the vertex array */
rank = GLC_ARRAY_LENGTH(data->vertexArray);
if (!__glcArrayAppend(data->vertexArray, cp)) {
GLC_ARRAY_LENGTH(data->controlPoints) = 0;
return 1;
}
/* Build the array of the control points */
for (iter = 0; iter < 3; iter++) {
cp += 5;
vector += 2;
memcpy(cp, vector, 2 * sizeof(GLfloat));
__glcComputePixelCoordinates(cp, data);
}
/* controlPoint[] must be computed there because data->controlPoints->data
* may have been modified by a realloc() in __glcArrayInsert()
*/
controlPoint = (GLfloat(*)[5])GLC_ARRAY_DATA(data->controlPoints);
/* Here the de Casteljau algorithm begins */
for (iter = 0; (iter < GLC_MAX_ITER) && (arc != nArc); iter++) {
GLfloat ax = controlPoint[0][2];
GLfloat ay = controlPoint[0][3];
GLfloat aw = controlPoint[0][4];
GLfloat abx = controlPoint[3][2]*aw - ax*controlPoint[3][4];
GLfloat aby = controlPoint[3][3]*aw - ay*controlPoint[3][4];
/* For the middle control point, compute its chordal distance that is its
* distance from the segment AB
*/
GLfloat mw = controlPoint[1][4];
GLfloat s = ((controlPoint[1][2]*aw - ax*mw) * aby
- (controlPoint[1][3]*aw - ay*mw) * abx)
/ (aw * mw);
GLfloat dmax = s * s;
GLfloat d;
mw = controlPoint[2][4];
s = ((controlPoint[2][2]*aw - ax*mw) * aby
- (controlPoint[2][3]*aw - ay*mw) * abx)
/ (aw * mw);
d = s * s;
dmax = d > dmax ? d : dmax;
if (dmax < data->tolerance * (abx * abx + aby *aby)) {
arc++; /* Process the next arc */
controlPoint = ((GLfloat(*)[5])GLC_ARRAY_DATA(data->controlPoints))+3*arc;
/* Update the place where new vertices will be inserted in the vertex
* array
*/
rank++;
}
else {
/* Split an arc into two smaller arcs (this is the actual de Casteljau
* algorithm)
*/
GLfloat *p1, *p2, *p3;
GLfloat *pm = (GLfloat*)__glcArrayInsertCell(data->controlPoints,
3*arc+1, 3);
if (!pm) {
GLC_ARRAY_LENGTH(data->controlPoints) = 0;
return 1;
}
/* controlPoint[] must be updated there because
* data->controlPoints->data may have been modified by a realloc() in
* __glcArrayInsert()
*/
controlPoint = ((GLfloat(*)[5])GLC_ARRAY_DATA(data->controlPoints))+3*arc;
p1 = controlPoint[0];
p2 = controlPoint[4];
pm = controlPoint[1];
pm[0] = 0.5*(p1[0]+p2[0]);
pm[1] = 0.5*(p1[1]+p2[1]);
pm[2] = 0.5*(p1[2]+p2[2]);
pm[3] = 0.5*(p1[3]+p2[3]);
pm[4] = 0.5*(p1[4]+p2[4]);
p3 = controlPoint[5];
pm = controlPoint[2];
pm[0] = 0.25*(p1[0]+2*p2[0]+p3[0]);
pm[1] = 0.25*(p1[1]+2*p2[1]+p3[1]);
pm[2] = 0.25*(p1[2]+2*p2[2]+p3[2]);
pm[3] = 0.25*(p1[3]+2*p2[3]+p3[3]);
pm[4] = 0.25*(p1[4]+2*p2[4]+p3[4]);
p1 = controlPoint[6];
p2 = controlPoint[5];
pm = controlPoint[5];
pm[0] = 0.5*(p1[0]+p2[0]);
pm[1] = 0.5*(p1[1]+p2[1]);
pm[2] = 0.5*(p1[2]+p2[2]);
pm[3] = 0.5*(p1[3]+p2[3]);
pm[4] = 0.5*(p1[4]+p2[4]);
p1 = controlPoint[4];
p2 = controlPoint[5];
p3 = controlPoint[6];
pm = controlPoint[4];
pm[0] = 0.25*(p1[0]+4*p2[0]-p3[0]);
pm[1] = 0.25*(p1[1]+4*p2[1]-p3[1]);
pm[2] = 0.25*(p1[2]+4*p2[2]-p3[2]);
pm[3] = 0.25*(p1[3]+4*p2[3]-p3[3]);
pm[4] = 0.25*(p1[4]+4*p2[4]-p3[4]);
p1 = controlPoint[2];
p2 = controlPoint[4];
pm = controlPoint[3];
pm[0] = 0.5*(p1[0]+p2[0]);
pm[1] = 0.5*(p1[1]+p2[1]);
pm[2] = 0.5*(p1[2]+p2[2]);
pm[3] = 0.5*(p1[3]+p2[3]);
pm[4] = 0.5*(p1[4]+p2[4]);
/* The point in pm[] is a point located on the Bezier curve : it must be
* added to the vertex array
*/
if (!__glcArrayInsert(data->vertexArray, rank+1, pm)) {
GLC_ARRAY_LENGTH(data->controlPoints) = 0;
return 1;
}
nArc++; /* A new arc has been defined */
}
}
/* The array of control points must be emptied in order to be ready for the
* next call to the de Casteljau routine
*/
GLC_ARRAY_LENGTH(data->controlPoints) = 0;
return 0;
}
/* Callback function that is called by the GLU when it is tesselating a
* polygon.
*/
static void CALLBACK __glcCombineCallback(GLdouble coords[3],
void* GLC_UNUSED_ARG(vertex_data[4]),
GLfloat GLC_UNUSED_ARG(weight[4]),
void** outData, void* inUserData)
{
__GLCrendererData *data = (__GLCrendererData*)inUserData;
GLfloat vertex[2];
/* Evil hack for 32/64 bits compatibility */
union {
void* ptr;
GLuint i;
} uintInPtr;
/* Compute the new vertex and append it to the vertex array */
vertex[0] = (GLfloat)coords[0];
vertex[1] = (GLfloat)coords[1];
if (!__glcArrayAppend(data->vertexArray, vertex))
return;
/* Returns the index of the new vertex in the vertex array */
uintInPtr.i = GLC_ARRAY_LENGTH(data->vertexArray)-1;
*outData = uintInPtr.ptr;
}
/* Callback function that is called by the GLU when it is rendering the
* tesselated polygon. This function is needed to convert the indices of the
* vertex array into the coordinates of the vertex.
*/
static void CALLBACK __glcVertexCallback(void* vertex_data, void* inUserData)
{
__GLCrendererData *data = (__GLCrendererData*)inUserData;
__GLCgeomBatch *geomBatch =
((__GLCgeomBatch*)GLC_ARRAY_DATA(data->geomBatches));
/* Evil hack for 32/64 bits compatibility */
union {
void* ptr;
GLuint i;
} uintInPtr;
geomBatch += GLC_ARRAY_LENGTH(data->geomBatches) - 1;
uintInPtr.ptr = vertex_data;
geomBatch->start = (uintInPtr.i < geomBatch->start) ? uintInPtr.i :
geomBatch->start;
geomBatch->end = (uintInPtr.i > geomBatch->end) ? uintInPtr.i :
geomBatch->end;
if (!__glcArrayAppend(data->vertexIndices, &uintInPtr.i))
return;
geomBatch->length++;
}
static void CALLBACK __glcBeginCallback(GLenum mode, void* inUserData)
{
__GLCrendererData *data = (__GLCrendererData*)inUserData;
__GLCgeomBatch geomBatch;
geomBatch.mode = mode;
geomBatch.length = 0;
geomBatch.start = 0xffffffff;
geomBatch.end = 0;
__glcArrayAppend(data->geomBatches, &geomBatch);
}
/* Callback function that is called by the GLU whenever an error occur during
* the tesselation of the polygon.
*/
static void CALLBACK __glcCallbackError(GLenum GLC_UNUSED_ARG(inErrorCode))
{
__glcRaiseError(GLC_RESOURCE_ERROR);
}
/* Function called by __glcRenderChar() and that performs the actual rendering
* for the GLC_LINE and the GLC_TRIANGLE types. It transforms the outlines of
* the glyph in polygon contour. If the rendering type is GLC_LINE then the
* contour is rendered as is and if the rendering type is GLC_TRIANGLE then the
* contour defines a polygon that is tesselated in triangles by the GLU library
* before being rendered.
*/
void __glcRenderCharScalable(const __GLCfont* inFont,
const __GLCcontext* inContext,
GLfloat* inTransformMatrix, const GLfloat inScaleX,
const GLfloat inScaleY, __GLCglyph* inGlyph)
{
__GLCrendererData rendererData;
GLfloat identityMatrix[16] = {1., 0., 0., 0., 0., 1., 0., 0., 0., 0.,
1., 0., 0., 0., 0., 1.};
GLfloat sx64 = 64. * inScaleX;
GLfloat sy64 = 64. * inScaleY;
int objectIndex = 0;
GLfloat orientation = 1.f;
rendererData.vertexArray = inContext->vertexArray;
rendererData.controlPoints = inContext->controlPoints;
rendererData.endContour = inContext->endContour;
rendererData.vertexIndices = inContext->vertexIndices;
rendererData.geomBatches = inContext->geomBatches;
if (inContext->enableState.extrude)
orientation = -inTransformMatrix[11];
/* If no display list is planned to be built then compute distances in pixels
* otherwise use the object space.
*/
if (!inContext->enableState.glObjects) {
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
rendererData.halfWidth = viewport[2] * 0.5;
rendererData.halfHeight = viewport[3] * 0.5;
rendererData.transformMatrix = inTransformMatrix;
rendererData.transformMatrix[0] *= rendererData.halfWidth / sx64;
rendererData.transformMatrix[4] *= rendererData.halfWidth / sy64;
rendererData.transformMatrix[12] *= rendererData.halfWidth;
rendererData.transformMatrix[1] *= rendererData.halfHeight / sx64;
rendererData.transformMatrix[5] *= rendererData.halfHeight / sy64;
rendererData.transformMatrix[13] *= rendererData.halfHeight;
rendererData.transformMatrix[2] /= sx64;
rendererData.transformMatrix[3] /= sx64;
rendererData.transformMatrix[6] /= sy64;
rendererData.transformMatrix[7] /= sy64;
#if 0
rendererData.tolerance = .25; /* Half pixel tolerance */
#else
rendererData.tolerance = 1.; /* Pixel tolerance */
#endif
}
else {
/* Distances are computed in object space, so is the tolerance of the
* de Casteljau algorithm.
*/
rendererData.tolerance = inContext->renderState.tolerance
* sqrt(inScaleX * inScaleX + inScaleY * inScaleY) / sx64 / sy64;
rendererData.halfWidth = 0.5;
rendererData.halfHeight = 0.5;
rendererData.transformMatrix = identityMatrix;
rendererData.transformMatrix[0] /= sx64;
rendererData.transformMatrix[5] /= sy64;
}
/* Parse the outline of the glyph */
if (!__glcFontOutlineDecompose(inFont, &rendererData, inContext))
return;
if (!__glcArrayAppend(rendererData.endContour,
&GLC_ARRAY_LENGTH(rendererData.vertexArray)))
goto reset;
switch(inContext->renderState.renderStyle) {
case GLC_LINE:
objectIndex = 0;
break;
case GLC_TRIANGLE:
objectIndex = inContext->enableState.extrude ? 3 : 2;
break;
}
/* Prepare the display list if needed. For optimization reasons, if we use
* VBOs we build them for the 3 rendering modes (GLC_LINE, GLC_TRIANGLE,
* extrusion) in a row. (Vertices are common to all rendering modes and
* contours are common to GLC_LINE and extrude).
*/
if (inContext->enableState.glObjects) {
if (GLEW_ARB_vertex_buffer_object) {
int i = 0;
GLfloat (*vertexArray)[2] =
(GLfloat(*)[2])GLC_ARRAY_DATA(rendererData.vertexArray);
inGlyph->nContour = GLC_ARRAY_LENGTH(rendererData.endContour) - 1;
inGlyph->contours =
(GLint*)__glcMalloc(GLC_ARRAY_SIZE(rendererData.endContour));
if (!inGlyph->contours) {
__glcRaiseError(GLC_RESOURCE_ERROR);
goto reset;
}
memcpy(inGlyph->contours, GLC_ARRAY_DATA(rendererData.endContour),
GLC_ARRAY_SIZE(rendererData.endContour));
for (i = 0; i < GLC_ARRAY_LENGTH(rendererData.vertexArray); i++) {
vertexArray[i][0] /= sx64;
vertexArray[i][1] /= sy64;
}
glGenBuffersARB(1, &inGlyph->glObject[0]);
glGenBuffersARB(1, &inGlyph->glObject[2]);
if (!inGlyph->glObject[0] || !inGlyph->glObject[2]) {
__glcRaiseError(GLC_RESOURCE_ERROR);
inGlyph->nContour = 0;
__glcFree(inGlyph->contours);
inGlyph->contours= NULL;
if (inGlyph->glObject[0]) {
glDeleteBuffersARB(1, &inGlyph->glObject[0]);
inGlyph->glObject[0] = 0;
}
if (inGlyph->glObject[2]) {
glDeleteBuffersARB(1, &inGlyph->glObject[2]);
inGlyph->glObject[2] = 0;
}
goto reset;
}
/* Create the VBO for GLC_LINE rendering mode */
glBindBufferARB(GL_ARRAY_BUFFER_ARB, inGlyph->glObject[0]);
glBufferDataARB(GL_ARRAY_BUFFER_ARB,
GLC_ARRAY_SIZE(rendererData.vertexArray),
GLC_ARRAY_DATA(rendererData.vertexArray),
GL_STATIC_DRAW_ARB);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, inGlyph->glObject[2]);
}
else {
inGlyph->glObject[objectIndex] = glGenLists(1);
if (!inGlyph->glObject[objectIndex]) {
__glcRaiseError(GLC_RESOURCE_ERROR);
goto reset;
}
glNewList(inGlyph->glObject[objectIndex], GL_COMPILE);
glScalef(1./sx64, 1./sy64, 1.);
}
}
/* Tesselate the polygon defined by the contour returned by
* __glcFontOutlineDecompose().
*/
if (inContext->renderState.renderStyle == GLC_TRIANGLE
|| (inContext->enableState.glObjects && GLEW_ARB_vertex_buffer_object)) {
GLUtesselator *tess = gluNewTess();
GLuint j = 0;
int i = 0;
GLuint* endContour = (GLuint*)GLC_ARRAY_DATA(rendererData.endContour);
GLfloat (*vertexArray)[2] =
(GLfloat(*)[2])GLC_ARRAY_DATA(rendererData.vertexArray);
GLdouble coords[3] = {0., 0., 0.};
/* Initialize the GLU tesselator */
gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
gluTessProperty(tess, GLU_TESS_BOUNDARY_ONLY, GL_FALSE);
gluTessCallback(tess, GLU_TESS_ERROR,
(void (CALLBACK *) (GLenum))__glcCallbackError);
gluTessCallback(tess, GLU_TESS_VERTEX_DATA,
(void (CALLBACK *) (void*, void*))__glcVertexCallback);
gluTessCallback(tess, GLU_TESS_COMBINE_DATA,
(void (CALLBACK *) (GLdouble[3], void*[4],
GLfloat[4], void**, void*))
__glcCombineCallback);
gluTessCallback(tess, GLU_TESS_BEGIN_DATA,
(void (CALLBACK *) (GLenum, void*))__glcBeginCallback);
gluTessNormal(tess, 0., 0., 1.);
/* Define the polygon geometry */
gluTessBeginPolygon(tess, &rendererData);
for (i = 0; i < GLC_ARRAY_LENGTH(rendererData.endContour)-1; i++) {
/* Evil hack for 32/64 bits compatibility */
union {
void* ptr;
GLuint i;
} uintInPtr;
gluTessBeginContour(tess);
for (j = endContour[i]; j < endContour[i+1]; j++) {
coords[0] = (GLdouble)vertexArray[j][0];
coords[1] = (GLdouble)vertexArray[j][1];
uintInPtr.i = j;
gluTessVertex(tess, coords, uintInPtr.ptr);
}
gluTessEndContour(tess);
}
/* Close the polygon and run the tesselation */
gluTessEndPolygon(tess);
/* Free memory */
gluDeleteTess(tess);
if (inContext->enableState.glObjects && GLEW_ARB_vertex_buffer_object) {
inGlyph->nGeomBatch = GLC_ARRAY_LENGTH(rendererData.geomBatches);
inGlyph->geomBatches =
(__GLCgeomBatch*)__glcMalloc(GLC_ARRAY_SIZE(rendererData.geomBatches));
if (!inGlyph->geomBatches) {
__glcRaiseError(GLC_RESOURCE_ERROR);
glDeleteBuffersARB(1, &inGlyph->glObject[2]);
inGlyph->glObject[2] = 0;
goto reset;
}
memcpy(inGlyph->geomBatches, GLC_ARRAY_DATA(rendererData.geomBatches),
GLC_ARRAY_SIZE(rendererData.geomBatches));
glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
GLC_ARRAY_SIZE(rendererData.vertexIndices),
GLC_ARRAY_DATA(rendererData.vertexIndices),
GL_STATIC_DRAW_ARB);
}
}
/* Now that the tesselation is done, the actual rendering for GLC_TRIANGLE
* begins.
*/
if (inContext->renderState.renderStyle == GLC_TRIANGLE) {
int i = 0;
__GLCgeomBatch* geomBatch =
(__GLCgeomBatch*)GLC_ARRAY_DATA(rendererData.geomBatches);
GLboolean extrude = GL_FALSE;
do {
GLuint* vertexIndices = NULL;
if (inContext->enableState.glObjects && GLEW_ARB_vertex_buffer_object)
glVertexPointer(2, GL_FLOAT, 0, NULL);
else {
vertexIndices = (GLuint*)GLC_ARRAY_DATA(rendererData.vertexIndices);
glVertexPointer(2, GL_FLOAT, 0,
GLC_ARRAY_DATA(rendererData.vertexArray));
}
if (inContext->enableState.glObjects || (orientation > 0.f))
for (i = 0; i < GLC_ARRAY_LENGTH(rendererData.geomBatches); i++) {
glDrawRangeElements(geomBatch[i].mode, geomBatch[i].start,
geomBatch[i].end, geomBatch[i].length,
GL_UNSIGNED_INT, vertexIndices);
vertexIndices += geomBatch[i].length;
}
/* If the extrusion is selected, the vertex array of the GLC_TRIANGLE will
* be rendered a second time translated along the axis.
*/
if (inContext->enableState.extrude) {
if (extrude)
glTranslatef(0.f, 0.f, 1.f);
else {
glNormal3f(0.f, 0.f, -1.f);
glTranslatef(0.f, 0.f, -1.f);
orientation = -orientation;
}
extrude = (!extrude);
}
} while (extrude);
}
/* For extruded glyphes : close the contours */
if ((inContext->renderState.renderStyle == GLC_TRIANGLE
&& inContext->enableState.extrude)
|| (inContext->enableState.glObjects && GLEW_ARB_vertex_buffer_object)) {
GLfloat ax = 0.f, bx = 0.f, ay = 0.f, by = 0.f;
GLfloat nx = 0.f, ny = 0.f, n0x = 0.f, n0y = 0.f, length = 0.f;
GLuint* endContour = (GLuint*)GLC_ARRAY_DATA(rendererData.endContour);
GLfloat (*vertexArray)[2] =
(GLfloat(*)[2])GLC_ARRAY_DATA(rendererData.vertexArray);
int i = 0;
GLuint j = 0;
GLfloat* extrudeArray = NULL;
GLfloat* interleavedArray = NULL;
/* Prepare the VBO for the contour */
if (inContext->enableState.glObjects && GLEW_ARB_vertex_buffer_object) {
GLuint nVertices = 0;
glGenBuffersARB(1, &inGlyph->glObject[3]);
if (!inGlyph->glObject[3]) {
__glcRaiseError(GLC_RESOURCE_ERROR);
goto reset;
}
/* Compute the total number of vertices that will be stored in the VBO */
for (i = 0; i < GLC_ARRAY_LENGTH(rendererData.endContour)-1; i++)
nVertices += endContour[i+1] - endContour[i] + 1;
assert(nVertices);
/* The array stores (3D vertices + 3D normal) * 2 for each point of the
* contour.
*/
extrudeArray = (GLfloat*)__glcMalloc(12 * sizeof(GLfloat) * nVertices);
if (!extrudeArray) {
__glcRaiseError(GLC_RESOURCE_ERROR);
glDeleteBuffers(1, &inGlyph->glObject[3]);
inGlyph->glObject[3] = 0;
goto reset;
}
interleavedArray = extrudeArray;
}
/* Compute the vertices and the normals of the contour */
for (i = 0; i < GLC_ARRAY_LENGTH(rendererData.endContour)-1; i++) {
if (!(inContext->enableState.glObjects && GLEW_ARB_vertex_buffer_object))
glBegin(GL_TRIANGLE_STRIP);
for (j = endContour[i]; j < endContour[i+1]; j++) {
if (j == endContour[i]) {
ax = vertexArray[endContour[i+1]-1][0];
ay = vertexArray[endContour[i+1]-1][1];
bx = vertexArray[j+1][0];
by = vertexArray[j+1][1];
n0x = ay - by;
n0y = bx - ax;
}
else if (j == (endContour[i+1] - 1)) {
ax = vertexArray[j-1][0];
ay = vertexArray[j-1][1];
bx = vertexArray[endContour[i]][0];
by = vertexArray[endContour[i]][1];
}
else {
ax = vertexArray[j-1][0];
ay = vertexArray[j-1][1];
bx = vertexArray[j+1][0];
by = vertexArray[j+1][1];
}
nx = ay - by;
ny = bx - ax;
length = sqrt(nx*nx + ny*ny);
if (inContext->enableState.glObjects && GLEW_ARB_vertex_buffer_object) {
interleavedArray[0] = nx / length;
interleavedArray[1] = nx / length;
interleavedArray[2] = 0.f;
interleavedArray[3] = vertexArray[j][0];
interleavedArray[4] = vertexArray[j][1];
interleavedArray[5] = 0.f;
memcpy(interleavedArray + 6, interleavedArray, 5 * sizeof(GLfloat));
interleavedArray[11] = -1.f;
interleavedArray += 12;
}
else {
glNormal3f(nx/length, ny/length, 0.f);
glVertex2fv(vertexArray[j]);
glVertex3f(vertexArray[j][0], vertexArray[j][1], -1.f);
}
}
length = sqrt(n0x*n0x + n0y*n0y);
/* Close the contour (repeat the first vertex at the end of the array) */
if (inContext->enableState.glObjects && GLEW_ARB_vertex_buffer_object) {
interleavedArray[0] = n0x / length;
interleavedArray[1] = n0x / length;
interleavedArray[2] = 0.f;
interleavedArray[3] = vertexArray[endContour[i]][0];
interleavedArray[4] = vertexArray[endContour[i]][1];
interleavedArray[5] = 0.f;
memcpy(interleavedArray + 6, interleavedArray, 5 * sizeof(GLfloat));
interleavedArray[11] = -1.f;
interleavedArray += 12;
}
else {
glNormal3f(n0x/length, n0y/length, 0.f);
glVertex2fv(vertexArray[endContour[i]]);
glVertex3f(vertexArray[endContour[i]][0],
vertexArray[endContour[i]][1], -1.f);
}
if (!(inContext->enableState.glObjects && GLEW_ARB_vertex_buffer_object))
glEnd();
}
/* Create the VBO of the contour */
if (inContext->enableState.glObjects && GLEW_ARB_vertex_buffer_object) {
glBindBufferARB(GL_ARRAY_BUFFER_ARB, inGlyph->glObject[3]);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, (interleavedArray - extrudeArray)
* sizeof(GLfloat), extrudeArray,
GL_STATIC_DRAW_ARB);
__glcFree(extrudeArray);
/* Render the contour */
if (inContext->enableState.extrude) {
glInterleavedArrays(GL_N3F_V3F, 0, NULL);
for (i = 0; i < GLC_ARRAY_LENGTH(rendererData.endContour)-1; i++)
glDrawArrays(GL_TRIANGLE_STRIP, endContour[i] * 2,
(endContour[i+1] - endContour[i] + 1) * 2);
}
}
glNormal3f(0.f, 0.f, 1.f);
}
if (inContext->renderState.renderStyle == GLC_LINE) {
/* For GLC_LINE, there is no need to tesselate. The vertices are contained
* in an array so we use the OpenGL function glDrawArrays().
*/
int i = 0;
int* endContour = (int*)GLC_ARRAY_DATA(rendererData.endContour);
if (inContext->enableState.glObjects && GLEW_ARB_vertex_buffer_object) {
glBindBufferARB(GL_ARRAY_BUFFER_ARB, inGlyph->glObject[0]);
glVertexPointer(2, GL_FLOAT, 0, NULL);
}
else
glVertexPointer(2, GL_FLOAT, 0, GLC_ARRAY_DATA(rendererData.vertexArray));
for (i = 0; i < GLC_ARRAY_LENGTH(rendererData.endContour)-1; i++)
glDrawArrays(GL_LINE_LOOP, endContour[i], endContour[i+1]-endContour[i]);
}
if (inContext->enableState.glObjects && !GLEW_ARB_vertex_buffer_object) {
glScalef(sx64, sy64, 1.);
glEndList();
glCallList(inGlyph->glObject[objectIndex]);
}
reset:
GLC_ARRAY_LENGTH(inContext->vertexArray) = 0;
GLC_ARRAY_LENGTH(inContext->endContour) = 0;
GLC_ARRAY_LENGTH(inContext->vertexIndices) = 0;
GLC_ARRAY_LENGTH(inContext->geomBatches) = 0;
}

602
3rdparty/quesoglc/texture.c vendored Normal file
View File

@ -0,0 +1,602 @@
/* 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$ */
/** \file
* defines the routines used to render characters with textures.
*/
#include "internal.h"
#if defined __APPLE__ && defined __MACH__
#include <OpenGL/glu.h>
#else
#include <GL/glu.h>
#endif
#include "texture.h"
/* This function is called when a glyph is destroyed, the atlas element is then
* released.
*/
void __glcReleaseAtlasElement(__GLCatlasElement* This,
__GLCcontext* inContext)
{
FT_ListNode node = (FT_ListNode)This;
/* Put the atlas element at the tail of the list so that its position is used
* as soon as possible.
*/
FT_List_Remove(&inContext->atlasList, node);
FT_List_Add(&inContext->atlasList, node);
This->glyph = NULL; /* The glyph will be destroyed so clear the pointer */
}
/* This function gets some room in the texture atlas for a new glyph 'inGlyph'.
* Eventually it creates the texture atlas, if it does not exist yet.
*/
static GLboolean __glcTextureAtlasGetPosition(__GLCcontext* inContext,
__GLCglyph* inGlyph)
{
__GLCatlasElement* atlasNode = NULL;
/* Test if the atlas already exists. If not, create it. */
if (!inContext->atlas.id) {
int size = 1024; /* Initial try with a 1024x1024 texture */
int i = 0;
GLint format = 0;
GLint level = 0;
void * buffer = NULL;
/* Not all gfx card are able to use 1024x1024 textures (especially old ones
* like 3dfx's). Moreover, the texture memory may be scarce when our texture
* will be created, so we try several texture sizes : first 1024x1024 then
* if it fails, we try 512x512 then 256x256. All gfx cards support 256x256
* textures so if it fails with this texture size, that is because we ran
* out of texture memory. In such a case, there is nothing we can do, so the
* routine aborts with GLC_RESOURCE_ERROR raised.
*/
for (i = 0; i < 3; i++) {
glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_ALPHA8, size,
size, 0, GL_ALPHA, GL_UNSIGNED_BYTE, NULL);
glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_COMPONENTS,
&format);
if (format)
break;
size >>= 1;
}
/* Out of texture memory : abortion */
if (i == 3) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return GL_FALSE;
}
buffer = __glcMalloc(size * size);
if (!buffer) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return GL_FALSE;
}
memset(buffer, 0, size * size);
/* Create the texture atlas structure. The texture is divided in small
* square areas of GLC_TEXTURE_SIZE x GLC_TEXTURE_SIZE, each of which will
* contain a different glyph.
* TODO: Allow the user to change GLC_TEXTURE_SIZE rather than using a fixed
* value.
*/
glGenTextures(1, &inContext->atlas.id);
inContext->atlas.width = size;
inContext->atlas.height = size;
inContext->atlasWidth = size / GLC_TEXTURE_SIZE;
inContext->atlasHeight = size / GLC_TEXTURE_SIZE;
inContext->atlasCount = 0;
glBindTexture(GL_TEXTURE_2D, inContext->atlas.id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, size,
size, 0, GL_ALPHA, GL_UNSIGNED_BYTE, buffer);
/* Create the mipmap structure of the texture atlas, no matter if GLC_MIPMAP
* is enabled or not.
*/
while (size > 1) {
size >>= 1;
level++;
glTexImage2D(GL_TEXTURE_2D, level, GL_ALPHA8, size,
size, 0, GL_ALPHA, GL_UNSIGNED_BYTE, buffer);
}
/* Use trilinear filtering if GLC_MIPMAP is enabled.
* Otherwise use bilinear filtering.
*/
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
/* The intent of this code is to work around an ugly bug of the Intel GMA
* 965 (or X3000) drivers on Linux. On those crappy drivers a 2nd call to
* glTexSubImage2D() completely clears the texture removing by the way the
* first character stored in the texture...
* This workaround displays a dummy character in order to deceive the
* stupid drivers. Note that I tried to reduce the code to the minimum : it
* seems that if any line below is removed, the workaround no longer works
* around the f***ing bug.
*/
size = GLC_TEXTURE_SIZE;
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, size, GL_ALPHA,
GL_UNSIGNED_BYTE, buffer);
level = 0;
while (size > 2) {
size >>= 1;
level++;
glTexSubImage2D(GL_TEXTURE_2D, level, 0, 0, size, size, GL_ALPHA,
GL_UNSIGNED_BYTE, buffer);
}
if (GLEW_VERSION_1_2 || GLEW_SGIS_texture_lod)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level - 1);
glBegin(GL_QUADS);
glNormal3f(0.f, 0.f, 1.f);
glTexCoord2f(0.f, 0.f);
glVertex2f(0.f, 0.f);
glTexCoord2f(0.f, 1.f);
glVertex2f(0.f, .5f);
glTexCoord2f(1.f, 1.f);
glVertex2f(.5f, .5f);
glTexCoord2f(1.f, 0.f);
glVertex2f(.5f, 0.f);
glEnd();
/* End of the workaround for the crappy open source drivers for Intel chips
*/
__glcFree(buffer);
if (inContext->enableState.mipmap)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_LINEAR);
else
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR);
}
/* At this stage, we want to get a free area in the texture atlas in order to
* store a new glyph. Two situations may occur : the atlas is full or not
*/
if (inContext->atlasCount == inContext->atlasWidth * inContext->atlasHeight) {
/* The texture atlas is full. We must release an area to re-use it.
* We get the glyph that has not been used for the longer time (that is the
* tail element of atlasList).
*/
atlasNode = (__GLCatlasElement*)inContext->atlasList.tail;
assert(atlasNode);
if (atlasNode->glyph) {
/* Release the texture area of the glyph */
__glcGlyphDestroyTexture(atlasNode->glyph, inContext);
}
/* Put the texture area at the head of the list otherwise we will use the
* same texture element over and over again each time that we need to
* release a texture area.
*/
FT_List_Up(&inContext->atlasList, (FT_ListNode)atlasNode);
}
else {
/* The texture atlas is not full. We create a new texture area and we store
* its definition in atlas list.
*/
atlasNode = (__GLCatlasElement*)__glcMalloc(sizeof(__GLCatlasElement));
if (!atlasNode) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return GL_FALSE;
}
atlasNode->node.data = atlasNode;
atlasNode->position = inContext->atlasCount++;
FT_List_Insert(&inContext->atlasList, (FT_ListNode)atlasNode);
}
/* Update the texture element */
atlasNode->glyph = inGlyph;
inGlyph->textureObject = atlasNode;
if (GLEW_ARB_vertex_buffer_object) {
/* Create a VBO, if none exists yet */
if (!inContext->atlas.bufferObjectID) {
glGenBuffersARB(1, &inContext->atlas.bufferObjectID);
if (!inContext->atlas.bufferObjectID) {
__glcRaiseError(GLC_RESOURCE_ERROR);
/* Even though we failed to create a VBO ID, the rendering of the glyph
* can be processed without VBO, so we return GL_TRUE.
*/
return GL_TRUE;
}
}
/* Bind the buffer and define/update its size */
glBindBufferARB(GL_ARRAY_BUFFER_ARB, inContext->atlas.bufferObjectID);
}
return GL_TRUE;
}
/* For immediate rendering mode (that is when GLC_GL_OBJECTS is disabled), this
* function returns a texture that will store the glyph that is intended to be
* rendered. If the texture does not exist yet, it is created.
*/
static GLboolean __glcTextureGetImmediate(__GLCcontext* inContext,
const GLsizei inWidth,
const GLsizei inHeight)
{
GLint format = 0;
GLsizei width = inWidth;
GLsizei height = inHeight;
/* Check if a texture exists to store the glyph */
if (inContext->texture.id) {
/* Check if the texture size is large enough to store the glyph */
if ((inWidth > inContext->texture.width)
|| (inHeight > inContext->texture.height)) {
/* The texture is not large enough so we destroy the current texture */
glDeleteTextures(1, &inContext->texture.id);
width = (inWidth > inContext->texture.width) ?
inWidth : inContext->texture.width;
height = (inHeight > inContext->texture.height) ?
inHeight : inContext->texture.height;
inContext->texture.id = 0;
inContext->texture.width = 0;
inContext->texture.height = 0;
}
else {
/* The texture is large enough, it is already bound to the current
* GL context.
*/
return GL_TRUE;
}
}
if (GLEW_ARB_pixel_buffer_object)
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
/* Check if a new texture can be created */
glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_ALPHA8, width, height, 0, GL_ALPHA,
GL_UNSIGNED_BYTE, NULL);
glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_COMPONENTS,
&format);
/* TODO: If the texture creation fails, try with a smaller size */
if (!format) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return GL_FALSE;
}
/* Create a texture object and make it current */
glGenTextures(1, &inContext->texture.id);
glBindTexture(GL_TEXTURE_2D, inContext->texture.id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, width, height, 0, GL_ALPHA,
GL_UNSIGNED_BYTE, NULL);
/* For immediate mode rendering, always use bilinear filtering even if
* GLC_MIPMAP is enabled : we have determined the size of the glyph when it
* will be rendered on the screen and the texture size has been defined
* accordingly. Hence the mipmap levels would not be used, so there is no
* point in spending time to compute them.
*/
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
inContext->texture.width = width;
inContext->texture.height = height;
if (GLEW_ARB_pixel_buffer_object) {
/* Create a PBO, if none exists yet */
if (!inContext->texture.bufferObjectID) {
glGenBuffersARB(1, &inContext->texture.bufferObjectID);
if (!inContext->texture.bufferObjectID) {
__glcRaiseError(GLC_RESOURCE_ERROR);
/* Even though we failed to create a PBO ID, the rendering of the glyph
* can be processed without PBO, so we return GL_TRUE.
*/
return GL_TRUE;
}
}
/* Bind the buffer and define/update its size */
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB,
inContext->texture.bufferObjectID);
glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, width * height, NULL,
GL_STREAM_DRAW_ARB);
}
return GL_TRUE;
}
/* Internal function that renders glyph in textures :
* 'inCode' must be given in UCS-4 format
*/
void __glcRenderCharTexture(const __GLCfont* inFont, __GLCcontext* inContext,
const GLfloat inScaleX, const GLfloat inScaleY,
__GLCglyph* inGlyph)
{
GLint level = 0;
GLint texX = 0, texY = 0;
GLint pixWidth = 0, pixHeight = 0;
void* pixBuffer = NULL;
GLint pixBoundingBox[4] = {0, 0, 0, 0};
int minSize = (GLEW_VERSION_1_2 || GLEW_SGIS_texture_lod) ? 2 : 1;
GLfloat texWidth = 0.f, texHeight = 0.f;
if (inContext->enableState.glObjects) {
__GLCatlasElement* atlasNode = NULL;
if (!__glcTextureAtlasGetPosition(inContext, inGlyph))
return;
/* Compute the size of the pixmap where the glyph will be rendered */
atlasNode = inGlyph->textureObject;
__glcFontGetBitmapSize(inFont, &pixWidth, &pixHeight, inScaleX, inScaleY, 0,
pixBoundingBox, inContext);
texWidth = inContext->atlas.width;
texHeight = inContext->atlas.height;
texY = (atlasNode->position / inContext->atlasWidth);
texX = (atlasNode->position - texY*inContext->atlasWidth)*GLC_TEXTURE_SIZE;
texY *= GLC_TEXTURE_SIZE;
}
else {
int factor = 0;
/* Try several texture size until we are able to create one */
do {
if (!__glcFontGetBitmapSize(inFont, &pixWidth, &pixHeight, inScaleX,
inScaleY, factor, pixBoundingBox, inContext))
return;
factor = 1;
} while (!__glcTextureGetImmediate(inContext, pixWidth, pixHeight));
texWidth = inContext->texture.width;
texHeight = inContext->texture.height;
texX = 0;
texY = 0;
}
if (!inContext->texture.bufferObjectID || inContext->enableState.glObjects) {
pixBuffer = (GLubyte *)__glcMalloc(pixWidth * pixHeight);
if (!pixBuffer) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return;
}
}
/* Create the texture */
glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
/* Iterate on the powers of 2 in order to build the mipmap */
do {
if (GLEW_ARB_pixel_buffer_object && !inContext->enableState.glObjects) {
pixBuffer = (GLubyte *)glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB,
GL_WRITE_ONLY_ARB);
if (!pixBuffer) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return;
}
}
/* render the glyph */
if (!__glcFaceDescGetBitmap(inFont->faceDesc, pixWidth, pixHeight,
pixBuffer, inContext)) {
glPopClientAttrib();
if (GLEW_ARB_pixel_buffer_object && !inContext->enableState.glObjects)
glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
else
__glcFree(pixBuffer);
return;
}
if (GLEW_ARB_pixel_buffer_object && !inContext->enableState.glObjects) {
glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
pixBuffer = NULL;
}
glTexSubImage2D(GL_TEXTURE_2D, level, texX >> level, texY >> level,
pixWidth, pixHeight, GL_ALPHA, GL_UNSIGNED_BYTE,
pixBuffer);
/* A mipmap is built only if a display list is currently building
* otherwise it adds useless computations
*/
if (!(inContext->enableState.mipmap && inContext->enableState.glObjects))
break;
level++; /* Next level of mipmap */
pixWidth >>= 1;
pixHeight >>= 1;
} while ((pixWidth > minSize) && (pixHeight > minSize));
/* Finish to build the mipmap if necessary */
if (inContext->enableState.mipmap && inContext->enableState.glObjects) {
if (GLEW_VERSION_1_2 || GLEW_SGIS_texture_lod)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level - 1);
else {
/* The OpenGL driver does not support the extension GL_EXT_texture_lod
* We must finish the pixmap until the mipmap level is 1x1.
* Here the smaller mipmap levels will be transparent, no glyph will be
* rendered.
* TODO: Use gluScaleImage() to render the last levels.
* Here we do not take the GL_ARB_pixel_buffer_object into account
* because there are few chances that a gfx card that supports PBO, does
* not support texture levels.
*/
assert(!GLEW_ARB_pixel_buffer_object);
memset(pixBuffer, 0, pixWidth * pixHeight);
while ((pixWidth > 0) || (pixHeight > 0)) {
glTexSubImage2D(GL_TEXTURE_2D, level, texX >> level, texY >> level,
pixWidth ? pixWidth : 1,
pixHeight ? pixHeight : 1, GL_ALPHA,
GL_UNSIGNED_BYTE, pixBuffer);
level++;
pixWidth >>= 1;
pixHeight >>= 1;
}
}
}
glPopClientAttrib();
if (pixBuffer)
__glcFree(pixBuffer);
/* Add the new texture to the texture list and the new display list
* to the list of display lists
*/
if (inContext->enableState.glObjects) {
if (GLEW_ARB_vertex_buffer_object) {
GLfloat* buffer = NULL;
GLfloat* data = NULL;
__GLCatlasElement* atlasNode = inGlyph->textureObject;
buffer = (GLfloat*)__glcMalloc(inContext->atlasWidth
* inContext->atlasHeight * 20
* sizeof(GLfloat));
if (!buffer) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return;
}
/* The display list ID is used as a flag to declare that the VBO has been
* initialized and can be used.
*/
inGlyph->glObject[1] = 0xffffffff;
/* Here we do not use the GL command glBufferSubData() since it seems to
* be buggy on some GL drivers (the DRI Intel specifically).
* Instead, we use a workaround: the current values of the VBO are stored
* in memory and new values are appended to them. Then, the content of
* the resulting array replaces all the values previously stored in the
* VBO.
*/
if (inContext->atlasCount > 1) {
data = (GLfloat*)glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY);
if (!data) {
__glcRaiseError(GLC_RESOURCE_ERROR);
__glcFree(buffer);
return;
}
memcpy(buffer, data, inContext->atlasCount * 20 * sizeof(GLfloat));
glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
}
data = buffer + atlasNode->position * 20;
data[0] = texX / texWidth;
data[1] = texY / texHeight;
data[2] = pixBoundingBox[0] / 64. / GLC_TEXTURE_SIZE;
data[3] = pixBoundingBox[1] / 64. / GLC_TEXTURE_SIZE;
data[4] = 0.f;
data[5] = (texX + GLC_TEXTURE_SIZE - 1) / texWidth;
data[6] = data[1];
data[7] = pixBoundingBox[2] / 64. / GLC_TEXTURE_SIZE;
data[8] = data[3];
data[9] = 0.f;
data[10] = data[5];
data[11] = (texY + GLC_TEXTURE_SIZE - 1) / texHeight;
data[12] = data[7];
data[13] = pixBoundingBox[3] / 64. / GLC_TEXTURE_SIZE;
data[14] = 0.f;
data[15] = data[0];
data[16] = data[11];
data[17] = data[2];
data[18] = data[13];
data[19] = 0.f;
/* Size of the buffer data is equal to the number of glyphes than can be
* stored in the texture times 20 GLfloat (4 vertices made of 3D
* coordinates plus 2D texture coordinates : 4 * (3 + 2) = 20)
*/
glBufferDataARB(GL_ARRAY_BUFFER_ARB,
inContext->atlasWidth * inContext->atlasHeight
* 20 * sizeof(GLfloat), buffer, GL_STATIC_DRAW_ARB);
__glcFree(buffer);
/* Do the actual GL rendering */
glInterleavedArrays(GL_T2F_V3F, 0, NULL);
glDrawArrays(GL_QUADS, atlasNode->position * 4, 4);
return;
}
else {
inGlyph->glObject[1] = glGenLists(1);
if (!inGlyph->glObject[1]) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return;
}
/* Create the display list */
glNewList(inGlyph->glObject[1], GL_COMPILE);
glScalef(1. / (64. * inScaleX), 1. / (64. * inScaleY) , 1.);
/* Modify the bouding box dimensions to compensate the glScalef() */
pixBoundingBox[0] *= inScaleX / GLC_TEXTURE_SIZE;
pixBoundingBox[1] *= inScaleY / GLC_TEXTURE_SIZE;
pixBoundingBox[2] *= inScaleX / GLC_TEXTURE_SIZE;
pixBoundingBox[3] *= inScaleY / GLC_TEXTURE_SIZE;
pixWidth = GLC_TEXTURE_SIZE;
pixHeight = GLC_TEXTURE_SIZE;
}
}
/* Do the actual GL rendering */
glBegin(GL_QUADS);
glTexCoord2f(texX / texWidth, texY / texHeight);
glVertex2iv(pixBoundingBox);
glTexCoord2f((texX + pixWidth - 1) / texWidth, texY / texHeight);
glVertex2i(pixBoundingBox[2], pixBoundingBox[1]);
glTexCoord2f((texX + pixWidth - 1) / texWidth,
(texY + pixHeight - 1) / texHeight);
glVertex2iv(pixBoundingBox + 2);
glTexCoord2f(texX / texWidth, (texY + pixHeight - 1) / texHeight);
glVertex2i(pixBoundingBox[0], pixBoundingBox[3]);
glEnd();
if (inContext->enableState.glObjects) {
/* Finish display list creation */
glScalef(64. * inScaleX, 64. * inScaleY, 1.);
glEndList();
glCallList(inGlyph->glObject[1]);
}
}

43
3rdparty/quesoglc/texture.h vendored Normal file
View File

@ -0,0 +1,43 @@
/* QuesoGLC
* A free implementation of the OpenGL Character Renderer (GLC)
* Copyright (c) 2002, 2004-2008, 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$ */
/** \file
* header of the routines used to render characters with textures.
*/
#ifndef __glc_texture_h
#define __glc_texture_h
#include "ofont.h"
#define GLC_TEXTURE_SIZE 64
struct __GLCatlasElementRec {
FT_ListNodeRec node;
int position;
__GLCglyph* glyph;
};
void __glcReleaseAtlasElement(__GLCatlasElement* This, __GLCcontext* inContext);
void __glcRenderCharTexture(const __GLCfont* inFont, __GLCcontext* inContext,
const GLfloat inScaleX, const GLfloat inScaleY,
__GLCglyph* inGlyph);
#endif

292
3rdparty/quesoglc/transform.c vendored Normal file
View File

@ -0,0 +1,292 @@
/* QuesoGLC
* A free implementation of the OpenGL Character Renderer (GLC)
* Copyright (c) 2002, 2004-2007, 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$ */
/** \file
* defines the so-called "Transformation commands" described in chapter 3.9
* of the GLC specs.
*/
/** \defgroup transform Transformation commands
* The GLC transformation commands modify the value of \b GLC_BITMAP_MATRIX.
* Glyph coordinates are defined in the em coordinate system. When the value
* of \b GLC_RENDER_STYLE is \b GLC_BITMAP, GLC uses the 2x2
* \b GLC_BITMAP_MATRIX to transform layouts from the em coordinate system to
* the GL raster coordinate system in which bitmaps are drawn.
*
* When the value of the variable \b GLC_RENDER_STYLE is not \b GLC_BITMAP,
* GLC performs no transformations on glyph coordinates. In this case, GLC
* uses em coordinates directly as GL world coordinates when drawing a layout,
* and it is the responsibility of the GLC client to issue GL commands that
* set up the appropriate GL transformations.
*
* There is a stack of matrices for \b GLC_BITMAP_MATRIX, the stack depth is
* at least 32 (that is, there is a stack of at least 32 matrices). Matrices
* can be pushed or popped in the stack with glcPushMatrixQSO() and
* glcPopMatrixQSO(). The maximum depth is implementation specific but can be
* retrieved by calling glcGeti() with \b GLC_MAX_MATRIX_STACK_DEPTH_QSO. The
* number of matrices that are currently stored in the stack can be retrieved
* by calling glcGeti() with \b GLC_MATRIX_STACK_DEPTH_QSO.
*/
#include <math.h>
#include "internal.h"
#define GLC_PI 3.1415926535
/** \ingroup transform
* This command assigns the value [1 0 0 1] to the floating point vector
* variable \b GLC_BITMAP_MATRIX.
* \sa glcGetfv() with argument \b GLC_BITMAP_MATRIX
* \sa glcLoadMatrix()
* \sa glcMultMatrix()
* \sa glcRotate()
* \sa glcScale()
*/
void APIENTRY glcLoadIdentity(void)
{
__GLCcontext *ctx = NULL;
GLC_INIT_THREAD();
/* Check if the current thread owns a context state */
ctx = GLC_GET_CURRENT_CONTEXT();
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return;
}
ctx->bitmapMatrix[0] = 1.;
ctx->bitmapMatrix[1] = 0.;
ctx->bitmapMatrix[2] = 0.;
ctx->bitmapMatrix[3] = 1.;
}
/** \ingroup transform
* This command assigns the value [inMatrix[0] inMatrix[1] inMatrix[2]
* inMatrix[3]] to the floating point vector variable \b GLC_BITMAP_MATRIX.
*
* \param inMatrix The value to assign to \b GLC_BITMAP_MATRIX
* \sa glcGetfv() with argument \b GLC_BITMAP_MATRIX
* \sa glcLoadIdentity()
* \sa glcMultMatrix()
* \sa glcRotate()
* \sa glcScale()
*/
void APIENTRY glcLoadMatrix(const GLfloat *inMatrix)
{
__GLCcontext *ctx = NULL;
GLC_INIT_THREAD();
assert(inMatrix);
/* Check if the current thread owns a context state */
ctx = GLC_GET_CURRENT_CONTEXT();
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return;
}
memcpy(ctx->bitmapMatrix, inMatrix, 4 * sizeof(GLfloat));
}
/** \ingroup transform
* This command multiply the floating point vector variable
* \b GLC_BITMAP_MATRIX by the incoming matrix \e inMatrix.
*
* \param inMatrix A pointer to a 2x2 matrix stored in column-major order
* as 4 consecutives values.
* \sa glcGetfv() with argument \b GLC_BITMAP_MATRIX
* \sa glcLoadIdentity()
* \sa glcLoadMatrix()
* \sa glcRotate()
* \sa glcScale()
*/
void APIENTRY glcMultMatrix(const GLfloat *inMatrix)
{
__GLCcontext *ctx = NULL;
GLfloat tempMatrix[4];
GLC_INIT_THREAD();
assert(inMatrix);
/* Check if the current thread owns a context state */
ctx = GLC_GET_CURRENT_CONTEXT();
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return;
}
memcpy(tempMatrix, ctx->bitmapMatrix, 4 * sizeof(GLfloat));
ctx->bitmapMatrix[0] = tempMatrix[0] * inMatrix[0]
+ tempMatrix[2] * inMatrix[1];
ctx->bitmapMatrix[1] = tempMatrix[1] * inMatrix[0]
+ tempMatrix[3] * inMatrix[1];
ctx->bitmapMatrix[2] = tempMatrix[0] * inMatrix[2]
+ tempMatrix[2] * inMatrix[3];
ctx->bitmapMatrix[3] = tempMatrix[1] * inMatrix[2]
+ tempMatrix[3] * inMatrix[3];
}
/** \ingroup transform
* This command assigns the value [a b c d] to the floating point vector
* variable \b GLC_BITMAP_MATRIX, where \e inAngle is measured in degrees,
* \f$ \theta = inAngle * \pi / 180 \f$ and \n
* \f$ \left [ \begin {array}{ll} a & b \\ c & d \\ \end {array} \right ]
* = \left [ \begin {array}{ll} GLC\_BITMAP\_MATRIX[0] & GLC\_BITMAP\_MATRIX[2]
* \\ GLC\_BITMAP\_MATRIX[1] & GLC\_BITMAP\_MATRIX[3] \\ \end{array}
* \right ]
* \left [ \begin {array}{ll} cos \theta & sin \theta \\
* -sin \theta & cos\theta \\ \end{array} \right ]
* \f$
* \param inAngle The angle of rotation around the Z axis, in degrees.
* \sa glcGetfv() with argument \b GLC_BITMAP_MATRIX
* \sa glcLoadIdentity()
* \sa glcLoadMatrix()
* \sa glcMultMatrix()
* \sa glcScale()
*/
void APIENTRY glcRotate(GLfloat inAngle)
{
GLfloat tempMatrix[4];
GLfloat radian = inAngle * GLC_PI / 180.;
GLfloat sine = sin(radian);
GLfloat cosine = cos(radian);
tempMatrix[0] = cosine;
tempMatrix[1] = sine;
tempMatrix[2] = -sine;
tempMatrix[3] = cosine;
glcMultMatrix(tempMatrix);
}
/** \ingroup transform
* This command produces a general scaling along the \b x and \b y
* axes, that is, it assigns the value [a b c d] to the floating point
* vector variable \b GLC_BITMAP_MATRIX, where \n
* \f$ \left [ \begin {array}{ll} a & b \\ c & d \\ \end {array} \right ]
* = \left [ \begin {array}{ll} GLC\_BITMAP\_MATRIX[0] & GLC\_BITMAP\_MATRIX[2]
* \\ GLC\_BITMAP\_MATRIX[1] & GLC\_BITMAP\_MATRIX[3] \\ \end{array}
* \right ]
* \left [ \begin {array}{ll} inX & 0 \\
* 0 & inY \\ \end{array} \right ]
* \f$
* \param inX The scale factor along the \b x axis
* \param inY The scale factor along the \b y axis
* \sa glcGetfv() with argument \b GLC_BITMAP_MATRIX
* \sa glcLoadIdentity()
* \sa glcLoadMatrix()
* \sa glcMultMatrix()
* \sa glcRotate()
*/
void APIENTRY glcScale(GLfloat inX, GLfloat inY)
{
GLfloat tempMatrix[4];
tempMatrix[0] = inX;
tempMatrix[1] = 0.;
tempMatrix[2] = 0.;
tempMatrix[3] = inY;
glcMultMatrix(tempMatrix);
}
/** \ingroup transform
* This command pushes the stack down by one, duplicating the current
* \b GLC_BITMAP_MATRIX in both the top of the stack and the entry below it.
* Pushing a matrix onto a full stack generates the error
* \b GLC_STACK_OVERFLOW_QSO.
* \sa glcPopMatrixQSO()
* \sa glcGeti() with argument \b GLC_MATRIX_STACK_DEPTH_QSO
* \sa glcGeti() with argument \b GLC_MAX_MATRIX_STACK_DEPTH_QSO
*/
void APIENTRY glcPushMatrixQSO(void)
{
__GLCcontext *ctx = NULL;
GLC_INIT_THREAD();
/* Check if the current thread owns a context state */
ctx = GLC_GET_CURRENT_CONTEXT();
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return;
}
if (ctx->bitmapMatrixStackDepth >= GLC_MAX_MATRIX_STACK_DEPTH) {
__glcRaiseError(GLC_STACK_OVERFLOW_QSO);
return;
}
memcpy(ctx->bitmapMatrix+4, ctx->bitmapMatrix, 4*sizeof(GLfloat));
ctx->bitmapMatrix += 4;
ctx->bitmapMatrixStackDepth++;
return;
}
/** \ingroup transform
* This command pops the top entry off the stack, replacing the current
* \b GLC_BITMAP_MATRIX with the matrix that was the second entry in the
* stack.
* Popping a matrix off a stack with only one entry generates the error
* \b GLC_STACK_OVERFLOW_QSO.
* \sa glcPushMatrixQSO()
* \sa glcGeti() with argument \b GLC_MATRIX_STACK_DEPTH_QSO
* \sa glcGeti() with argument \b GLC_MAX_MATRIX_STACK_DEPTH_QSO
*/
void APIENTRY glcPopMatrixQSO(void)
{
__GLCcontext *ctx = NULL;
GLC_INIT_THREAD();
/* Check if the current thread owns a context state */
ctx = GLC_GET_CURRENT_CONTEXT();
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return;
}
if (ctx->bitmapMatrixStackDepth <= 1) {
__glcRaiseError(GLC_STACK_UNDERFLOW_QSO);
return;
}
ctx->bitmapMatrix -= 4;
ctx->bitmapMatrixStackDepth--;
return;
}

782
3rdparty/quesoglc/unicode.c vendored Normal file
View File

@ -0,0 +1,782 @@
/* 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$ */
/* This file defines miscellaneous utility routines used for Unicode management
*/
/** \file
* defines the routines used to manipulate Unicode strings and characters
*/
#include <fribidi/fribidi.h>
#include "internal.h"
/* Find a Unicode name from its code */
const GLCchar8* __glcNameFromCode(const GLint code)
{
GLint position = -1;
if ((code < 0) || (code > __glcMaxCode)) {
static char buffer[20];
if (code > 0x10ffff) {
__glcRaiseError(GLC_PARAMETER_ERROR);
return NULL;
}
snprintf(buffer, 20, "Character 0x%x", code);
return (const GLCchar8*)buffer;
}
position = __glcNameFromCodeArray[code];
if (position == -1) {
__glcRaiseError(GLC_PARAMETER_ERROR);
return NULL;
}
return (const GLCchar8*)__glcCodeFromNameArray[position].name;
}
/* Find a Unicode code from its name */
GLint __glcCodeFromName(const GLCchar8* name)
{
int start = 0;
int end = __glcCodeFromNameSize;
int middle = (end + start) / 2;
int res = 0;
while (end - start > 1) {
res = strcmp((const char*)name, __glcCodeFromNameArray[middle].name);
if (res > 0)
start = middle;
else if (res < 0)
end = middle;
else
return __glcCodeFromNameArray[middle].code;
middle = (end + start) / 2;
}
if (strcmp((const char*)name, __glcCodeFromNameArray[start].name) == 0)
return __glcCodeFromNameArray[start].code;
if (strcmp((const char*)name, __glcCodeFromNameArray[end].name) == 0)
return __glcCodeFromNameArray[end].code;
__glcRaiseError(GLC_PARAMETER_ERROR);
return -1;
}
/* Convert a character from UCS1 to UTF-8 and return the number of bytes
* needed to encode the char.
*/
static int __glcUcs1ToUtf8(const GLCchar8 ucs1, GLCchar8 dest[FC_UTF8_MAX_LEN])
{
GLCchar8 *d = dest;
if (ucs1 < 0x80)
*d++ = ucs1;
else {
*d++ = ((ucs1 >> 6) & 0x1F) | 0xC0;
*d++ = (ucs1 & 0x3F) | 0x80;
}
return d - dest;
}
/* Convert a character from UCS2 to UTF-8 and return the number of bytes
* needed to encode the char.
*/
static int __glcUcs2ToUtf8(const GLCchar16 ucs2, GLCchar8 dest[FC_UTF8_MAX_LEN])
{
GLCchar8 *d = dest;
if (ucs2 < 0x80)
*d++ = ucs2;
else if (ucs2 < 0x800) {
*d++ = ((ucs2 >> 6) & 0x1F) | 0xC0;
*d++ = (ucs2 & 0x3F) | 0x80;
}
else {
*d++ = ((ucs2 >> 12) & 0x0F) | 0xE0;
*d++ = ((ucs2 >> 6) & 0x3F) | 0x80;
*d++ = (ucs2 & 0x3F) | 0x80;
}
return d - dest;
}
/* Convert a character from UTF-8 to UCS1 and return the number of bytes
* needed to encode the character.
* According to the GLC specs, when the value of a character code exceed the
* range of the character encoding, the returned character is converted
* to a character sequence \<hexcode> where 'hexcode' is the original
* character code represented as a sequence of hexadecimal digits
*/
static int __glcUtf8ToUcs1(const GLCchar8* src_orig,
GLCchar8 dst[GLC_OUT_OF_RANGE_LEN], int len,
int* dstlen)
{
GLCchar32 result = 0;
int src_shift = FcUtf8ToUcs4(src_orig, &result, len);
if (src_shift > 0) {
/* src_orig is a well-formed UTF-8 character */
if (result < 0x100) {
*dst = result;
*dstlen = 1;
}
else {
/* Convert to the string '\<xxx>' */
#ifdef _MSC_VER
*dstlen = sprintf_s((char*)dst, GLC_OUT_OF_RANGE_LEN, "\\<%X>", result);
/* sprintf_s returns -1 on any error, and the number of characters
* written to the string not including the terminating null otherwise.
* Insufficient length of the destination buffer is an error and the
* buffer is set to an empty string. */
if (*dstlen < 0)
*dstlen = 0;
#else
*dstlen = snprintf((char*)dst, GLC_OUT_OF_RANGE_LEN, "\\<%X>", result);
/* Standard ISO/IEC 9899:1999 (ISO C99) snprintf, which it appears
* Microsoft has not implemented for their operating systems. Return
* value is length of the string that would have been written into
* the destination buffer not including the terminating null had their
* been enough space. Truncation has occurred if return value is >=
* destination buffer size. */
if (*dstlen >= GLC_OUT_OF_RANGE_LEN)
*dstlen = GLC_OUT_OF_RANGE_LEN - 1;
#endif
}
}
return src_shift;
}
/* Convert a character from UTF-8 to UCS1 and return the number of bytes
* needed to encode the character.
* According to the GLC specs, when the value of a character code exceed the
* range of the character encoding, the returned character is converted
* to a character sequence \<hexcode> where 'hexcode' is the original
* character code represented as a sequence of hexadecimal digits
*/
static int __glcUtf8ToUcs2(const GLCchar8* src_orig,
GLCchar16 dst[GLC_OUT_OF_RANGE_LEN], int len,
int* dstlen)
{
GLCchar32 result = 0;
int src_shift = FcUtf8ToUcs4(src_orig, &result, len);
if (src_shift > 0) {
/* src_orig is a well-formed UTF-8 character */
if (result < 0x10000) {
*dst = result;
*dstlen = 1;
}
else {
/* Convert to the string '\<xxx>' */
int count;
char* src = NULL;
char buffer[GLC_OUT_OF_RANGE_LEN];
#ifdef _MSC_VER
*dstlen = sprintf_s((char*)buffer, GLC_OUT_OF_RANGE_LEN, "\\<%X>",
result);
/* sprintf_s returns -1 on any error, and the number of characters
* written to the string not including the terminating null otherwise.
* Insufficient length of the destination buffer is an error and the
* buffer is set to an empty string. */
if (*dstlen < 0)
*dstlen = 0;
#else
*dstlen = snprintf((char*)buffer, GLC_OUT_OF_RANGE_LEN, "\\<%X>", result);
/* Standard ISO/IEC 9899:1999 (ISO C99) snprintf, which it appears
* Microsoft has not implemented for their operating systems. Return
* value is length of the string that would have been written into
* the destination buffer not including the terminating null had their
* been enough space. Truncation has occurred if return value is >=
* destination buffer size. */
if (*dstlen >= GLC_OUT_OF_RANGE_LEN)
*dstlen = GLC_OUT_OF_RANGE_LEN - 1;
#endif
for (count = 0, src = buffer; count < *dstlen; count++, *dst++ = *src++);
*dst = 0; /* Terminating '\0' character */
}
}
return src_shift;
}
/* Convert 'inString' in the UTF-8 format and return a copy of the converted
* string.
*/
GLCchar8* __glcConvertToUtf8(const GLCchar* inString, const GLint inStringType)
{
GLCchar8 buffer[FC_UTF8_MAX_LEN > 8 ? FC_UTF8_MAX_LEN : 8];
GLCchar8* string = NULL;
GLCchar8* ptr = NULL;
int len;
switch(inStringType) {
case GLC_UCS1:
{
const GLCchar8* ucs1 = NULL;
/* Determine the length of the final string */
for (len = 0, ucs1 = (const GLCchar8*)inString; *ucs1;
len += __glcUcs1ToUtf8(*ucs1++, buffer));
/* Allocate the room to store the final string */
string = (GLCchar8*)__glcMalloc((len+1)*sizeof(GLCchar8));
if (!string) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
/* Perform the conversion */
for (ucs1 = (const GLCchar8*)inString, ptr = string; *ucs1;
ptr += __glcUcs1ToUtf8(*ucs1++, ptr));
*ptr = 0;
}
break;
case GLC_UCS2:
{
const GLCchar16* ucs2 = NULL;
/* Determine the length of the final string */
for (len = 0, ucs2 = (const GLCchar16*)inString; *ucs2;
len += __glcUcs2ToUtf8(*ucs2++, buffer));
/* Allocate the room to store the final string */
string = (GLCchar8*)__glcMalloc((len+1)*sizeof(GLCchar8));
if (!string) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
/* Perform the conversion */
for (ucs2 = (const GLCchar16*)inString, ptr = string; *ucs2;
ptr += __glcUcs2ToUtf8(*ucs2++, ptr));
*ptr = 0;
}
break;
case GLC_UCS4:
{
const GLCchar32* ucs4 = NULL;
/* Determine the length of the final string */
for (len = 0, ucs4 = (const GLCchar32*)inString; *ucs4;
len += FcUcs4ToUtf8(*ucs4++, buffer));
/* Allocate the room to store the final string */
string = (GLCchar8*)__glcMalloc((len+1)*sizeof(GLCchar8));
if (!string) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
/* Perform the conversion */
for (ucs4 = (const GLCchar32*)inString, ptr = string; *ucs4;
ptr += FcUcs4ToUtf8(*ucs4++, ptr));
*ptr = 0;
}
break;
case GLC_UTF8_QSO:
/* If the string is already encoded in UTF-8 format then all we need to do
* is to make a copy of it.
*/
#ifdef __WIN32__
string = (GLCchar8*)_strdup((const char*)inString);
#else
string = (GLCchar8*)strdup((const char*)inString);
#endif
break;
default:
return NULL;
}
return string;
}
/* Convert 'inString' from the UTF-8 format and return a copy of the
* converted string in the context buffer.
*/
GLCchar* __glcConvertFromUtf8ToBuffer(__GLCcontext* This,
const GLCchar8* inString)
{
GLCchar* string = NULL;
const GLCchar8* utf8 = NULL;
int len_buffer = 0;
int len = 0;
int shift = 0;
assert(inString);
switch(This->stringState.stringType) {
case GLC_UCS1:
{
GLCchar8 buffer[GLC_OUT_OF_RANGE_LEN];
GLCchar8* ucs1 = NULL;
/* Determine the length of the final string */
utf8 = inString;
while(*utf8) {
shift = __glcUtf8ToUcs1(utf8, buffer, strlen((const char*)utf8),
&len_buffer);
if (shift < 0) {
/* There is an ill-formed character in the UTF-8 string, abort */
return NULL;
}
utf8 += shift;
len += len_buffer;
}
/* Allocate the room to store the final string */
string = (GLCchar*)__glcContextQueryBuffer(This,
(len+1)*sizeof(GLCchar8));
if (!string)
return NULL; /* GLC_RESOURCE_ERROR has been raised */
/* Perform the conversion */
ucs1 = (GLCchar8*)string;
utf8 = inString;
while(*utf8) {
utf8 += __glcUtf8ToUcs1(utf8, ucs1, strlen((const char*)utf8),
&len_buffer);
ucs1 += len_buffer;
}
*ucs1 = 0; /* Add the '\0' termination of the string */
}
break;
case GLC_UCS2:
{
GLCchar16 buffer[GLC_OUT_OF_RANGE_LEN];
GLCchar16* ucs2 = NULL;
/* Determine the length of the final string */
utf8 = inString;
while(*utf8) {
shift = __glcUtf8ToUcs2(utf8, buffer, strlen((const char*)utf8),
&len_buffer);
if (shift < 0) {
/* There is an ill-formed character in the UTF-8 string, abort */
return NULL;
}
utf8 += shift;
len += len_buffer;
}
/* Allocate the room to store the final string */
string = (GLCchar*)__glcContextQueryBuffer(This,
(len+1)*sizeof(GLCchar16));
if (!string)
return NULL; /* GLC_RESOURCE_ERROR has been raised */
/* Perform the conversion */
ucs2 = (GLCchar16*)string;
utf8 = inString;
while(*utf8) {
utf8 += __glcUtf8ToUcs2(utf8, ucs2, strlen((const char*)utf8),
&len_buffer);
ucs2 += len_buffer;
}
*ucs2 = 0; /* Add the '\0' termination of the string */
}
break;
case GLC_UCS4:
{
GLCchar32 buffer = 0;
GLCchar32* ucs4 = NULL;
/* Determine the length of the final string */
utf8 = inString;
while(*utf8) {
shift = FcUtf8ToUcs4(utf8, &buffer, strlen((const char*)utf8));
if (shift < 0) {
/* There is an ill-formed character in the UTF-8 string, abort */
__glcRaiseError(GLC_PARAMETER_ERROR);
return NULL;
}
utf8 += shift;
len++;
}
/* Allocate the room to store the final string */
string = (GLCchar*)__glcContextQueryBuffer(This,
(len+1)*sizeof(GLCchar32));
if (!string)
return NULL; /* GLC_RESOURCE_ERROR has been raised */
/* Perform the conversion */
utf8 = inString;
ucs4 = (GLCchar32*)string;
while(*utf8)
utf8 += FcUtf8ToUcs4(utf8, ucs4++, strlen((const char*)utf8));
*ucs4 = 0; /* Add the '\0' termination of the string */
}
break;
case GLC_UTF8_QSO:
/* If the string is already encoded in UTF-8 format then all we need to do
* is to make a copy of it.
*/
string = (GLCchar*)__glcContextQueryBuffer(This,
strlen((const char*)inString)+1);
if (!string)
return NULL; /* GLC_RESOURCE_ERROR has been raised */
strcpy((char*)string, (const char*)inString);
break;
default:
return NULL;
}
return string;
}
/* Convert a UCS-4 character code into the current string type. The result is
* stored in a GLint. If the code can not be converted to the current string
* type a GLC_PARAMETER_ERROR is issued.
*/
GLint __glcConvertUcs4ToGLint(__GLCcontext *inContext, GLint inCode)
{
switch(inContext->stringState.stringType) {
case GLC_UCS2:
/* Check that inCode can be stored in UCS-2 format */
if (inCode <= 65535)
break;
case GLC_UCS1:
/* Check that inCode can be stored in UCS-1 format */
if (inCode <= 255)
break;
case GLC_UTF8_QSO:
/* A Unicode codepoint can be no higher than 0x10ffff
* (see Unicode specs)
*/
if (inCode > 0x10ffff) {
__glcRaiseError(GLC_PARAMETER_ERROR);
return -1;
}
else {
/* Codepoints lower or equal to 0x10ffff can be encoded on 4 bytes in
* UTF-8 format
*/
GLCchar8 buffer[FC_UTF8_MAX_LEN > 8 ? FC_UTF8_MAX_LEN : 8];
#ifndef NDEBUG
int len = FcUcs4ToUtf8((GLCchar32)inCode, buffer);
assert((size_t)len <= sizeof(GLint));
#else
FcUcs4ToUtf8((GLCchar32)inCode, buffer);
#endif
return *((GLint*)buffer);
}
}
return inCode;
}
/* Convert a character encoded in the current string type to the UCS-4 format.
* This function is needed since the GLC specs store individual character codes
* in GLint which may cause problems for the UTF-8 format.
*/
GLint __glcConvertGLintToUcs4(const __GLCcontext *inContext, GLint inCode)
{
GLint code = inCode;
if (inCode < 0) {
__glcRaiseError(GLC_PARAMETER_ERROR);
return -1;
}
switch (inContext->stringState.stringType) {
case GLC_UCS1:
if (inCode > 0xff) {
__glcRaiseError(GLC_PARAMETER_ERROR);
return -1;
}
break;
case GLC_UCS2:
if (inCode > 0xffff) {
__glcRaiseError(GLC_PARAMETER_ERROR);
return -1;
}
break;
case GLC_UTF8_QSO:
/* Convert the codepoint in UCS4 format and check if it is ill-formed or
* not
*/
if (FcUtf8ToUcs4((GLCchar8*)&inCode, (GLCchar32*)&code,
sizeof(GLint)) < 0) {
__glcRaiseError(GLC_PARAMETER_ERROR);
return -1;
}
break;
}
return code;
}
/* Convert 'inString' (stored in logical order) to UCS4 format and return a
* copy of the converted string in visual order.
*/
GLCchar32* __glcConvertToVisualUcs4(__GLCcontext* inContext,
GLboolean *outIsRTL, GLint *outLength,
const GLCchar* inString)
{
GLCchar32* string = NULL;
int length = 0;
FriBidiCharType base = FRIBIDI_TYPE_ON;
GLCchar32* visualString = NULL;
assert(inString);
switch(inContext->stringState.stringType) {
case GLC_UCS1:
{
const GLCchar8* ucs1 = (const GLCchar8*)inString;
GLCchar32* ucs4 = NULL;
length = strlen((const char*)ucs1);
/* Allocate the room to store the final string */
string = (GLCchar32*)__glcContextQueryBuffer(inContext,
2*(length+1)*sizeof(GLCchar32));
if (!string)
return NULL; /* GLC_RESOURCE_ERROR has been raised */
for (ucs4 = string; *ucs1; ucs1++, ucs4++)
*ucs4 = (GLCchar32)(*ucs1);
*ucs4 = 0; /* Add the '\0' termination of the string */
}
break;
case GLC_UCS2:
{
const GLCchar16* ucs2 = NULL;
GLCchar32* ucs4 = NULL;
for (ucs2 = (const GLCchar16*)inString; *ucs2; ucs2++, length++);
/* Allocate the room to store the final string */
string = (GLCchar32*)__glcContextQueryBuffer(inContext,
2*(length+1)*sizeof(GLCchar32));
if (!string)
return NULL; /* GLC_RESOURCE_ERROR has been raised */
for (ucs2 = (const GLCchar16*)inString, ucs4 = string; *ucs2;
ucs2++, ucs4++)
*ucs4 = (GLCchar32)(*ucs2);
*ucs4 = 0; /* Add the '\0' termination of the string */
}
break;
case GLC_UCS4:
{
const GLCchar32* ucs4 = NULL;
for (ucs4 = (const GLCchar32*)inString; *ucs4; ucs4++, length++);
/* Allocate the room to store the final string */
string = (GLCchar32*)__glcContextQueryBuffer(inContext,
2*(length+1)*sizeof(int));
if (!string)
return NULL; /* GLC_RESOURCE_ERROR has been raised */
memcpy(string, inString, length*sizeof(int));
((int*)string)[length] = 0; /* Add the '\0' termination of the string */
}
break;
case GLC_UTF8_QSO:
{
GLCchar32* ucs4 = NULL;
const GLCchar8* utf8 = NULL;
GLCchar32 buffer = 0;
int shift = 0;
/* Determine the length of the final string */
utf8 = (const GLCchar8*)inString;
while(*utf8) {
shift = FcUtf8ToUcs4(utf8, &buffer, strlen((const char*)utf8));
if (shift < 0) {
/* There is an ill-formed character in the UTF-8 string, abort */
return NULL;
}
utf8 += shift;
length++;
}
/* Allocate the room to store the final string */
string = (GLCchar32*)__glcContextQueryBuffer(inContext,
2*(length+1)*sizeof(GLCchar32));
if (!string)
return NULL; /* GLC_RESOURCE_ERROR has been raised */
/* Perform the conversion */
utf8 = (const GLCchar8*)inString;
ucs4 = (GLCchar32*)string;
while(*utf8)
utf8 += FcUtf8ToUcs4(utf8, ucs4++, strlen((const char*)utf8));
*ucs4 = 0; /* Add the '\0' termination of the string */
}
break;
}
if (length) {
visualString = string + length + 1;
if (!fribidi_log2vis(string, length, &base, visualString, NULL, NULL,
NULL)) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
*outIsRTL = FRIBIDI_IS_RTL(base) ? GL_TRUE : GL_FALSE;
}
else
visualString = string;
*outLength = length;
return visualString;
}
/* Convert 'inCount' characters of 'inString' (stored in logical order) to UCS4
* format and return a copy of the converted string in visual order.
*/
GLCchar32* __glcConvertCountedStringToVisualUcs4(__GLCcontext* inContext,
GLboolean *outIsRTL,
const GLCchar* inString,
const GLint inCount)
{
GLCchar32* string = NULL;
FriBidiCharType base = FRIBIDI_TYPE_ON;
GLCchar32* visualString = NULL;
assert(inString);
switch(inContext->stringState.stringType) {
case GLC_UCS1:
{
const GLCchar8* ucs1 = (const GLCchar8*)inString;
GLCchar32* ucs4 = NULL;
GLint i = 0;
/* Allocate the room to store the final string */
string = (GLCchar32*)__glcContextQueryBuffer(inContext,
2*(inCount+1)*sizeof(GLCchar32));
if (!string)
return NULL; /* GLC_RESOURCE_ERROR has been raised */
ucs4 = string;
for (i = 0; i < inCount; i++)
*(ucs4++) = (GLCchar32)(*(ucs1++));
*ucs4 = 0; /* Add the '\0' termination of the string */
}
break;
case GLC_UCS2:
{
const GLCchar16* ucs2 = NULL;
GLCchar32* ucs4 = NULL;
GLint i = 0;
/* Allocate the room to store the final string */
string = (GLCchar32*)__glcContextQueryBuffer(inContext,
2*(inCount+1)*sizeof(GLCchar32));
if (!string)
return NULL; /* GLC_RESOURCE_ERROR has been raised */
ucs2 = (const GLCchar16*)inString;
ucs4 = string;
for (i = 0 ; i < inCount; i++)
*(ucs4++) = (GLCchar32)(*(ucs2++));
*ucs4 = 0; /* Add the '\0' termination of the string */
}
break;
case GLC_UCS4:
{
/* Allocate the room to store the final string */
string = (GLCchar32*)__glcContextQueryBuffer(inContext,
2*(inCount+1)*sizeof(int));
if (!string)
return NULL; /* GLC_RESOURCE_ERROR has been raised */
memcpy(string, inString, inCount*sizeof(int));
((int*)string)[inCount] = 0; /* Add the '\0' termination of the string */
}
break;
case GLC_UTF8_QSO:
{
GLCchar32* ucs4 = NULL;
const GLCchar8* utf8 = NULL;
GLint i = 0;
/* Allocate the room to store the final string */
string = (GLCchar32*)__glcContextQueryBuffer(inContext,
2*(inCount+1)*sizeof(GLCchar32));
if (!string)
return NULL; /* GLC_RESOURCE_ERROR has been raised */
/* Perform the conversion */
utf8 = (const GLCchar8*)inString;
ucs4 = (GLCchar32*)string;
for (i = 0; i < inCount; i++)
utf8 += FcUtf8ToUcs4(utf8, ucs4++, strlen((const char*)utf8));
*ucs4 = 0; /* Add the '\0' termination of the string */
}
break;
}
visualString = string + inCount;
if (!fribidi_log2vis(string, inCount, &base, visualString, NULL, NULL,
NULL)) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
*outIsRTL = FRIBIDI_IS_RTL(base) ? GL_TRUE : GL_FALSE;
return visualString;
}

486
3rdparty/quesoglc/win32/ocharmap.c vendored Normal file
View File

@ -0,0 +1,486 @@
/* QuesoGLC
* A free implementation of the OpenGL Character Renderer (GLC)
* Copyright (c) 2002, 2004-2007, 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: ocharmap.c,v 1.17 2007/02/25 13:30:48 bcoconni Exp $ */
/** \file
* defines the object __GLCcharMap which manage the charmaps of both the fonts
* and the masters. One of the purpose of this object is to encapsulate the
* GLYPHSET structure from Win32 GDI and to add it some more functionalities.
* It also allows to centralize the character map management for easier
* maintenance.
*/
/* QuesoGLC needs Windows 2000 or newer */
#define _WIN32_WINNT 0x0500
#include "internal.h"
/* Constructor of the object : it allocates memory and initializes the member
* of the new object.
* The user must give the initial GLYPHSET of the font or the master (which
* may be NULL) in which case the character map will be empty.
*/
__GLCcharMap* __glcCharMapCreate(__GLCmaster* inMaster)
{
__GLCcharMap* This = NULL;
This = (__GLCcharMap*)__glcMalloc(sizeof(__GLCcharMap));
if (!This) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
if (inMaster) {
HFONT font;
DWORD size;
HDC dc = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
if (FAILED(dc)) {
__glcFree(This);
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
font = CreateFontIndirect(&inMaster->pattern->elfLogFont);
if (FAILED(font)) {
DeleteDC(dc);
__glcFree(This);
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
if (FAILED(SelectObject(dc, font))) {
DeleteDC(dc);
DeleteObject(font);
__glcFree(This);
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
size = GetFontUnicodeRanges(dc, NULL);
if (!size) {
DeleteDC(dc);
DeleteObject(font);
__glcFree(This);
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
This->charSet = (LPGLYPHSET)__glcMalloc(size);
if (!This->charSet) {
DeleteDC(dc);
DeleteObject(font);
__glcRaiseError(GLC_RESOURCE_ERROR);
__glcFree(This);
return NULL;
}
if (!GetFontUnicodeRanges(dc, This->charSet)) {
DeleteDC(dc);
DeleteObject(font);
__glcFree(This->charSet);
__glcFree(This);
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
DeleteDC(dc);
DeleteObject(font);
}
else {
This->charSet = (LPGLYPHSET)__glcMalloc(sizeof(GLYPHSET));
if (!This->charSet) {
__glcRaiseError(GLC_RESOURCE_ERROR);
__glcFree(This);
return NULL;
}
}
/* The array 'map' will contain the actual character map */
This->map = __glcArrayCreate(sizeof(__GLCcharMapElement));
if (!This->map) {
__glcRaiseError(GLC_RESOURCE_ERROR);
__glcFree(This->charSet);
__glcFree(This);
return NULL;
}
return This;
}
/* Destructor of the object */
void __glcCharMapDestroy(__GLCcharMap* This)
{
if (This->map)
__glcArrayDestroy(This->map);
__glcFree(This->charSet);
__glcFree(This);
}
/* Add a given character to the character map. Afterwards, the character map
* will associate the glyph 'inGlyph' to the Unicode codepoint 'inCode'.
*/
void __glcCharMapAddChar(__GLCcharMap* This, GLint inCode, __GLCglyph* inGlyph)
{
__GLCcharMapElement* element = NULL;
__GLCcharMapElement* newElement = NULL;
int start = 0, middle = 0, end = 0;
assert(This->map);
assert(GLC_ARRAY_DATA(This->map));
assert(inCode >= 0);
/* Characters are stored by ascending order of their mapped code */
element = (__GLCcharMapElement*)GLC_ARRAY_DATA(This->map);
end = GLC_ARRAY_LENGTH(This->map) - 1;
/* Parse the array by dichotomy to look for the place where to add the new
* character.
*/
while (start <= end) {
middle = (start + end) >> 1;
/* If the character map already contains the new character then update the
* glyph then return.
*/
if (element[middle].mappedCode == (GLCulong)inCode) {
element[middle].glyph = inGlyph;
return;
}
else if (element[middle].mappedCode > (GLCulong)inCode)
end = middle - 1;
else
start = middle + 1;
}
/* If we have reached the end of the array then updated the rank 'middle'
* accordingly.
*/
if ((end >= 0) && (element[middle].mappedCode < (GLCulong)inCode))
middle++;
/* Insert the new character in the character map */
newElement = (__GLCcharMapElement*)__glcArrayInsertCell(This->map, middle, 1);
if (!newElement)
return;
newElement->mappedCode = inCode;
newElement->glyph = inGlyph;
return;
}
/* Remove a character from the character map */
void __glcCharMapRemoveChar(__GLCcharMap* This, GLint inCode)
{
__GLCcharMapElement* element = NULL;
int start = 0, middle = 0, end = 0;
assert(This->map);
assert(GLC_ARRAY_DATA(This->map));
assert(inCode >= 0);
/* Characters are stored by ascending order of their mapped code */
element = (__GLCcharMapElement*)GLC_ARRAY_DATA(This->map);
end = GLC_ARRAY_LENGTH(This->map) - 1;
/* Parse the array by dichotomy to look for the place where to add the new
* character.
*/
while (start <= end) {
middle = (start + end) >> 1;
/* When the character is found remove it from the array and return */
if (element[middle].mappedCode == (GLCulong)inCode) {
__glcArrayRemove(This->map, middle);
break;
}
else if (element[middle].mappedCode > (GLCulong)inCode)
end = middle - 1;
else
start = middle + 1;
}
}
/* Get the Unicode character name of the character which codepoint is inCode.
* Note : since the character maps of the fonts can be altered, this function
* can return 'LATIN CAPITAL LETTER B' whereas inCode contained 65 (which is
* the Unicode code point of 'LATIN CAPITAL LETTER A'.
*/
GLCchar* __glcCharMapGetCharName(__GLCcharMap* This, GLint inCode,
__GLCcontext* inContext)
{
GLCchar *buffer = NULL;
GLCchar8* name = NULL;
__GLCcharMapElement* element = NULL;
int start = 0, middle = 0, end = 0;
assert(This->map);
assert(GLC_ARRAY_DATA(This->map));
assert(inCode >= 0);
/* Characters are stored by ascending order of their mapped code */
element = (__GLCcharMapElement*)GLC_ARRAY_DATA(This->map);
end = GLC_ARRAY_LENGTH(This->map) - 1;
/* Parse the array by dichotomy to look for the Unicode codepoint that the
* request character maps to.
*/
while (start <= end) {
middle = (start + end) >> 1;
if (element[middle].mappedCode == (GLCulong)inCode) {
inCode = element[middle].glyph->codepoint;
break;
}
else if (element[middle].mappedCode > (GLCulong)inCode)
end = middle - 1;
else
start = middle + 1;
}
/* If we have not found the character in the character map, it means that
* the mapped code is equal to 'inCode' otherwise inCode is modified to
* contain the mapped code.
*/
name = __glcNameFromCode(inCode);
if (!name) {
__glcRaiseError(GLC_PARAMETER_ERROR);
return GLC_NONE;
}
/* Convert the Unicode to the current string type */
buffer = __glcConvertFromUtf8ToBuffer(inContext, name,
inContext->stringState.stringType);
if (!buffer) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return GLC_NONE;
}
return buffer;
}
/* Get the glyph corresponding to codepoint 'inCode' */
__GLCglyph* __glcCharMapGetGlyph(__GLCcharMap* This, GLint inCode)
{
__GLCcharMapElement* element = NULL;
int start = 0, middle = 0, end = 0;
assert(This->map);
assert(GLC_ARRAY_DATA(This->map));
assert(inCode >= 0);
/* Characters are stored by ascending order of their mapped code */
element = (__GLCcharMapElement*)GLC_ARRAY_DATA(This->map);
end = GLC_ARRAY_LENGTH(This->map) - 1;
/* Parse the array by dichotomy to find the glyph of the requested
* character.
*/
while (start <= end) {
middle = (start + end) >> 1;
if (element[middle].mappedCode == (GLCulong)inCode)
/* When the character is found return the corresponding glyph */
return element[middle].glyph;
else if (element[middle].mappedCode > (GLCulong)inCode)
end = middle - 1;
else
start = middle + 1;
}
/* No glyph has been defined yet for the requested character */
return NULL;
}
/* Check if a character is in the character map */
GLboolean __glcCharMapHasChar(__GLCcharMap* This, GLint inCode)
{
__GLCcharMapElement* element = NULL;
int start = 0, middle = 0, end = 0;
assert(This->map);
assert(GLC_ARRAY_DATA(This->map));
assert(inCode >= 0);
/* Characters are stored by ascending order of their mapped code */
element = (__GLCcharMapElement*)GLC_ARRAY_DATA(This->map);
end = GLC_ARRAY_LENGTH(This->map) - 1;
/* Parse the array by dichotomy to find the requested character. */
while (start <= end) {
middle = (start + end) >> 1;
/* The character has been found : return GL_TRUE */
if (element[middle].mappedCode == (GLCulong)inCode)
return GL_TRUE;
else if (element[middle].mappedCode > (GLCulong)inCode)
end = middle - 1;
else
start = middle + 1;
}
/* Check if the character identified by inCode exists in the font */
if (This->charSet->cGlyphsSupported) {
DWORD i = 0;
LPGLYPHSET charSet = This->charSet;
LPWCRANGE range = charSet->ranges;
for (; i < charSet->cRanges; i++, range++) {
if (inCode > (range->wcLow + range->cGlyphs - 1))
continue;
if (inCode >= range->wcLow)
return GL_TRUE;
}
}
return GL_FALSE;
}
/* Get the name of the character which is stored at rank 'inIndex' in the
* GLYPHSET of the face.
*/
GLCchar* __glcCharMapGetCharNameByIndex(__GLCcharMap* This, GLint inIndex,
__GLCcontext* inContext)
{
LPGLYPHSET charSet = This->charSet;
assert(inIndex >= 0);
if (charSet->cGlyphsSupported) {
DWORD i = 0;
LPWCRANGE range = charSet->ranges;
GLCchar8* name = NULL;
GLCchar* buffer = NULL;
for (; i < charSet->cRanges; i++, range++) {
if (inIndex > range->cGlyphs) {
inIndex -= range->cGlyphs;
continue;
}
/* Get the character name */
name = __glcNameFromCode(range->wcLow + inIndex);
if (!name) {
__glcRaiseError(GLC_PARAMETER_ERROR);
return GLC_NONE;
}
/* Performs the conversion to the current string type */
buffer = __glcConvertFromUtf8ToBuffer(inContext, name,
inContext->stringState.stringType);
if (!buffer) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return GLC_NONE;
}
return buffer;
}
}
/* The character has not been found */
__glcRaiseError(GLC_PARAMETER_ERROR);
return GLC_NONE;
}
/* Return the number of characters in the character map */
GLint __glcCharMapGetCount(__GLCcharMap* This)
{
return This->charSet->cGlyphsSupported;
}
/* Get the maximum mapped code of a character set */
GLint __glcCharMapGetMaxMappedCode(__GLCcharMap* This)
{
DWORD i = 0;
LPGLYPHSET charSet = This->charSet;
LPWCRANGE range = charSet->ranges;
GLCulong maxMappedCode = 0;
__GLCcharMapElement* element = NULL;
int length = 0;
assert(charSet->cGlyphsSupported);
assert(This->map);
assert(GLC_ARRAY_DATA(This->map));
for (; i < charSet->cRanges; i++, range++) {
WCHAR maxCode = range->wcLow + range->cGlyphs - 1;
maxMappedCode < maxCode ? maxCode : maxMappedCode;
}
/* Check that a code greater than the one found in the GLYPHSET is not
* stored in the array 'map'.
*/
element = (__GLCcharMapElement*)GLC_ARRAY_DATA(This->map);
length = GLC_ARRAY_LENGTH(This->map);
/* Return the greater of the code of both the GLYPHSET and the array 'map'*/
if (length)
return element[length-1].mappedCode > maxMappedCode ?
element[length-1].mappedCode : maxMappedCode;
else
return maxMappedCode;
}
/* Get the minimum mapped code of a character set */
GLint __glcCharMapGetMinMappedCode(__GLCcharMap* This)
{
DWORD i = 0;
LPGLYPHSET charSet = This->charSet;
LPWCRANGE range = charSet->ranges;
GLCulong minMappedCode = 0xffffffff;
__GLCcharMapElement* element = NULL;
int length = 0;
assert(charSet->cGlyphsSupported);
assert(This->map);
assert(GLC_ARRAY_DATA(This->map));
for (; i < charSet->cRanges; i++, range++)
minMappedCode > range->wcLow ? range->wcLow : minMappedCode;
/* Check that a code lower than the one found in the GLYPHSET is not
* stored in the array 'map'.
*/
element = (__GLCcharMapElement*)GLC_ARRAY_DATA(This->map);
length = GLC_ARRAY_LENGTH(This->map);
/* Return the lower of the code of both the GLYPHSET and the array 'map' */
if (length > 0)
return element[0].mappedCode < minMappedCode ?
element[0].mappedCode : minMappedCode;
else
return minMappedCode;
}

773
3rdparty/quesoglc/win32/ocontext.c vendored Normal file
View File

@ -0,0 +1,773 @@
/* QuesoGLC
* A free implementation of the OpenGL Character Renderer (GLC)
* Copyright (c) 2002, 2004-2007, 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$ */
/** \file
* defines the object __GLCcontext which is used to manage the contexts.
*/
/* QuesoGLC needs Windows 2000 or newer */
#define _WIN32_WINNT 0x0500
#include "internal.h"
#include <sys/stat.h>
#include <io.h>
#define BUFSIZE MAX_PATH
#include "texture.h"
#include FT_MODULE_H
__GLCcommonArea __glcCommonArea;
__GLCthreadArea* __glcThreadArea = NULL;
static void __glcContextUpdateHashTable(__GLCcontext *This);
static LPTSTR __glcAddCatalog(const GLCchar* inCatalog);
/* Constructor of the object : it allocates memory and initializes the member
* of the new object.
*/
__GLCcontext* __glcContextCreate(GLint inContext)
{
__GLCcontext *This = NULL;
This = (__GLCcontext*)__glcMalloc(sizeof(__GLCcontext));
if (!This) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
memset(This, 0, sizeof(__GLCcontext));
if (FT_New_Library(&__glcCommonArea.memoryManager, &This->library)) {
__glcRaiseError(GLC_RESOURCE_ERROR);
__glcFree(This);
return NULL;
}
FT_Add_Default_Modules(This->library);
#ifdef FT_CACHE_H
if (FTC_Manager_New(This->library, 0, 0, 0, __glcFileOpen, NULL,
&This->cache)) {
__glcRaiseError(GLC_RESOURCE_ERROR);
FT_Done_Library(This->library);
__glcFree(This);
return NULL;
}
#endif
This->node.prev = NULL;
This->node.next = NULL;
This->node.data = NULL;
This->catalogList = __glcArrayCreate(sizeof(GLCchar8*));
if (!This->catalogList) {
__glcRaiseError(GLC_RESOURCE_ERROR);
#ifdef FT_CACHE_H
FTC_Manager_Done(This->cache);
#endif
FT_Done_Library(This->library);
__glcFree(This);
return NULL;
}
This->masterHashTable = __glcArrayCreate(sizeof(GLCchar32));
if (!This->masterHashTable) {
__glcArrayDestroy(This->catalogList);
__glcRaiseError(GLC_RESOURCE_ERROR);
#ifdef FT_CACHE_H
FTC_Manager_Done(This->cache);
#endif
FT_Done_Library(This->library);
__glcFree(This);
return NULL;
}
__glcContextUpdateHashTable(This);
This->currentFontList.head = NULL;
This->currentFontList.tail = NULL;
This->fontList.head = NULL;
This->fontList.tail = NULL;
This->isCurrent = GL_FALSE;
This->isInGlobalCommand = GL_FALSE;
This->id = inContext;
This->pendingDelete = GL_FALSE;
This->stringState.callback = GLC_NONE;
This->stringState.dataPointer = NULL;
This->stringState.replacementCode = 0;
This->stringState.stringType = GLC_UCS1;
This->enableState.autoFont = GL_TRUE;
This->enableState.glObjects = GL_TRUE;
This->enableState.mipmap = GL_TRUE;
This->enableState.hinting = GL_FALSE;
This->enableState.extrude = GL_FALSE;
This->enableState.kerning = GL_FALSE;
This->renderState.resolution = 0.;
This->renderState.renderStyle = GLC_BITMAP;
This->bitmapMatrixStackDepth = 1;
This->bitmapMatrix = This->bitmapMatrixStack;
This->bitmapMatrix[0] = 1.;
This->bitmapMatrix[1] = 0.;
This->bitmapMatrix[2] = 0.;
This->bitmapMatrix[3] = 1.;
This->attribStackDepth = 0;
This->measurementBuffer = __glcArrayCreate(12 * sizeof(GLfloat));
if (!This->measurementBuffer) {
__glcArrayDestroy(This->masterHashTable);
__glcArrayDestroy(This->catalogList);
__glcRaiseError(GLC_RESOURCE_ERROR);
#ifdef FT_CACHE_H
FTC_Manager_Done(This->cache);
#endif
FT_Done_Library(This->library);
__glcFree(This);
return NULL;
}
This->isInCallbackFunc = GL_FALSE;
This->buffer = NULL;
This->bufferSize = 0;
This->lastFontID = 1;
This->vertexArray = __glcArrayCreate(2 * sizeof(GLfloat));
if (!This->vertexArray) {
__glcArrayDestroy(This->measurementBuffer);
__glcArrayDestroy(This->masterHashTable);
__glcArrayDestroy(This->catalogList);
__glcRaiseError(GLC_RESOURCE_ERROR);
#ifdef FT_CACHE_H
FTC_Manager_Done(This->cache);
#endif
FT_Done_Library(This->library);
__glcFree(This);
return NULL;
}
This->controlPoints = __glcArrayCreate(5 * sizeof(GLfloat));
if (!This->controlPoints) {
__glcArrayDestroy(This->vertexArray);
__glcArrayDestroy(This->measurementBuffer);
__glcArrayDestroy(This->masterHashTable);
__glcArrayDestroy(This->catalogList);
__glcRaiseError(GLC_RESOURCE_ERROR);
#ifdef FT_CACHE_H
FTC_Manager_Done(This->cache);
#endif
FT_Done_Library(This->library);
__glcFree(This);
return NULL;
}
This->endContour = __glcArrayCreate(sizeof(int));
if (!This->endContour) {
__glcArrayDestroy(This->controlPoints);
__glcArrayDestroy(This->vertexArray);
__glcArrayDestroy(This->measurementBuffer);
__glcArrayDestroy(This->masterHashTable);
__glcArrayDestroy(This->catalogList);
__glcRaiseError(GLC_RESOURCE_ERROR);
#ifdef FT_CACHE_H
FTC_Manager_Done(This->cache);
#endif
FT_Done_Library(This->library);
__glcFree(This);
return NULL;
}
This->vertexIndices = __glcArrayCreate(sizeof(GLuint));
if (!This->vertexIndices) {
__glcArrayDestroy(This->controlPoints);
__glcArrayDestroy(This->vertexArray);
__glcArrayDestroy(This->measurementBuffer);
__glcArrayDestroy(This->masterHashTable);
__glcArrayDestroy(This->endContour);
__glcArrayDestroy(This->catalogList);
__glcRaiseError(GLC_RESOURCE_ERROR);
#ifdef FT_CACHE_H
FTC_Manager_Done(This->cache);
#endif
FT_Done_Library(This->library);
__glcFree(This);
return NULL;
}
This->geomBatches = __glcArrayCreate(sizeof(__GLCgeomBatch));
if (!This->geomBatches) {
__glcArrayDestroy(This->controlPoints);
__glcArrayDestroy(This->vertexArray);
__glcArrayDestroy(This->measurementBuffer);
__glcArrayDestroy(This->masterHashTable);
__glcArrayDestroy(This->endContour);
__glcArrayDestroy(This->vertexIndices);
__glcArrayDestroy(This->catalogList);
__glcRaiseError(GLC_RESOURCE_ERROR);
#ifdef FT_CACHE_H
FTC_Manager_Done(This->cache);
#endif
FT_Done_Library(This->library);
__glcFree(This);
return NULL;
}
This->texture.id = 0;
This->texture.width = 0;
This->texture.heigth = 0;
This->texture.bufferObjectID = 0;
This->atlas.id = 0;
This->atlas.width = 0;
This->atlas.heigth = 0;
This->atlasList.head = NULL;
This->atlasList.tail = NULL;
This->atlasWidth = 0;
This->atlasHeight = 0;
This->atlasCount = 0;
/* The environment variable GLC_PATH is an alternate way to allow QuesoGLC
* to access to fonts catalogs/directories.
*/
/*Check if the GLC_PATH environment variables are exported */
if (getenv("GLC_CATALOG_LIST") || getenv("GLC_PATH")) {
char *path = NULL;
char *begin = NULL;
char *sepPos = NULL;
char *separator = NULL;
/* Read the paths of fonts file.
* First, try GLC_CATALOG_LIST...
*/
if (getenv("GLC_CATALOG_LIST"))
path = strdup(getenv("GLC_CATALOG_LIST"));
else if (getenv("GLC_PATH")) {
/* Try GLC_PATH which uses the same format than PATH */
path = strdup(getenv("GLC_PATH"));
}
/* Get the list separator */
separator = getenv("GLC_LIST_SEPARATOR");
if (!separator) {
#ifdef __WIN32__
/* Windows can not use a colon-separated list since the colon sign is
* used after the drive letter. The semicolon is used for the PATH
* variable, so we use it for consistency.
*/
separator = (char *)";";
#else
/* POSIX platforms uses colon-separated lists for the paths variables
* so we keep with it for consistency.
*/
separator = (char *)":";
#endif
}
if (path) {
/* Get each path and add the corresponding masters to the current
* context */
LPTSTR dup = NULL;
begin = path;
do {
sepPos = (char *)__glcFindIndexList(begin, 1, separator);
if (*sepPos)
*(sepPos++) = 0;
dup = __glcAddCatalog(begin);
if (!dup) {
__glcRaiseError(GLC_RESOURCE_ERROR);
}
else {
if (!__glcArrayAppend(This->catalogList, &dup)) {
__glcRaiseError(GLC_RESOURCE_ERROR);
__glcFree(dup);
}
}
begin = sepPos;
} while (*sepPos);
free(path);
__glcContextUpdateHashTable(This);
}
else {
/* strdup has failed to allocate memory to duplicate GLC_PATH => ERROR */
__glcRaiseError(GLC_RESOURCE_ERROR);
}
}
return This;
}
/* This function is called from FT_List_Finalize() to destroy all
* remaining fonts
*/
static void __glcFontDestructor(FT_Memory GLC_UNUSED_ARG(inMemory),
void* inData, void* inUser)
{
__GLCfont *font = (__GLCfont*)inData;
__GLCcontext* ctx = (__GLCcontext*)inUser;
assert(ctx);
if (font)
__glcFontDestroy(font, ctx);
}
/* Destructor of the object : it first destroys all the GLC objects that have
* been created during the life of the context. Then it releases the memory
* occupied by the GLC state struct.
* It does not destroy GL objects associated with the GLC context since we can
* not be sure that the current GL context is the GL context that contains the
* GL objects designated by the GLC context that we are destroying. This could
* happen if the user calls glcDeleteContext() after the GL context has been
* destroyed of after the user has changed the current GL context.
*/
void __glcContextDestroy(__GLCcontext *This)
{
int i = 0;
assert(This);
/* Destroy the list of catalogs */
for (i = 0; i < GLC_ARRAY_LENGTH(This->catalogList); i++) {
GLCchar8* string = ((GLCchar8**)GLC_ARRAY_DATA(This->catalogList))[i];
assert(string);
free(string);
}
__glcArrayDestroy(This->catalogList);
/* Destroy GLC_CURRENT_FONT_LIST */
FT_List_Finalize(&This->currentFontList, NULL,
&__glcCommonArea.memoryManager, NULL);
/* Destroy GLC_FONT_LIST */
FT_List_Finalize(&This->fontList, __glcFontDestructor,
&__glcCommonArea.memoryManager, This);
if (This->masterHashTable)
__glcArrayDestroy(This->masterHashTable);
FT_List_Finalize(&This->atlasList, NULL,
&__glcCommonArea.memoryManager, NULL);
if (This->bufferSize)
__glcFree(This->buffer);
if (This->measurementBuffer)
__glcArrayDestroy(This->measurementBuffer);
if (This->vertexArray)
__glcArrayDestroy(This->vertexArray);
if (This->controlPoints)
__glcArrayDestroy(This->controlPoints);
if (This->endContour)
__glcArrayDestroy(This->endContour);
if (This->vertexIndices)
__glcArrayDestroy(This->vertexIndices);
if (This->geomBatches)
__glcArrayDestroy(This->geomBatches);
#ifdef FT_CACHE_H
FTC_Manager_Done(This->cache);
#endif
FT_Done_Library(This->library);
__glcFree(This);
}
/* Return the first font in GLC_CURRENT_FONT_LIST that maps 'inCode'.
* If there is no such font, the function returns NULL.
* 'inCode' must be given in UCS-4 format.
*/
static __GLCfont* __glcLookupFont(GLint inCode, FT_List fontList)
{
FT_ListNode node = NULL;
for (node = fontList->head; node; node = node->next) {
__GLCfont* font = (__GLCfont*)node->data;
/* Check if the character identified by inCode exists in the font */
if (__glcCharMapHasChar(font->charMap, inCode))
return font;
}
return NULL;
}
/* Calls the callback function (does various tests to determine if it is
* possible) and returns GL_TRUE if it has succeeded or GL_FALSE otherwise.
* 'inCode' must be given in UCS-4 format.
*/
static GLboolean __glcCallCallbackFunc(GLint inCode,
__GLCcontext *inContext)
{
GLCfunc callbackFunc = NULL;
GLboolean result = GL_FALSE;
GLint aCode = 0;
/* Recursivity is not allowed */
if (inContext->isInCallbackFunc)
return GL_FALSE;
callbackFunc = inContext->stringState.callback;
if (!callbackFunc)
return GL_FALSE;
/* Convert the character code back to the current string type */
aCode = __glcConvertUcs4ToGLint(inContext, inCode);
/* Check if the character has been converted */
if (aCode < 0)
return GL_FALSE;
inContext->isInCallbackFunc = GL_TRUE;
/* Call the callback function with the character converted to the current
* string type.
*/
result = (*callbackFunc)(aCode);
inContext->isInCallbackFunc = GL_FALSE;
return result;
}
/* Returns the ID of the first font in GLC_CURRENT_FONT_LIST that maps
* 'inCode'. If there is no such font and GLC_AUTO_FONT is enabled, the
* function attempts to append a new font from GLC_FONT_LIST (or from a master)
* to GLC_CURRENT_FONT_LIST. If the attempt fails the function returns zero.
* 'inCode' must be given in UCS-4 format.
*/
__GLCfont* __glcContextGetFont(__GLCcontext *This, GLint inCode)
{
__GLCfont* font = NULL;
/* Look for a font in the current font list */
font = __glcLookupFont(inCode, &This->currentFontList);
/* If a font has been found return */
if (font)
return font;
/* If a callback function is defined for GLC_OP_glcUnmappedCode then call it.
* The callback function should return GL_TRUE if it succeeds in appending to
* GLC_CURRENT_FONT_LIST the ID of a font that maps 'inCode'.
*/
if (__glcCallCallbackFunc(inCode, This)) {
font = __glcLookupFont(inCode, &This->currentFontList);
if (font)
return font;
}
/* If the value of the boolean variable GLC_AUTOFONT is GL_TRUE then search
* GLC_FONT_LIST for the first font that maps 'inCode'. If the search
* succeeds, then append the font's ID to GLC_CURRENT_FONT_LIST.
*/
if (This->enableState.autoFont) {
__GLCmaster* master = NULL;
font = __glcLookupFont(inCode, &This->fontList);
if (font) {
__glcAppendFont(This, font);
return font;
}
master = __glcMasterMatchCode(This, inCode);
if (!master)
return NULL;
font = __glcNewFontFromMaster(NULL, glcGenFontID(), master, This);
__glcMasterDestroy(master);
if (font) {
/* Add the font to the GLC_CURRENT_FONT_LIST */
__glcAppendFont(This, font);
return font;
}
}
return NULL;
}
/* Sometimes informations may need to be stored temporarily by a thread.
* The so-called 'buffer' is created for that purpose. Notice that it is a
* component of the GLC state struct hence its lifetime is the same as the
* GLC state's lifetime.
* __glcCtxQueryBuffer() should be called whenever the buffer is to be used
* in order to check if it is big enough to store infos.
* Note that the only memory management function used below is 'realloc' which
* means that the buffer goes bigger and bigger until it is freed. No function
* is provided to reduce its size so it should be freed and re-allocated
* manually in case of emergency ;-)
*/
GLCchar* __glcContextQueryBuffer(__GLCcontext *This, int inSize)
{
GLCchar* buffer;
buffer = This->buffer;
if (inSize > This->bufferSize) {
buffer = (GLCchar*)__glcRealloc(This->buffer, inSize);
if (!buffer) {
__glcRaiseError(GLC_RESOURCE_ERROR);
}
else {
This->buffer = buffer;
This->bufferSize = inSize;
}
}
return buffer;
}
static int CALLBACK __glcEnumUpdateHashTable(ENUMLOGFONTEX* inElfe,
NEWTEXTMETRICEX* inNtme,
DWORD inFontType, LPARAM inData)
{
__GLCarray* masterHashTable = (__GLCarray*)inData;
GLCchar32* hashTable = (GLCchar32*)GLC_ARRAY_DATA(masterHashTable);
TCHAR* ptr = NULL;
int length = GLC_ARRAY_LENGTH(masterHashTable);
int i = 0;
GLCchar32 hashValue = 0;
if (!(inFontType & TRUETYPE_FONTTYPE))
return 1;
hashValue = __glcHashValue(&inElfe->elfLogFont);
/* Check if the font is already registered in the hash table */
for (i = 0; i < length; i++) {
if (hashTable[i] == hashValue)
break;
}
/* If the font is already registered then parse the next one */
if (i != length)
return 1;
/* Register the font (i.e. append its hash value to the hash table) */
if (!__glcArrayAppend(masterHashTable, &hashValue)) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return 0;
}
return 1;
}
/* Update the hash table that allows to convert master IDs into FontConfig
* patterns.
*/
static void __glcContextUpdateHashTable(__GLCcontext *This)
{
int i = 0;
LOGFONT lfont;
HDC dc = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
if (FAILED(dc)) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return;
}
/* Enumerates all fonts in all character sets */
lfont.lfCharSet = DEFAULT_CHARSET;
lfont.lfFaceName[0] = '\0';
EnumFontFamiliesEx(dc, &lfont, (FONTENUMPROC)__glcEnumUpdateHashTable,
(LPARAM)This->masterHashTable, 0);
DeleteDC(dc);
}
static LPTSTR __glcAddCatalog(const GLCchar* inCatalog)
{
WIN32_FIND_DATA FindFileData;
LPTSTR DirSpec = NULL;
size_t length = 0;
HANDLE hFind = INVALID_HANDLE_VALUE;
TCHAR* ptr;
DirSpec = (LPTSTR) __glcMalloc(BUFSIZE);
if (!DirSpec) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
/* Check that input is not larger than allowed */
StringCbLength(inCatalog, BUFSIZE, &length);
if (length > (BUFSIZE - 2)) {
__glcRaiseError(GLC_PARAMETER_ERROR);
__glcFree(DirSpec);
return NULL;
}
StringCbCopyN(DirSpec, BUFSIZE, inCatalog, length+1);
StringCbCatN(DirSpec, BUFSIZE, TEXT("\\*"), 2*sizeof(TCHAR));
hFind = FindFirstFile(DirSpec, &FindFileData);
if (hFind == INVALID_HANDLE_VALUE) {
__glcRaiseError(GLC_PARAMETER_ERROR);
__glcFree(DirSpec);
return NULL;
}
AddFontResourceEx(FindFileData.cFileName, FR_PRIVATE, 0);
while (FindNextFile(hFind, &FindFileData))
AddFontResourceEx(FindFileData.cFileName, FR_PRIVATE, 0);
FindClose(hFind);
ptr = (TCHAR*)DirSpec;
ptr[length+1] = (TCHAR)'\0';
return DirSpec;
}
/* Append a catalog to the context catalog list */
void __glcContextAppendCatalog(__GLCcontext* This, const GLCchar* inCatalog)
{
LPTSTR DirSpec = __glcAddCatalog(inCatalog);
if (!DirSpec)
return;
if (!__glcArrayAppend(This->catalogList, DirSpec)) {
__glcRaiseError(GLC_RESOURCE_ERROR);
__glcFree(DirSpec);
return;
}
__glcContextUpdateHashTable(This);
}
/* Prepend a catalog to the context catalog list */
void __glcContextPrependCatalog(__GLCcontext* This, const GLCchar* inCatalog)
{
LPTSTR DirSpec = __glcAddCatalog(inCatalog);
if (!DirSpec)
return;
if (!__glcArrayInsert(This->catalogList, 0, &dup)) {
__glcRaiseError(GLC_RESOURCE_ERROR);
free(dup);
return;
}
__glcContextUpdateHashTable(This);
}
/* Get the path of the catalog identified by inIndex */
GLCchar8* __glcContextGetCatalogPath(__GLCcontext* This, GLint inIndex)
{
if (inIndex >= GLC_ARRAY_LENGTH(This->catalogList)) {
__glcRaiseError(GLC_PARAMETER_ERROR);
return NULL;
}
return ((GLCchar8**)GLC_ARRAY_DATA(This->catalogList))[inIndex];
}
/* Remove a catalog from the context catalog list */
void __glcContextRemoveCatalog(__GLCcontext* This, GLint inIndex)
{
FT_ListNode node = NULL;
int i = 0;
WIN32_FIND_DATA FindFileData;
LPTSTR DirSpec = NULL;
HANDLE hFind = INVALID_HANDLE_VALUE;
if (inIndex >= GLC_ARRAY_LENGTH(This->catalogList)) {
__glcRaiseError(GLC_PARAMETER_ERROR);
return;
}
DirSpec = ((LPTSTR*)GLC_ARRAY_DATA(This->catalogList))[inIndex];
assert(DirSpec);
__glcArrayRemove(This->catalogList, inIndex);
StringCbCatN(DirSpec, BUFSIZE, TEXT("\\*"), 2*sizeof(TCHAR));
hFind = FindFirstFile(DirSpec, &FindFileData);
if (hFind == INVALID_HANDLE_VALUE) {
__glcRaiseError(GLC_PARAMETER_ERROR);
__glcFree(DirSpec);
return;
}
RemoveFontResourceEx(FindFileData.cFileName, FR_PRIVATE, 0);
while (FindNextFile(hFind, &FindFileData))
RemoveFontResourceEx(FindFileData.cFileName, FR_PRIVATE, 0);
FindClose(hFind);
__glcFree(DirSpec);
/* Re-create the hash table from scratch */
GLC_ARRAY_LENGTH(This->masterHashTable) = 0;
__glcContextUpdateHashTable(This);
/* Remove from GLC_FONT_LIST the fonts that were defined in the catalog that
* has been removed.
*/
for (node = This->fontList.head; node; node = node->next) {
__GLCfont* font = (__GLCfont*)(node->data);
__GLCmaster* master = __glcMasterCreate(font->parentMasterID, This);
GLCchar32 hashValue = 0;
GLCchar32* hashTable = (GLCchar32*)GLC_ARRAY_DATA(This->masterHashTable);
int length = GLC_ARRAY_LENGTH(This->masterHashTable);
int i = 0;
if (!master) {
__glcRaiseError(GLC_RESOURCE_ERROR);
continue;
}
/* Check if the hash value of the master is in the hash table */
hashValue = GLC_MASTER_HASH_VALUE(master);
for (i = 0; i < length; i++) {
if (hashValue == hashTable[i])
break;
}
/* The font is not contained in the hash table => remove it */
if (i == length)
glcDeleteFont(font->id);
__glcMasterDestroy(master);
}
}

775
3rdparty/quesoglc/win32/omaster.c vendored Normal file
View File

@ -0,0 +1,775 @@
/* QuesoGLC
* A free implementation of the OpenGL Character Renderer (GLC)
* Copyright (c) 2002, 2004-2007, 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$ */
/** \file
* defines the object __GLCmaster which manage the masters
*/
/* QuesoGLC needs Windows 2000 or newer */
#define _WIN32_WINNT 0x0500
#include "internal.h"
typedef struct __GLCdataRec __GLCdata;
struct __GLCdataRec {
__GLCarray* hashTable;
__GLCmaster* master;
__GLCcharMap* charMap;
void* ptr;
GLint index;
};
/* Hash function of strings adapted from "Compilers : Principles, Techniques and
* Tools - Alfred V. Aho, Ravi Sethi and Jeffrey D. Ullman"
*/
GLCchar32 __glcHashValue(LPLOGFONT inLogFont)
{
TCHAR* ptr = inLogFont->lfFaceName;
GLCchar32 tmp = 0;
GLCchar32 hashValue = 0;
while(*ptr) {
hashValue = (hashValue << 4) + (*ptr);
tmp = hashValue & 0xf0000000;
if (tmp) {
hashValue = hashValue ^ (tmp >> 24);
hashValue = hashValue ^ tmp;
}
ptr++;
}
return hashValue;
}
static int CALLBACK __glcEnumMasterCreate(ENUMLOGFONTEX* inElfe,
NEWTEXTMETRICEX* inNtme,
DWORD inFontType, LPARAM inData)
{
__GLCarray* masterHashTable = ((__GLCdata*)inData)->hashTable;
GLCchar32* hashTable = (GLCchar32*)GLC_ARRAY_DATA(masterHashTable);
int length = GLC_ARRAY_LENGTH(masterHashTable);
int i = 0;
GLCchar32 hashValue = 0;
if (!(inFontType & TRUETYPE_FONTTYPE))
return 1;
hashValue = __glcHashValue(&inElfe->elfLogFont);
/* Check if the font is already registered in the hash table */
for (i = 0; i < length; i++) {
if (hashTable[i] == hashValue) {
__GLCmaster* master = ((__GLCdata*)inData)->master;
memcpy(master->pattern, &inElfe->elfLogFont, sizeof(ENUMLOGFONTEX));
return 0;
}
}
return 1;
}
/* Constructor of the object : it allocates memory and initializes the member
* of the new object.
*/
__GLCmaster* __glcMasterCreate(GLint inMaster, __GLCcontext* inContext)
{
__GLCmaster* This = NULL;
__GLCdata data = {NULL, NULL, NULL, NULL, 0};
LOGFONT lfont;
HDC dc = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
if (FAILED(dc)) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
This = (__GLCmaster*)__glcMalloc(sizeof(__GLCmaster));
if (!This) {
__glcRaiseError(GLC_RESOURCE_ERROR);
DeleteDC(dc);
return NULL;
}
data.hashTable = inContext->masterHashTable;
data.master = This;
/* Enumerates all fonts in all character sets */
lfont.lfCharSet = DEFAULT_CHARSET;
lfont.lfFaceName[0] = '\0';
EnumFontFamiliesEx(dc, &lfont, (FONTENUMPROC)__glcEnumMasterCreate,
(LPARAM)&data, 0);
DeleteDC(dc);
return This;
}
/* Destructor of the object */
void __glcMasterDestroy(__GLCmaster* This)
{
__glcFree(This->pattern);
__glcFree(This);
}
/* Merge the character map 'inCharMap' in the character map 'This' */
static GLboolean __glcCharMapUnion(__GLCcharMap* This, LPGLYPHSET inCharSet)
{
LPGLYPHSET result = NULL;
LPGLYPHSET charSet = This->charSet;
DWORD i = 0;
DWORD resultSize = 0;
LPWCRANGE range = NULL;
assert(charSet);
assert(inCharSet);
if (!inCharSet->cGlyphsSupported)
return GL_TRUE;
if (!charSet->cGlyphsSupported)
resultSize = inCharSet->cbThis;
else
resultSize = charSet->cbThis + inCharSet->cRanges * sizeof(WCRANGE);
result = (LPGLYPHSET)__glcMalloc(resultSize);
if (!result) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return GL_FALSE;
}
if (!charSet->cGlyphsSupported) {
memcpy(result, inCharSet, inCharSet->cbThis);
__glcFree(charSet);
This->charSet = result;
return GL_TRUE;
}
else {
memcpy(result, charSet, charSet->cbThis);
result->cbThis = resultSize;
}
for (; i < inCharSet->cRanges; i++) {
DWORD j = 0;
LPWCRANGE range2 = result->ranges;
WCRANGE temp;
range = inCharSet->ranges + i;
for (; j < result->cRanges; j++, range2++) {
if (range->wcLow > (range2->wcLow + range2->cGlyphs -1))
continue;
if ((range->wcLow + range->cGlyphs - 1) < range2->wcLow) {
memcpy(range2+1, range2, (result->cRanges - j) * sizeof(WCRANGE));
range2->wcLow = range->wcLow;
range2->cGlyphs = range2->cGlyphs;
result->cRanges++;
break;
}
if ((range->wcLow >= range2->wcLow) && ((range->wcLow + range->cGlyphs) <= (range2->wcLow + range2->cGlyphs)))
break;
if ((range->wcLow < range2->wcLow) && ((range->wcLow + range->cGlyphs) <= (range2->wcLow + range2->cGlyphs))) {
range2->cGlyphs = range2->wcLow + range2->cGlyphs - range->wcLow;
range2->wcLow = range->wcLow;
break;
}
temp.wcLow = (range->wcLow < range2->wcLow) ? range->wcLow : range2->wcLow;
temp.cGlyphs = range2->wcLow + range2->cGlyphs - temp.wcLow;
range = &temp;
if (result->cRanges-j-1) {
memcpy(range2-1, range2, (result->cRanges-j-1)*sizeof(WCRANGE));
result->cRanges--;
j--;
range2--;
}
}
if (j == result->cRanges) {
range2->wcLow = range->wcLow;
range2->cGlyphs = range->cGlyphs;
result->cRanges++;
}
}
range = result->ranges;
result->cGlyphsSupported = 0;
for (i = 0; i < result->cRanges; i++, range++)
result->cGlyphsSupported += range->cGlyphs;
/* Destroy the previous GLYPHSET and replace it by the new one */
__glcFree(This->charSet);
This->charSet = result;
return GL_TRUE;
}
static int CALLBACK __glcEnumMasterGetCharMap(ENUMLOGFONTEX* inElfe,
NEWTEXTMETRICEX* inNtme,
DWORD inFontType, LPARAM inData)
{
__GLCdata* data = (__GLCdata*)inData;
GLCchar32 hashValue = GLC_MASTER_HASH_VALUE(data->master);
HFONT font;
DWORD size;
HDC dc;
LPGLYPHSET charSet = NULL;
if (!(inFontType & TRUETYPE_FONTTYPE))
return 1;
if (hashValue != __glcHashValue(&inElfe->elfLogFont))
return 1;
dc = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
if (FAILED(dc)) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return 0;
}
font = CreateFontIndirect(&inElfe->elfLogFont);
if (FAILED(font)) {
__glcRaiseError(GLC_RESOURCE_ERROR);
DeleteDC(dc);
return 0;
}
if (FAILED(SelectObject(dc, font))) {
DeleteDC(dc);
DeleteObject(font);
__glcRaiseError(GLC_RESOURCE_ERROR);
return 0;
}
size = GetFontUnicodeRanges(dc, NULL);
if (!size) {
DeleteDC(dc);
DeleteObject(font);
__glcRaiseError(GLC_RESOURCE_ERROR);
return 0;
}
charSet = (LPGLYPHSET)__glcMalloc(size);
if (!charSet) {
DeleteDC(dc);
DeleteObject(font);
__glcRaiseError(GLC_RESOURCE_ERROR);
return 0;
}
if (!GetFontUnicodeRanges(dc, charSet)) {
DeleteDC(dc);
DeleteObject(font);
__glcFree(charSet);
__glcRaiseError(GLC_RESOURCE_ERROR);
return 0;
}
DeleteDC(dc);
DeleteObject(font);
__glcCharMapUnion(data->charMap, charSet);
__glcFree(charSet);
return 1;
}
/* Extract the charmap of the master */
__GLCcharMap* __glcMasterGetCharMap(__GLCmaster* This, __GLCcontext* inContext)
{
LOGFONT lfont;
__GLCdata data = {NULL, NULL, NULL, NULL, 0};
__GLCcharMap* charMap = NULL;
HDC dc = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
if (FAILED(dc)) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
charMap = __glcCharMapCreate(This);
if (!charMap) {
__glcRaiseError(GLC_RESOURCE_ERROR);
DeleteDC(dc);
return NULL;
}
data.master = This;
data.charMap = charMap;
/* Enumerates all fonts in all character sets */
lfont.lfCharSet = DEFAULT_CHARSET;
lfont.lfFaceName[0] = '\0';
EnumFontFamiliesEx(dc, &lfont, (FONTENUMPROC)__glcEnumMasterGetCharMap,
(LPARAM)&data, 0);
DeleteDC(dc);
return charMap;
}
static int CALLBACK __glcEnumMasterGetFaceName(ENUMLOGFONTEX* inElfe,
NEWTEXTMETRICEX* inNtme,
DWORD inFontType, LPARAM inData)
{
__GLCdata* data = (__GLCdata*)inData;
GLCchar32 hashValue = GLC_MASTER_HASH_VALUE(data->master);
if (!(inFontType & TRUETYPE_FONTTYPE))
return 1;
if (hashValue != __glcHashValue(&inElfe->elfLogFont))
return 1;
if (--data->index)
return 1;
data->ptr = __glcMalloc(LF_FACESIZE * sizeof(TCHAR));
if (!data->ptr) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return 0;
}
memcpy(data->ptr, inElfe->elfStyle, LF_FACESIZE * sizeof(TCHAR));
return 0;
}
/* Get the style name of the face identified by inIndex */
GLCchar8* __glcMasterGetFaceName(__GLCmaster* This, __GLCcontext* inContext,
GLint inIndex)
{
LOGFONT lfont;
__GLCdata data = {NULL, NULL, NULL, NULL, 0};
HDC dc = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
if (FAILED(dc)) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
data.master = This;
data.index = inIndex;
/* Enumerates all fonts in all character sets */
lfont.lfCharSet = DEFAULT_CHARSET;
lfont.lfFaceName[0] = '\0';
if (EnumFontFamiliesEx(dc, &lfont, (FONTENUMPROC)__glcEnumMasterGetFaceName,
(LPARAM)&data, 0)) {
/* Could not find face identified by inIndex */
assert(data.index);
__glcRaiseError(GLC_PARAMETER_ERROR);
return NULL;
}
assert(!data.index);
DeleteDC(dc);
return (GLCchar8*)data.ptr;
}
static int CALLBACK __glcEnumMasterIsFixedPitch(ENUMLOGFONTEX* inElfe,
NEWTEXTMETRICEX* inNtme,
DWORD inFontType, LPARAM inData)
{
__GLCdata* data = (__GLCdata*)inData;
GLCchar32 hashValue = GLC_MASTER_HASH_VALUE(data->master);
if (!(inFontType & TRUETYPE_FONTTYPE))
return 1;
if (hashValue == __glcHashValue(&inElfe->elfLogFont))
data->index += (inNtme->ntmTm.tmPitchAndFamily & 1);
return 1;
}
/* Is this a fixed font ? */
GLboolean __glcMasterIsFixedPitch(__GLCmaster* This)
{
LOGFONT lfont;
__GLCdata data = {NULL, NULL, NULL, NULL, 0};
HDC dc = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
if (FAILED(dc)) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return GL_FALSE;
}
data.master = This;
/* Enumerates all fonts in all character sets */
lfont.lfCharSet = DEFAULT_CHARSET;
lfont.lfFaceName[0] = '\0';
EnumFontFamiliesEx(dc, &lfont, (FONTENUMPROC)__glcEnumMasterGetFaceName,
(LPARAM)&data, 0);
DeleteDC(dc);
return data.index ? GL_FALSE : GL_TRUE;
}
static int CALLBACK __glcEnumMasterFaceCount(ENUMLOGFONTEX* inElfe,
NEWTEXTMETRICEX* inNtme,
DWORD inFontType, LPARAM inData)
{
__GLCdata* data = (__GLCdata*)inData;
GLCchar32 hashValue = GLC_MASTER_HASH_VALUE(data->master);
if (!(inFontType & TRUETYPE_FONTTYPE))
return 1;
if (hashValue == __glcHashValue(&inElfe->elfLogFont))
data->index++;
return 1;
}
/* Get the face count of the master */
GLint __glcMasterFaceCount(__GLCmaster* This, __GLCcontext* inContext)
{
LOGFONT lfont;
__GLCdata data = {NULL, NULL, NULL, NULL, 0};
HDC dc = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
if (FAILED(dc)) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return 0;
}
data.master = This;
/* Enumerates all fonts in all character sets */
lfont.lfCharSet = DEFAULT_CHARSET;
lfont.lfFaceName[0] = '\0';
EnumFontFamiliesEx(dc, &lfont, (FONTENUMPROC)__glcEnumMasterGetFaceName,
(LPARAM)&data, 0);
DeleteDC(dc);
return data.index;
}
/* This subroutine is called whenever the user wants to access to informations
* that have not been loaded from the font files yet. In order to reduce disk
* accesses, informations such as the master format, full name or version are
* read "just in time" i.e. only when the user requests them.
*/
GLCchar8* __glcMasterGetInfo(__GLCmaster* This, __GLCcontext* inContext,
GLCenum inAttrib)
{
TCHAR* string = NULL;
GLCchar *buffer = NULL;
static TCHAR unknown[] = TEXT("Unknown");
#ifdef UNICODE
int size = 0;
size_t length = 0;
LPSTR stringUTF8 = NULL;
#endif
/* Get the Unicode string which corresponds to the requested attribute */
switch(inAttrib) {
case GLC_FAMILY:
string = This->pattern->elfLogFont.lfFaceName;
break;
case GLC_FULL_NAME_SGI:
string = This->pattern->elfFullName;
break;
case GLC_VERSION:
case GLC_VENDOR:
case GLC_MASTER_FORMAT:
string = unknown;
break;
}
#ifdef UNICODE
StringCchLength(string, STRSAFE_MAX_CCH, &length);
size = WideCharToMultiByte(CP_UTF8, 0, string, length, NULL, 0, NULL, NULL);
stringUTF8 = (LPSTR)__glcMalloc(size);
if (!stringUTF8) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
WideCharToMultiByte(CP_UTF8, 0, string, length, stringUTF8, size, NULL, NULL);
string = stringUTF8;
#endif
if (string) {
/* Convert the string and store it in the context buffer */
buffer = __glcConvertFromUtf8ToBuffer(inContext, string,
inContext->stringState.stringType);
if (!buffer)
__glcRaiseError(GLC_RESOURCE_ERROR);
}
else
__glcRaiseError(GLC_RESOURCE_ERROR);
return buffer;
}
static int CALLBACK __glcEnumMasterFromFamily(ENUMLOGFONTEX* inElfe,
NEWTEXTMETRICEX* inNtme,
DWORD inFontType, LPARAM inData)
{
__GLCdata* data = (__GLCdata*)inData;
__GLCmaster* master = ((__GLCdata*)inData)->master;
if (!(inFontType & TRUETYPE_FONTTYPE))
return 1;
if (lstrcmp(inElfe->elfLogFont.lfFaceName, data->ptr))
return 1;
memcpy(master->pattern, &inElfe->elfLogFont, sizeof(ENUMLOGFONTEX));
return 0;
}
/* Create a master on the basis of the family name */
__GLCmaster* __glcMasterFromFamily(__GLCcontext* inContext, GLCchar8* inFamily)
{
__GLCmaster* This = NULL;
TCHAR* family = NULL;
LOGFONT lfont;
__GLCdata data = {NULL, NULL, NULL, NULL, 0};
#ifdef UNICODE
int size = 0;
#endif
HDC dc = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
if (FAILED(dc)) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
This = (__GLCmaster*)__glcMalloc(sizeof(__GLCmaster));
if (!This) {
__glcRaiseError(GLC_RESOURCE_ERROR);
DeleteDC(dc);
return NULL;
}
#ifdef UNICODE
int size = MultiByteToWideChar(CP_UTF8, 0, inFamily, -1, NULL, 0);
family = (LPWSTR)__glcMalloc(size * sizeof(WCHAR));
if (!family) {
__glcRaiseError(GLC_RESOURCE_ERROR);
DeleteDC(dc);
__glcFree(This);
return NULL;
}
MultiByteToWideChar(CP_UTF8, 0, inFamily, -1, family, size);
#else
family = (TCHAR*)inFamily;
#endif
data.master = This;
data.ptr = family;
/* Enumerates all fonts in all character sets */
lfont.lfCharSet = DEFAULT_CHARSET;
lfont.lfFaceName[0] = '\0';
if (EnumFontFamiliesEx(dc, &lfont, (FONTENUMPROC)__glcEnumMasterFromFamily,
(LPARAM)&data, 0)) {
__glcFree(This);
This = NULL;
data.master = NULL;
}
DeleteDC(dc);
return data.master;
}
static int CALLBACK __glcEnumMasterMatchCode(ENUMLOGFONTEX* inElfe,
NEWTEXTMETRICEX* inNtme,
DWORD inFontType, LPARAM inData)
{
__GLCdata* data = (__GLCdata*)inData;
GLint code = data->index;
__GLCmaster* master = data->master;
HFONT font;
DWORD size;
HDC dc;
LPGLYPHSET charSet = NULL;
if (!(inFontType & TRUETYPE_FONTTYPE))
return 1;
dc = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
if (FAILED(dc)) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return 0;
}
font = CreateFontIndirect(&inElfe->elfLogFont);
if (FAILED(font)) {
__glcRaiseError(GLC_RESOURCE_ERROR);
DeleteDC(dc);
return 0;
}
if (FAILED(SelectObject(dc, font))) {
DeleteDC(dc);
DeleteObject(font);
__glcRaiseError(GLC_RESOURCE_ERROR);
return 0;
}
size = GetFontUnicodeRanges(dc, NULL);
if (!size) {
DeleteDC(dc);
DeleteObject(font);
__glcRaiseError(GLC_RESOURCE_ERROR);
return 0;
}
charSet = (LPGLYPHSET)__glcMalloc(size);
if (!charSet) {
DeleteDC(dc);
DeleteObject(font);
__glcRaiseError(GLC_RESOURCE_ERROR);
return 0;
}
if (!GetFontUnicodeRanges(dc, charSet)) {
DeleteDC(dc);
DeleteObject(font);
__glcFree(charSet);
__glcRaiseError(GLC_RESOURCE_ERROR);
return 0;
}
DeleteDC(dc);
DeleteObject(font);
/* Check if the character identified by inCode exists in the font */
if (charSet->cGlyphsSupported) {
DWORD i = 0;
LPWCRANGE range = charSet->ranges;
for (; i < charSet->cRanges; i++, range++) {
if (code > (range->wcLow + range->cGlyphs - 1))
continue;
if (code >= range->wcLow) {
memcpy(master->pattern, &inElfe->elfLogFont, sizeof(ENUMLOGFONTEX));
__glcFree(charSet);
return 0;
}
}
}
__glcFree(charSet);
return 1;
}
/* Create a master which contains at least a font which match the character
* identified by inCode.
*/
__GLCmaster* __glcMasterMatchCode(__GLCcontext* inContext, GLint inCode)
{
__GLCmaster* This = NULL;
LOGFONT lfont;
__GLCdata data = {NULL, NULL, NULL, NULL, 0};
HDC dc = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
if (FAILED(dc)) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
This = (__GLCmaster*)__glcMalloc(sizeof(__GLCmaster));
if (!This) {
__glcRaiseError(GLC_RESOURCE_ERROR);
DeleteDC(dc);
return NULL;
}
data.master = This;
data.index = inCode;
/* Enumerates all fonts in all character sets */
lfont.lfCharSet = DEFAULT_CHARSET;
lfont.lfFaceName[0] = '\0';
if (EnumFontFamiliesEx(dc, &lfont, (FONTENUMPROC)__glcEnumMasterMatchCode,
(LPARAM)&data, 0)) {
__glcFree(This);
This = NULL;
data.master = NULL;
}
DeleteDC(dc);
return data.master;
}
GLint __glcMasterGetID(__GLCmaster* This, __GLCcontext* inContext)
{
GLCchar32 hashValue = GLC_MASTER_HASH_VALUE(This);
GLint i = 0;
GLCchar32* hashTable = (GLCchar32*)GLC_ARRAY_DATA(inContext->masterHashTable);
for (i = 0; i < GLC_ARRAY_LENGTH(inContext->masterHashTable); i++) {
if (hashValue == hashTable[i])
break;
}
assert(i < GLC_ARRAY_LENGTH(inContext->masterHashTable));
return i;
}

View File

@ -7,6 +7,7 @@ endif
SUBDIRS = \
win32 \
3rdparty/miniupnpc \
3rdparty/quesoglc \
lib/framework \
lib/exceptionhandler \
lib/script \

View File

@ -429,8 +429,20 @@ AC_CHECK_LIB(GLU, main,
[${OPENGL_LIBS} -lm]), [${OPENGL_LIBS} -lm])
AC_SUBST([OPENGL_LIBS], [${OPENGL_LIBS}])
# Look for OpenGLC
PKG_CHECK_MODULES([OPENGLC], [quesoglc >= 0.7.2])
# OpenGLC stuff
ACX_PTHREAD
CC="$PTHREAD_CC"
AX_TLS
PKG_CHECK_MODULES([FRIBIDI], [fribidi])
PKG_CHECK_MODULES([FREETYPE], [freetype2])
AC_CHECK_LIB(freetype, FTC_Manager_New,
AC_DEFINE([HAVE_FT_CACHE], [1],
[Define if FreeType supports the caching routines]))
PKG_CHECK_MODULES([FONTCONFIG], [fontconfig])
OPENGLC_LIBS="${FRIBIDI_LIBS} ${FREETYPE_LIBS} ${FONTCONFIG_LIBS} ${PTHREAD_LIBS} ${OPENGL_LIBS} ${GLEW_LIBS}"
AC_SUBST([OPENGLC_LIBS], [${OPENGLC_LIBS}])
# When (cross-)compiling for Windows (MinGW) we need to link in BFD for the Dr.
# MinGW derived exception handler.
@ -467,6 +479,7 @@ AC_CONFIG_FILES([Makefile
win32/Makefile
tests/Makefile
3rdparty/miniupnpc/Makefile
3rdparty/quesoglc/Makefile
lib/framework/Makefile
lib/exceptionhandler/Makefile
lib/gamelib/Makefile

239
m4/acx_pthread.m4 Normal file
View File

@ -0,0 +1,239 @@
dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
dnl
dnl This macro figures out how to build C programs using POSIX
dnl threads. It sets the PTHREAD_LIBS output variable to the threads
dnl library and linker flags, and the PTHREAD_CFLAGS output variable
dnl to any special C compiler flags that are needed. (The user can also
dnl force certain compiler flags/libs to be tested by setting these
dnl environment variables.)
dnl
dnl Also sets PTHREAD_CC to any special C compiler that is needed for
dnl multi-threaded programs (defaults to the value of CC otherwise).
dnl (This is necessary on AIX to use the special cc_r compiler alias.)
dnl
dnl NOTE: You are assumed to not only compile your program with these
dnl flags, but also link it with them as well. e.g. you should link
dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
dnl
dnl If you are only building threads programs, you may wish to
dnl use these variables in your default LIBS, CFLAGS, and CC:
dnl
dnl LIBS="$PTHREAD_LIBS $LIBS"
dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
dnl CC="$PTHREAD_CC"
dnl
dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute
dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE
dnl to that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
dnl
dnl ACTION-IF-FOUND is a list of shell commands to run if a threads
dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands
dnl to run it if it is not found. If ACTION-IF-FOUND is not specified,
dnl the default action will define HAVE_PTHREAD.
dnl
dnl Please let the authors know if this macro fails on any platform,
dnl or if you have any other suggestions or comments. This macro was
dnl based on work by SGJ on autoconf scripts for FFTW (www.fftw.org)
dnl (with help from M. Frigo), as well as ac_pthread and hb_pthread
dnl macros posted by AFC to the autoconf macro repository. We are also
dnl grateful for the helpful feedback of numerous users.
dnl
dnl @version $Id$
dnl @author Steven G. Johnson <stevenj@alum.mit.edu> and Alejandro Forero Cuervo <bachue@bachue.com>
AC_DEFUN([ACX_PTHREAD], [
AC_REQUIRE([AC_CANONICAL_HOST])
AC_LANG_SAVE
AC_LANG_C
acx_pthread_ok=no
# We used to check for pthread.h first, but this fails if pthread.h
# requires special compiler flags (e.g. on True64 or Sequent).
# It gets checked for in the link test anyway.
# First of all, check if the user has set any of the PTHREAD_LIBS,
# etcetera environment variables, and if threads linking works using
# them:
if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes)
AC_MSG_RESULT($acx_pthread_ok)
if test x"$acx_pthread_ok" = xno; then
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
fi
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
fi
# We must check for the threads library under a number of different
# names; the ordering is very important because some systems
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
# libraries is broken (non-POSIX).
# Create a list of thread flags to try. Items starting with a "-" are
# C compiler flags, and other items are library names, except for "none"
# which indicates that we try without any flags at all, and "pthread-config"
# which is a program returning the flags for the Pth emulation library.
acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
# The ordering *is* (sometimes) important. Some notes on the
# individual items follow:
# pthreads: AIX (must check this before -lpthread)
# none: in case threads are in libc; should be tried before -Kthread and
# other compiler flags to prevent continual compiler warnings
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
# -pthreads: Solaris/gcc
# -mthreads: Mingw32/gcc, Lynx/gcc
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
# doesn't hurt to check since this sometimes defines pthreads too;
# also defines -D_REENTRANT)
# pthread: Linux, etcetera
# --thread-safe: KAI C++
# pthread-config: use pthread-config program (for GNU Pth library)
case "${host_cpu}-${host_os}" in
*solaris*)
# On Solaris (at least, for some versions), libc contains stubbed
# (non-functional) versions of the pthreads routines, so link-based
# tests will erroneously succeed. (We need to link with -pthread or
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
# a function called by this macro, so we could check for that, but
# who knows whether they'll stub that too in a future libc.) So,
# we'll just look for -pthreads and -lpthread first:
acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags"
;;
esac
if test x"$acx_pthread_ok" = xno; then
for flag in $acx_pthread_flags; do
case $flag in
none)
AC_MSG_CHECKING([whether pthreads work without any flags])
;;
-*)
AC_MSG_CHECKING([whether pthreads work with $flag])
PTHREAD_CFLAGS="$flag"
;;
pthread-config)
AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no)
if test x"$acx_pthread_config" = xno; then continue; fi
PTHREAD_CFLAGS="`pthread-config --cflags`"
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
;;
*)
AC_MSG_CHECKING([for the pthreads library -l$flag])
PTHREAD_LIBS="-l$flag"
;;
esac
save_LIBS="$LIBS"
save_CFLAGS="$CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# Check for various functions. We must include pthread.h,
# since some functions may be macros. (On the Sequent, we
# need a special flag -Kthread to make this header compile.)
# We check for pthread_join because it is in -lpthread on IRIX
# while pthread_create is in libc. We check for pthread_attr_init
# due to DEC craziness with -lpthreads. We check for
# pthread_cleanup_push because it is one of the few pthread
# functions on Solaris that doesn't have a non-functional libc stub.
# We try pthread_create on general principles.
AC_TRY_LINK([#include <pthread.h>],
[pthread_t th; pthread_join(th, 0);
pthread_attr_init(0); pthread_cleanup_push(0, 0);
pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
[acx_pthread_ok=yes])
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
AC_MSG_RESULT($acx_pthread_ok)
if test "x$acx_pthread_ok" = xyes; then
break;
fi
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
done
fi
# Various other checks:
if test "x$acx_pthread_ok" = xyes; then
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# Detect AIX lossage: threads are created detached by default
# and the JOINABLE attribute has a nonstandard name (UNDETACHED).
AC_MSG_CHECKING([for joinable pthread attribute])
AC_TRY_LINK([#include <pthread.h>],
[int attr=PTHREAD_CREATE_JOINABLE;],
ok=PTHREAD_CREATE_JOINABLE, ok=unknown)
if test x"$ok" = xunknown; then
AC_TRY_LINK([#include <pthread.h>],
[int attr=PTHREAD_CREATE_UNDETACHED;],
ok=PTHREAD_CREATE_UNDETACHED, ok=unknown)
fi
if test x"$ok" != xPTHREAD_CREATE_JOINABLE; then
AC_DEFINE(PTHREAD_CREATE_JOINABLE, "${ok}",
[Define to the necessary symbol if this constant
uses a non-standard name on your system.])
fi
AC_MSG_RESULT(${ok})
if test x"$ok" = xunknown; then
AC_MSG_WARN([we do not know how to create joinable pthreads])
fi
AC_MSG_CHECKING([if more special flags are required for pthreads])
flag=no
case "${host_cpu}-${host_os}" in
*-aix* | *-freebsd*) flag="-D_THREAD_SAFE";;
*solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
esac
AC_MSG_RESULT(${flag})
if test "x$flag" != xno; then
PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
fi
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
# More AIX lossage: must compile with cc_r
AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC})
else
PTHREAD_CC="$CC"
fi
AC_SUBST(PTHREAD_LIBS)
AC_SUBST(PTHREAD_CFLAGS)
AC_SUBST(PTHREAD_CC)
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
if test x"$acx_pthread_ok" = xyes; then
ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
:
else
acx_pthread_ok=no
$2
fi
AC_LANG_RESTORE
])dnl ACX_PTHREAD

76
m4/ax_tls.m4 Normal file
View File

@ -0,0 +1,76 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_tls.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_TLS([action-if-found], [action-if-not-found])
#
# DESCRIPTION
#
# Provides a test for the compiler support of thread local storage (TLS)
# extensions. Defines TLS if it is found. Currently knows about GCC/ICC
# and MSVC. I think SunPro uses the same as GCC, and Borland apparently
# supports either.
#
# LICENSE
#
# Copyright (c) 2008 Alan Woodland <ajw05@aber.ac.uk>
# Copyright (c) 2010 Diego Elio Petteno` <flameeyes@gmail.com>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program 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 General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 10
AC_DEFUN([AX_TLS], [
AC_MSG_CHECKING(for thread local storage (TLS) class)
AC_CACHE_VAL(ac_cv_tls, [
ax_tls_keywords="__thread __declspec(thread) none"
for ax_tls_keyword in $ax_tls_keywords; do
AS_CASE([$ax_tls_keyword],
[none], [ac_cv_tls=none ; break],
[AC_TRY_COMPILE(
[#include <stdlib.h>
static void
foo(void) {
static ] $ax_tls_keyword [ int bar;
exit(1);
}],
[],
[ac_cv_tls=$ax_tls_keyword ; break],
ac_cv_tls=none
)])
done
])
AC_MSG_RESULT($ac_cv_tls)
AS_IF([test "$ac_cv_tls" != "none"],
AC_DEFINE_UNQUOTED([TLS], $ac_cv_tls, [If the compiler supports a TLS storage class define it to that here])
m4_ifnblank([$1], [$1]),
m4_ifnblank([$2], [$2])
)
])

View File

@ -273,7 +273,8 @@ warzone2100_LIBS = \
$(top_builddir)/lib/gamelib/libgamelib.a \
$(top_builddir)/lib/framework/libframework.a \
$(top_builddir)/lib/exceptionhandler/libexceptionhandler.a \
$(top_builddir)/3rdparty/miniupnpc/libminiupnpc.a
$(top_builddir)/3rdparty/miniupnpc/libminiupnpc.a \
$(top_builddir)/3rdparty/quesoglc/libquesoglc.a
if BACKEND_QT
warzone2100_LIBS += $(top_builddir)/lib/qtgame/libqtgame.a