diff options
author | Jinghua Luo <sunmoon1997@gmail.com> | 2007-01-25 14:10:30 +0800 |
---|---|---|
committer | Jinghua Luo <sunmoon1997@gmail.com> | 2007-01-25 14:10:30 +0800 |
commit | 90f450f394f827fd8c9bcaae2f3007acc287cff7 (patch) | |
tree | f3d21c6734da9dceab85bb5f9094adc85144589a | |
parent | 0421c839313afd7ee62fcfb9404fdcfbd9a915be (diff) |
pref: convert all float point to fixed point.
-rw-r--r-- | src/sdl-font.c | 185 | ||||
-rw-r--r-- | src/sdl-freetype-utils.c | 124 | ||||
-rw-r--r-- | src/sdl-freetype-utils.h | 31 | ||||
-rw-r--r-- | src/sdl-freetype.h | 47 |
4 files changed, 338 insertions, 49 deletions
diff --git a/src/sdl-font.c b/src/sdl-font.c index 27af278..7525325 100644 --- a/src/sdl-font.c +++ b/src/sdl-font.c @@ -56,6 +56,8 @@ #define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0)) #define DOUBLE_FROM_16_16(t) ((double)(t) / 65536.0) +#define FIXED_FROM_26_6(t) sdl_freetype_fixed_from_26_6(t) + #ifndef SDL_FREETYPE_GLYPHS_CACHE_SIZE #define SDL_FREETYPE_GLYPHS_CACHE_SIZE 256 #endif @@ -65,13 +67,13 @@ #define GLYPH_INFO_SURFACE (1 << 1) typedef struct { - double x1, x2, y1, y2; + sdl_freetype_fixed_t x1, x2, y1, y2; } sdl_freetype_bbox_t; typedef struct { sdl_freetype_cache_entry_t base; sdl_freetype_font_t * font; - sdl_freetype_text_extents_t metrics; + sdl_freetype_text_fixed_extents_t metrics; sdl_freetype_bbox_t bbox; FT_Bitmap bitmap; int x_offset; @@ -87,7 +89,7 @@ struct _sdl_freetype_font { sdl_freetype_font_face_t * face; sdl_freetype_font_options_t options; sdl_freetype_cache_t * glyphs; - sdl_freetype_font_extents_t metrics; + sdl_freetype_font_fixed_extents_t metrics; sdl_freetype_glyph_render_t * render; FT_Stroker stroker; FT_Matrix xform; @@ -284,7 +286,7 @@ sdl_freetype_font_create_full (const char * file, double size, int index = 0; FT_Face face; double scale; - sdl_freetype_font_extents_t * metrics; + sdl_freetype_font_fixed_extents_t * metrics; if (mask & SDL_FONT_INDEX_MASK) index = desc->index; @@ -323,15 +325,20 @@ sdl_freetype_font_create_full (const char * file, double size, metrics = &font->metrics; scale = face->units_per_EM; - metrics->ascent = face->ascender * font->size / scale; - metrics->descent = -face->descender * font->size / scale; - metrics->height = face->height * font->size / scale; + metrics->ascent = + sdl_freetype_fixed_from_double(face->ascender * font->size / scale); + metrics->descent = + sdl_freetype_fixed_from_double(-face->descender * font->size / scale); + metrics->height = + sdl_freetype_fixed_from_double(face->height * font->size / scale); if (!font->options.vertical_layout) { - metrics->max_x_advance = face->max_advance_width * font->size / scale; + metrics->max_x_advance = + sdl_freetype_fixed_from_double(face->max_advance_width * font->size / scale); metrics->max_y_advance = 0; } else { metrics->max_x_advance = 0; - metrics->max_y_advance = face->max_advance_height * font->size / scale; + metrics->max_y_advance = + sdl_freetype_fixed_from_double(face->max_advance_height * font->size / scale); } if (mask & SDL_FONT_STROKE_MASK && desc->stroke) { @@ -801,21 +808,21 @@ sdl_freetype_font_glyph_info_load (sdl_freetype_font_t * font, if (what & GLYPH_INFO_METRICS) { FT_Glyph_Metrics * metrics = &glyph->metrics; - glyph_info->metrics.width = DOUBLE_FROM_26_6 (metrics->width); - glyph_info->metrics.height = DOUBLE_FROM_26_6 (metrics->height); + glyph_info->metrics.width = FIXED_FROM_26_6 (metrics->width); + glyph_info->metrics.height = FIXED_FROM_26_6 (metrics->height); if (!font->options.vertical_layout) { - glyph_info->metrics.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX); - glyph_info->metrics.y_bearing = DOUBLE_FROM_26_6 (-metrics->horiBearingY); + glyph_info->metrics.x_bearing = FIXED_FROM_26_6 (metrics->horiBearingX); + glyph_info->metrics.y_bearing = FIXED_FROM_26_6 (-metrics->horiBearingY); - glyph_info->metrics.x_advance = DOUBLE_FROM_26_6 (metrics->horiAdvance); + glyph_info->metrics.x_advance = FIXED_FROM_26_6 (metrics->horiAdvance); glyph_info->metrics.y_advance = 0; } else { - glyph_info->metrics.x_bearing = DOUBLE_FROM_26_6 (metrics->vertBearingX); - glyph_info->metrics.y_bearing = DOUBLE_FROM_26_6 (metrics->vertBearingY); + glyph_info->metrics.x_bearing = FIXED_FROM_26_6 (metrics->vertBearingX); + glyph_info->metrics.y_bearing = FIXED_FROM_26_6 (metrics->vertBearingY); glyph_info->metrics.x_advance = 0; - glyph_info->metrics.y_advance = DOUBLE_FROM_26_6 (metrics->vertAdvance); + glyph_info->metrics.y_advance = FIXED_FROM_26_6 (metrics->vertAdvance); } if (glyph_info->metrics.width && glyph_info->metrics.height) { @@ -948,7 +955,7 @@ sdl_freetype_font_glyph_info_lookup (sdl_freetype_font_t * font, static int sdl_freetype_font_glyph_metrics_and_bbox (sdl_freetype_font_t * font, FT_UInt index, - sdl_freetype_text_extents_t * metrics, + sdl_freetype_text_fixed_extents_t * metrics, sdl_freetype_bbox_t * bbox) { sdl_freetype_glyph_info_t * info; @@ -962,6 +969,19 @@ sdl_freetype_font_glyph_metrics_and_bbox (sdl_freetype_font_t * font, FT_UInt in } int +sdl_freetype_font_glyph_fixed_metrics (sdl_freetype_font_t * font, FT_UInt index, + sdl_freetype_text_fixed_extents_t * metrics) +{ + sdl_freetype_glyph_info_t * info; + + info = sdl_freetype_font_glyph_info_lookup (font, index, GLYPH_INFO_METRICS); + if (!info) + return -1; + *metrics = info->metrics; + return 0; +} + +int sdl_freetype_font_glyph_metrics (sdl_freetype_font_t * font, FT_UInt index, sdl_freetype_text_extents_t * metrics) { @@ -970,7 +990,7 @@ sdl_freetype_font_glyph_metrics (sdl_freetype_font_t * font, FT_UInt index, info = sdl_freetype_font_glyph_info_lookup (font, index, GLYPH_INFO_METRICS); if (!info) return -1; - *metrics = info->metrics; + sdl_freetype_text_extents_from_fixed(metrics, &info->metrics); return 0; } @@ -1098,13 +1118,26 @@ sdl_freetype_font_glyph_thaw (sdl_freetype_font_t * font) } int -sdl_freetype_font_extents (sdl_freetype_font_t * font, - sdl_freetype_font_extents_t * metrics) +sdl_freetype_font_fixed_extents (sdl_freetype_font_t * font, + sdl_freetype_font_fixed_extents_t * metrics) { *metrics = font->metrics; return 0; } +int +sdl_freetype_font_extents (sdl_freetype_font_t * font, + sdl_freetype_font_extents_t * metrics) +{ + metrics->ascent = sdl_freetype_fixed_to_double(font->metrics.ascent); + metrics->descent = sdl_freetype_fixed_to_double(font->metrics.descent); + metrics->height = sdl_freetype_fixed_to_double(font->metrics.height); + metrics->max_x_advance = sdl_freetype_fixed_to_double(font->metrics.max_x_advance); + metrics->max_y_advance = sdl_freetype_fixed_to_double(font->metrics.max_y_advance); + + return 0; +} + void sdl_freetype_font_destroy (sdl_freetype_font_t * font) { @@ -1203,17 +1236,17 @@ sdl_freetype_font_show_glyphs (sdl_freetype_font_t * font, } int -sdl_freetype_font_glyphs_extents (sdl_freetype_font_t * font, - sdl_freetype_text_extents_t * extents, - const sdl_freetype_glyph_t * glyphs, - int num) +sdl_freetype_font_glyphs_fixed_extents (sdl_freetype_font_t * font, + sdl_freetype_text_fixed_extents_t * extents, + const sdl_freetype_glyph_t * glyphs, + int num) { - sdl_freetype_text_extents_t metrics; + sdl_freetype_text_fixed_extents_t metrics; + sdl_freetype_bbox_t bbox; int i, firsttime = 1; int min_x = 0, max_x = 0; int min_y = 0, max_y = 0; - double x_advance = 0, y_advance = 0; - sdl_freetype_bbox_t bbox; + sdl_freetype_fixed_t x_advance = 0, y_advance = 0; sdl_freetype_font_glyph_freeze (font); @@ -1228,13 +1261,13 @@ sdl_freetype_font_glyphs_extents (sdl_freetype_font_t * font, /* glyph images are snapped to pixel locations */ - x = sdl_freetype_lround (glyphs[i].x); - y = sdl_freetype_lround (glyphs[i].y); + x = sdl_freetype_fixed_round (glyphs[i].x); + y = sdl_freetype_fixed_round (glyphs[i].y); - left = x + floor (bbox.x1); - top = y + floor (bbox.y1); - right = x + ceil (bbox.x2); - bottom = y + ceil (bbox.y2); + left = x + sdl_freetype_fixed_floor (bbox.x1); + top = y + sdl_freetype_fixed_floor (bbox.y1); + right = x + sdl_freetype_fixed_ceil (bbox.x2); + bottom = y + sdl_freetype_fixed_ceil (bbox.y2); x_advance += metrics.x_advance; y_advance += metrics.y_advance; @@ -1257,10 +1290,10 @@ sdl_freetype_font_glyphs_extents (sdl_freetype_font_t * font, } } - extents->x_bearing = min_x; - extents->y_bearing = min_y; - extents->width = max_x - min_x; - extents->height = max_y - min_y; + extents->x_bearing = sdl_freetype_fixed_from_integer(min_x); + extents->y_bearing = sdl_freetype_fixed_from_integer(min_y); + extents->width = sdl_freetype_fixed_from_integer(max_x - min_x); + extents->height = sdl_freetype_fixed_from_integer(max_y - min_y); extents->x_advance = x_advance; extents->y_advance = y_advance; @@ -1270,15 +1303,32 @@ sdl_freetype_font_glyphs_extents (sdl_freetype_font_t * font, } int -sdl_freetype_font_text_extents (sdl_freetype_font_t * font, - sdl_freetype_text_extents_t * extents, - const FT_Int32 * ucs4, int num) +sdl_freetype_font_glyphs_extents (sdl_freetype_font_t * font, + sdl_freetype_text_extents_t * extents, + const sdl_freetype_glyph_t * glyphs, + int num) +{ + sdl_freetype_text_fixed_extents_t fixed; + int ret; + + ret = sdl_freetype_font_glyphs_fixed_extents(font, &fixed, glyphs, num); + if (ret < 0) + return ret; + + sdl_freetype_text_extents_from_fixed(extents, &fixed); + return 0; +} + +int +sdl_freetype_font_text_fixed_extents (sdl_freetype_font_t * font, + sdl_freetype_text_fixed_extents_t * extents, + const FT_Int32 * ucs4, int num) { sdl_freetype_glyph_t * glyphs, lglyphs[LOCAL_BUFSZ]; - sdl_freetype_text_extents_t metrics; + sdl_freetype_text_fixed_extents_t metrics; + sdl_freetype_fixed_t x_offset, y_offset, x_advance, y_advance; FT_Face face; int ret, i; - double x_offset, y_offset, x_advance, y_advance; face = sdl_freetype_font_lock_face (font); if (!face) @@ -1305,8 +1355,8 @@ sdl_freetype_font_text_extents (sdl_freetype_font_t * font, y_offset += y_advance; glyphs[i].x = x_offset; glyphs[i].y = y_offset; - if (sdl_freetype_font_glyph_metrics (font, glyphs[i].index, - &metrics) < 0) { + if (sdl_freetype_font_glyph_fixed_metrics (font, glyphs[i].index, + &metrics) < 0) { x_advance = y_advance = 0; } else { x_advance = metrics.x_advance; @@ -1314,7 +1364,7 @@ sdl_freetype_font_text_extents (sdl_freetype_font_t * font, } } - ret = sdl_freetype_font_glyphs_extents (font, extents, glyphs, num); + ret = sdl_freetype_font_glyphs_fixed_extents (font, extents, glyphs, num); if (glyphs != lglyphs) free (glyphs); @@ -1328,6 +1378,28 @@ sdl_freetype_font_text_extents (sdl_freetype_font_t * font, } int +sdl_freetype_font_text_extents (sdl_freetype_font_t * font, + sdl_freetype_text_extents_t * extents, + const FT_Int32 * ucs4, int num) +{ + sdl_freetype_text_fixed_extents_t fextents; + int ret; + + ret = sdl_freetype_font_text_fixed_extents (font, &fextents, ucs4, num); + if (ret < 0) + return ret; + + extents->x_bearing = sdl_freetype_fixed_to_double(fextents.x_bearing); + extents->y_bearing = sdl_freetype_fixed_to_double(fextents.y_bearing); + extents->x_advance = sdl_freetype_fixed_to_double(fextents.x_advance); + extents->y_advance = sdl_freetype_fixed_to_double(fextents.y_advance); + extents->width = sdl_freetype_fixed_to_double(fextents.width); + extents->height = sdl_freetype_fixed_to_double(fextents.height); + + return 0; +} + +int sdl_freetype_font_show_text (sdl_freetype_font_t * font, void * dst, unsigned char r, @@ -1340,9 +1412,9 @@ sdl_freetype_font_show_text (sdl_freetype_font_t * font, { sdl_freetype_glyph_t * glyphs, lglyphs[LOCAL_BUFSZ]; sdl_freetype_text_extents_t metrics; + sdl_freetype_fixed_t x_offset, y_offset, x_advance, y_advance; FT_Face face; int ret, i; - double x_offset, y_offset, x_advance, y_advance; if (!a) return 0; @@ -1439,3 +1511,22 @@ sdl_freetype_font_utf8_extents (sdl_freetype_font_t * font, return ret; } + +int +sdl_freetype_font_utf8_fixed_extents (sdl_freetype_font_t * font, + sdl_freetype_text_fixed_extents_t * extents, + const char * utf8, int len) +{ + FT_Int32 * ucs4; + int ulen, ret; + + ulen = sdl_freetype_utf8_to_ucs4 (utf8, len, &ucs4); + if (ulen < 0) + return -1; + + ret = sdl_freetype_font_text_fixed_extents (font, extents, ucs4, ulen); + + free (ucs4); + + return ret; +} diff --git a/src/sdl-freetype-utils.c b/src/sdl-freetype-utils.c index 7c88d09..9535f0c 100644 --- a/src/sdl-freetype-utils.c +++ b/src/sdl-freetype-utils.c @@ -63,6 +63,7 @@ #error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, etc.) #endif +#include "sdl-freetype.h" #include "sdl-freetype-utils.h" static int @@ -382,3 +383,126 @@ sdl_freetype_lround (double d) #undef LSW } +sdl_freetype_fixed_t +sdl_freetype_fixed_from_int (int i) +{ + return i << 16; +} + +/* This is the "magic number" approach to converting a double into fixed + * point as described here: + * + * http://www.stereopsis.com/sree/fpu2006.html (an overview) + * http://www.d6.com/users/checker/pdfs/gdmfp.pdf (in detail) + * + * The basic idea is to add a large enough number to the double that the + * literal floating point is moved up to the extent that it forces the + * double's value to be shifted down to the bottom of the mantissa (to make + * room for the large number being added in). Since the mantissa is, at a + * given moment in time, a fixed point integer itself, one can convert a + * float to various fixed point representations by moving around the point + * of a floating point number through arithmetic operations. This behavior + * is reliable on most modern platforms as it is mandated by the IEEE-754 + * standard for floating point arithmetic. + * + * For our purposes, a "magic number" must be carefully selected that is + * both large enough to produce the desired point-shifting effect, and also + * has no lower bits in its representation that would interfere with our + * value at the bottom of the mantissa. The magic number is calculated as + * follows: + * + * (2 ^ (MANTISSA_SIZE - FRACTIONAL_SIZE)) * 1.5 + * + * where in our case: + * - MANTISSA_SIZE for 64-bit doubles is 52 + * - FRACTIONAL_SIZE for 16.16 fixed point is 16 + * + * Although this approach provides a very large speedup of this function + * on a wide-array of systems, it does come with two caveats: + * + * 1) It uses banker's rounding as opposed to arithmetic rounding. + * 2) It doesn't function properly if the FPU is in single-precision + * mode. + */ +#define SDL_FREETYPE_MAGIC_NUMBER_FIXED_16_16 (103079215104.0) +sdl_freetype_fixed_t +sdl_freetype_fixed_from_double (double d) +{ + union { + double d; + int32_t i[2]; + } u; + + u.d = d + SDL_FREETYPE_MAGIC_NUMBER_FIXED_16_16; +#ifdef FLOAT_WORDS_BIGENDIAN + return u.i[1]; +#else + return u.i[0]; +#endif +} + +sdl_freetype_fixed_t +sdl_freetype_fixed_from_26_6 (FT_Int32 i) +{ + return i << 10; +} + +sdl_freetype_fixed_t +sdl_freetype_fixed_from_integer (int f) +{ + return f << 16; +} + +double +sdl_freetype_fixed_to_double (sdl_freetype_fixed_t f) +{ + return ((double) f) / 65536.0; +} + +int +sdl_freetype_fixed_is_integer (sdl_freetype_fixed_t f) +{ + return (f & 0xFFFF) == 0; +} + +int +sdl_freetype_fixed_integer (sdl_freetype_fixed_t f) +{ + return f >> 16; +} + +int +sdl_freetype_fixed_round (sdl_freetype_fixed_t f) +{ + return (f + 32768)>> 16; +} + +int +sdl_freetype_fixed_floor (sdl_freetype_fixed_t f) +{ + if (f >= 0) + return f >> 16; + else + return -((-f - 1) >> 16) - 1; +} + +int +sdl_freetype_fixed_ceil (sdl_freetype_fixed_t f) +{ + if (f > 0) + return ((f - 1)>>16) + 1; + else + return - (-f >> 16); +} + +void +sdl_freetype_text_extents_from_fixed (sdl_freetype_text_extents_t * extents, + sdl_freetype_text_fixed_extents_t * fixed) +{ + extents->x_bearing = sdl_freetype_fixed_to_double(fixed->x_bearing); + extents->y_bearing = sdl_freetype_fixed_to_double(fixed->y_bearing); + extents->x_advance = sdl_freetype_fixed_to_double(fixed->x_advance); + extents->y_advance = sdl_freetype_fixed_to_double(fixed->y_advance); + extents->width = sdl_freetype_fixed_to_double(fixed->width); + extents->height = sdl_freetype_fixed_to_double(fixed->height); +} diff --git a/src/sdl-freetype-utils.h b/src/sdl-freetype-utils.h index f73c566..5945cd4 100644 --- a/src/sdl-freetype-utils.h +++ b/src/sdl-freetype-utils.h @@ -43,4 +43,35 @@ sdl_freetype_utf8_to_ucs4 (const char * utf8, int len, FT_Int32 ** retucs4); int sdl_freetype_lround(double d); +sdl_freetype_fixed_t +sdl_freetype_fixed_from_double(double d); + +sdl_freetype_fixed_t +sdl_freetype_fixed_from_26_6 (FT_Int32 i); + +sdl_freetype_fixed_t +sdl_freetype_fixed_from_integer (int f); + +double +sdl_freetype_fixed_to_double (sdl_freetype_fixed_t f); + +int +sdl_freetype_fixed_is_integer (sdl_freetype_fixed_t f); + +int +sdl_freetype_fixed_integer (sdl_freetype_fixed_t f); + +int +sdl_freetype_fixed_round (sdl_freetype_fixed_t f); + +int +sdl_freetype_fixed_floor (sdl_freetype_fixed_t f); + +int +sdl_freetype_fixed_ceil (sdl_freetype_fixed_t f); + +void +sdl_freetype_text_extents_from_fixed (sdl_freetype_text_extents_t * extents, + sdl_freetype_text_fixed_extents_t * fixed); + #endif diff --git a/src/sdl-freetype.h b/src/sdl-freetype.h index 2f0385a..28b767a 100644 --- a/src/sdl-freetype.h +++ b/src/sdl-freetype.h @@ -41,10 +41,12 @@ extern "C" { struct _sdl_freetype_font; typedef struct _sdl_freetype_font sdl_freetype_font_t; +typedef FT_Int32 sdl_freetype_fixed_t; + typedef struct { FT_UInt index; - double x; - double y; + sdl_freetype_fixed_t x; + sdl_freetype_fixed_t y; } sdl_freetype_glyph_t; typedef struct { @@ -57,6 +59,15 @@ typedef struct { } sdl_freetype_text_extents_t; typedef struct { + sdl_freetype_fixed_t x_bearing; + sdl_freetype_fixed_t y_bearing; + sdl_freetype_fixed_t width; + sdl_freetype_fixed_t height; + sdl_freetype_fixed_t x_advance; + sdl_freetype_fixed_t y_advance; +} sdl_freetype_text_fixed_extents_t; + +typedef struct { double ascent; double descent; double height; @@ -64,6 +75,14 @@ typedef struct { double max_y_advance; } sdl_freetype_font_extents_t; +typedef struct { + sdl_freetype_fixed_t ascent; + sdl_freetype_fixed_t descent; + sdl_freetype_fixed_t height; + sdl_freetype_fixed_t max_x_advance; + sdl_freetype_fixed_t max_y_advance; +} sdl_freetype_font_fixed_extents_t; + typedef enum { SDL_FT_ANTIALIAS_DEFAULT, SDL_FT_ANTIALIAS_NONE, @@ -210,6 +229,10 @@ sdl_freetype_font_glyph_metrics (sdl_freetype_font_t * font, FT_UInt index, sdl_freetype_text_extents_t * metrics); int +sdl_freetype_font_glyph_fixed_metrics (sdl_freetype_font_t * font, FT_UInt index, + sdl_freetype_text_fixed_extents_t * metrics); + +int sdl_freetype_font_glyph_surface (sdl_freetype_font_t * font, FT_UInt index, FT_Bitmap ** surface, int * x_offset, int * y_offset, void ** data); @@ -232,6 +255,10 @@ sdl_freetype_font_extents (sdl_freetype_font_t * font, sdl_freetype_font_extents_t * extents); int +sdl_freetype_font_fixed_extents (sdl_freetype_font_t * font, + sdl_freetype_font_fixed_extents_t * extents); + +int sdl_freetype_font_show_text (sdl_freetype_font_t * font, void * dst, unsigned char r, unsigned char g, unsigned char b, unsigned char a, int x, int y, const FT_Int32 * ucs4, @@ -244,11 +271,22 @@ sdl_freetype_font_glyphs_extents (sdl_freetype_font_t * font, int num_glyphs); int +sdl_freetype_font_glyphs_fixed_extents (sdl_freetype_font_t * font, + sdl_freetype_text_fixed_extents_t * extents, + const sdl_freetype_glyph_t * glyphs, + int num_glyphs); + +int sdl_freetype_font_text_extents (sdl_freetype_font_t * font, sdl_freetype_text_extents_t * extents, const FT_Int32 * ucs4, int len); int +sdl_freetype_font_text_fixed_extents (sdl_freetype_font_t * font, + sdl_freetype_text_fixed_extents_t * extents, + const FT_Int32 * ucs4, int len); + +int sdl_freetype_font_show_glyphs (sdl_freetype_font_t * font, void * dst, unsigned char r, unsigned char g, unsigned char b, unsigned char a, int x, int y, @@ -269,6 +307,11 @@ sdl_freetype_font_utf8_extents (sdl_freetype_font_t * font, sdl_freetype_text_extents_t * extents, const char * utf8, int len); +int +sdl_freetype_font_utf8_fixed_extents (sdl_freetype_font_t * font, + sdl_freetype_text_fixed_extents_t * extents, + const char * utf8, int len); + #ifdef __cplusplus } #endif |