Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
42 KB
Referenced Files
None
Subscribers
None
This document is not UTF8. It was detected as JIS and converted to UTF8 for display.
diff --git a/src/sge_tt_text.cpp b/src/sge_tt_text.cpp
index 5ce1274..f6336b3 100644
--- a/src/sge_tt_text.cpp
+++ b/src/sge_tt_text.cpp
@@ -1,1469 +1,1470 @@
/*
* SDL Graphics Extension
* Text/TrueType font functions
*
* Started 990815
*
* License: LGPL v2+ (see the file LICENSE)
* (c)1999-2001 Anders Lindstr?m
*
* Uses the excellent FreeType 2 library, available at:
* http://www.freetype.org/
*/
/*********************************************************************
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
*********************************************************************/
/*
* Most of this code is taken from the SDL ttf lib by Sam Lantinga
* <slouken@devolution.com>
*/
#include "SDL.h"
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <string.h>
#include <stdarg.h>
#include <math.h>
#include "sge_surface.h"
#include "sge_primitives.h"
#include "sge_tt_text.h"
#ifndef _SGE_NOTTF
+#include <ft2build.h>
#include <freetype/freetype.h>
#include <freetype/ftoutln.h>
#include <freetype/ttnameid.h>
/* The structure used to hold glyph information (cached) */
struct glyph {
int stored;
FT_UInt index;
//FT_Bitmap bitmap;
FT_Bitmap pixmap;
int minx;
int maxx;
int miny;
int maxy;
int yoffset;
int advance;
Uint16 cached;
};
/* the truetype font structure */
struct _sge_TTFont{
FT_Face face;
/* Font metrics */
int height;
int ascent;
int descent;
int lineskip;
/* The font style */
Uint8 style;
/* Extra width in glyph bounds for text styles */
int glyph_overhang;
float glyph_italics;
/* Information in the font for underlining */
int underline_offset;
int underline_height;
/* For now, support Latin-1 character set caching */
glyph *current;
glyph cache[256];
glyph scratch;
};
/* Macro to convert a character to a Unicode value -- assume already Unicode */
//Should really make a proper convert algorithm someday
#define UNICODE(c) c
/* FIXME: Right now we assume the gray-scale renderer Freetype is using
supports 256 shades of gray, but we should instead key off of num_grays
in the result FT_Bitmap after the FT_Render_Glyph() call. */
#define NUM_GRAYS 256
/* Handy routines for converting from fixed point */
#define FT_FLOOR(X) ((X & -64) / 64)
#define FT_CEIL(X) (((X + 63) & -64) / 64)
#define CACHED_METRICS 0x10
#define CACHED_BITMAP 0x01
#define CACHED_PIXMAP 0x02
/* The FreeType font engine/library */
static FT_Library _sge_library;
static int _sge_TTF_initialized = 0;
Uint8 _sge_TTF_AA=1; //Rendering mode: 0-OFF, 1-AA, 2-Alpha
/**********************************************************************************/
/** Open/misc font functions **/
/**********************************************************************************/
//==================================================================================
// Turns TTF AntiAliasing On/Off or alpha (nice but slow) (Default: On)
//==================================================================================
void sge_TTF_AAOff(void)
{
_sge_TTF_AA=0;
}
void sge_TTF_AAOn(void)
{
_sge_TTF_AA=1;
}
void sge_TTF_AA_Alpha(void)
{
_sge_TTF_AA=2;
}
//==================================================================================
// Closes the ttf engine, done by exit
//==================================================================================
void sge_TTF_Quit(void)
{
if ( _sge_TTF_initialized ) {
FT_Done_FreeType( _sge_library );
}
_sge_TTF_initialized = 0;
}
//==================================================================================
// Starts the ttf engine, must be called first
//==================================================================================
int sge_TTF_Init(void)
{
FT_Error error;
error = FT_Init_FreeType( &_sge_library );
if ( error ) {
SDL_SetError("SGE - Couldn't init FreeType engine");
return(-1);
} else {
_sge_TTF_initialized = 1;
}
atexit(sge_TTF_Quit); //dont't trust the user...
return(0);
}
//==================================================================================
// Some helper functions
//==================================================================================
void Flush_Glyph(glyph *glyph)
{
glyph->stored = 0;
glyph->index = 0;
//if( glyph->bitmap.buffer ) {
// free( glyph->bitmap.buffer );
// glyph->bitmap.buffer = 0;
//}
if( glyph->pixmap.buffer ) {
free( glyph->pixmap.buffer );
glyph->pixmap.buffer = 0;
}
glyph->cached = 0;
}
void Flush_Cache(sge_TTFont *font)
{
int i;
int size = sizeof( font->cache ) / sizeof( font->cache[0] );
for( i = 0; i < size; ++i ) {
if( font->cache[i].cached ) {
Flush_Glyph( &font->cache[i] );
}
}
if( font->scratch.cached ) {
Flush_Glyph( &font->scratch );
}
}
//==================================================================================
// Remove font from memory
//==================================================================================
void sge_TTF_CloseFont(sge_TTFont *font)
{
Flush_Cache( font );
FT_Done_Face( font->face );
free( font );
}
//==================================================================================
// Open the TT font file and returns the font with pt size
//==================================================================================
sge_TTFont *sge_TTF_OpenFont(const char *file, int ptsize)
{
sge_TTFont *font;
FT_Error error;
FT_Face face;
FT_Fixed scale;
font = (sge_TTFont *)malloc(sizeof(*font));
if ( font == NULL ) {
SDL_SetError("SGE - Out of memory");
return(NULL);
}
memset(font, 0, sizeof(*font));
/* Open the font and create ancillary data */
error = FT_New_Face( _sge_library, file, 0, &font->face );
if ( error ) {
sge_SetError("SGE - Couldn't load font file: %s",file);
free(font);
return(NULL);
}
face = font->face;
/* Make sure that our font face is scalable (global metrics) */
if ( ! FT_IS_SCALABLE(face) ) {
sge_SetError("SGE - Font face is not scalable: %s",file);
sge_TTF_CloseFont( font );
return NULL;
}
/* Set the character size and use 96 DPI */
error = FT_Set_Char_Size( font->face, 0, ptsize * 64, 96, 96 );
//error = FT_Set_Pixel_Sizes( font->face, 0, ptsize );
if( error ) {
sge_SetError("SGE - Couldn't set font size: %s",file);
sge_TTF_CloseFont( font );
return NULL;
}
/* Get the scalable font metrics for this font */
scale = face->size->metrics.y_scale;
font->ascent = FT_CEIL(FT_MulFix(face->bbox.yMax, scale));
font->descent = FT_CEIL(FT_MulFix(face->bbox.yMin, scale));
font->height = font->ascent - font->descent + /* baseline */ 1;
font->lineskip = FT_CEIL(FT_MulFix(face->height, scale));
font->underline_offset = FT_FLOOR(FT_MulFix(face->underline_position, scale));
font->underline_height = FT_FLOOR(FT_MulFix(face->underline_thickness, scale));
if ( font->underline_height < 1 ) {
font->underline_height = 1;
}
/* Set the default font style */
font->style = SGE_TTF_NORMAL;
font->glyph_overhang = face->size->metrics.y_ppem / 10;
/* x offset = cos(((90.0-12)/360)*2*M_PI), or 12 degree angle */
font->glyph_italics = 0.207f;
font->glyph_italics *= font->height;
return font;
}
//==================================================================================
// Load a glyph
//==================================================================================
FT_Error Load_Glyph(sge_TTFont *font, Uint16 ch, glyph *cached, int want )
{
FT_Face face;
FT_Error error;
FT_GlyphSlot glyph;
FT_Glyph_Metrics* metrics;
FT_Outline* outline;
//assert( font );
//assert( font->face );
face = font->face;
/* Load the glyph */
if ( ! cached->index ) {
cached->index = FT_Get_Char_Index( face, ch );
}
error = FT_Load_Glyph( face, cached->index, FT_LOAD_DEFAULT );
if( error ) {
return error;
}
/* Get our glyph shortcuts */
glyph = face->glyph;
metrics = &glyph->metrics;
outline = &glyph->outline;
/* Get the glyph metrics if desired */
if ( (want & CACHED_METRICS) && !(cached->stored & CACHED_METRICS) ) {
/* Get the bounding box */
cached->minx = FT_FLOOR(metrics->horiBearingX);
cached->maxx = cached->minx + FT_CEIL(metrics->width);
cached->maxy = FT_FLOOR(metrics->horiBearingY);
cached->miny = cached->maxy - FT_CEIL(metrics->height);
cached->yoffset = font->ascent - cached->maxy;
cached->advance = FT_CEIL(metrics->horiAdvance);
/* Adjust for bold and italic text */
if ( font->style & SGE_TTF_BOLD ) {
cached->maxx += font->glyph_overhang;
}
if ( font->style & SGE_TTF_ITALIC ) {
cached->maxx += (int)ceil(font->glyph_italics);
}
cached->stored |= CACHED_METRICS;
}
if ( ((want & CACHED_BITMAP) && !(cached->stored & CACHED_BITMAP)) ||
((want & CACHED_PIXMAP) && !(cached->stored & CACHED_PIXMAP)) ) {
//int mono = (want & CACHED_BITMAP);
int i;
FT_Bitmap* src;
FT_Bitmap* dst;
/* Handle the italic style */
if( font->style & SGE_TTF_ITALIC ) {
FT_Matrix shear;
shear.xx = 1 << 16;
shear.xy = (int) ( font->glyph_italics * ( 1 << 16 ) ) / font->height;
shear.yx = 0;
shear.yy = 1 << 16;
FT_Outline_Transform( outline, &shear );
}
/* Render the glyph */
//if ( mono ) {
// error = FT_Render_Glyph( glyph, ft_render_mode_mono );
//} else {
error = FT_Render_Glyph( glyph, ft_render_mode_normal );
//}
if( error ) {
return error;
}
/* Copy over information to cache */
src = &glyph->bitmap;
//if ( mono ) {
// dst = &cached->bitmap;
//} else {
dst = &cached->pixmap;
//}
memcpy( dst, src, sizeof( *dst ) );
//if ( mono ) {
// dst->pitch *= 8;
//}
/* Adjust for bold and italic text */
if( font->style & SGE_TTF_BOLD ) {
int bump = font->glyph_overhang;
dst->pitch += bump;
dst->width += bump;
}
if( font->style & SGE_TTF_ITALIC ) {
int bump = (int)ceil(font->glyph_italics);
dst->pitch += bump;
dst->width += bump;
}
dst->buffer = (unsigned char *)malloc( dst->pitch * dst->rows );
if( !dst->buffer ) {
return FT_Err_Out_Of_Memory;
}
memset( dst->buffer, 0, dst->pitch * dst->rows );
for( i = 0; i < src->rows; i++ ) {
int soffset = i * src->pitch;
int doffset = i * dst->pitch;
/*if ( mono ) {
unsigned char *srcp = src->buffer + soffset;
unsigned char *dstp = dst->buffer + doffset;
int j;
for ( j = 0; j < src->width; j += 8 ) {
unsigned char ch = *srcp++;
*dstp++ = (ch&0x80) >> 7;
ch <<= 1;
*dstp++ = (ch&0x80) >> 7;
ch <<= 1;
*dstp++ = (ch&0x80) >> 7;
ch <<= 1;
*dstp++ = (ch&0x80) >> 7;
ch <<= 1;
*dstp++ = (ch&0x80) >> 7;
ch <<= 1;
*dstp++ = (ch&0x80) >> 7;
ch <<= 1;
*dstp++ = (ch&0x80) >> 7;
ch <<= 1;
*dstp++ = (ch&0x80) >> 7;
}
} else {*/
memcpy(dst->buffer+doffset,
src->buffer+soffset, src->pitch);
//}
}
/* Handle the bold style */
if ( font->style & SGE_TTF_BOLD ) {
int row;
int col;
int offset;
int pixel;
Uint8* pixmap;
/* The pixmap is a little hard, we have to add and clamp */
for( row = dst->rows - 1; row >= 0; --row ) {
pixmap = (Uint8*) dst->buffer + row * dst->pitch;
for( offset=1; offset <= font->glyph_overhang; ++offset ) {
for( col = dst->width - 1; col > 0; --col ) {
pixel = (pixmap[col] + pixmap[col-1]);
if( pixel > NUM_GRAYS - 1 ) {
pixel = NUM_GRAYS - 1;
}
pixmap[col] = (Uint8) pixel;
}
}
}
}
/* Mark that we rendered this format */
//if ( mono ) {
// cached->stored |= CACHED_BITMAP;
//} else {
cached->stored |= CACHED_PIXMAP;
//}
}
/* We're done, mark this glyph cached */
cached->cached = ch;
return 0;
}
//==================================================================================
// Find glyph
//==================================================================================
FT_Error Find_Glyph(sge_TTFont *font, Uint16 ch, int want)
{
int retval = 0;
if( ch < 256 ) {
font->current = &font->cache[ch];
} else {
if ( font->scratch.cached != ch ) {
Flush_Glyph( &font->scratch );
}
font->current = &font->scratch;
}
if ( (font->current->stored & want) != want ) {
retval = Load_Glyph( font, ch, font->current, want );
}
return retval;
}
//==================================================================================
// Change the size of font
//==================================================================================
int sge_TTF_SetFontSize(sge_TTFont *font, int ptsize)
{
FT_Error error;
FT_Fixed scale;
FT_Face face;
/* Set the character size and use 96 DPI */
error = FT_Set_Char_Size( font->face, 0, ptsize * 64, 96, 96 );
//error = FT_Set_Pixel_Sizes( font->face, 0, ptsize );
if( error ) {
sge_SetError("SGE - Couldn't set font size");
sge_TTF_CloseFont( font );
return -1;
}
Flush_Cache(font);
face = font->face;
/* Get the scalable font metrics for this font */
scale = face->size->metrics.y_scale;
font->ascent = FT_CEIL(FT_MulFix(face->bbox.yMax, scale));
font->descent = FT_CEIL(FT_MulFix(face->bbox.yMin, scale));
font->height = font->ascent - font->descent + /* baseline */ 1;
font->lineskip = FT_CEIL(FT_MulFix(face->height, scale));
font->underline_offset = FT_FLOOR(FT_MulFix(face->underline_position, scale));
font->underline_height = FT_FLOOR(FT_MulFix(face->underline_thickness, scale));
if ( font->underline_height < 1 ) {
font->underline_height = 1;
}
/* Set the default font style */
//font->style = SGE_TTF_NORMAL;
font->glyph_overhang = face->size->metrics.y_ppem / 10;
/* x offset = cos(((90.0-12)/360)*2*M_PI), or 12 degree angle */
font->glyph_italics = 0.207f;
font->glyph_italics *= font->height;
return 0;
}
//==================================================================================
// Get font geometrics
//==================================================================================
int sge_TTF_FontHeight(sge_TTFont *font)
{
return(font->height);
}
int sge_TTF_FontAscent(sge_TTFont *font)
{
return(font->ascent);
}
int sge_TTF_FontDescent(sge_TTFont *font)
{
return(font->descent);
}
int sge_TTF_FontLineSkip(sge_TTFont *font)
{
return(font->lineskip);
}
int sge_TTF_GlyphMetrics(sge_TTFont *font, Uint16 ch, int* minx, int* maxx, int* miny, int* maxy, int* advance)
{
FT_Error error;
error = Find_Glyph(font, ch, CACHED_METRICS);
if ( error ) {
return -1;
}
if ( minx ) {
*minx = font->current->minx;
}
if ( maxx ) {
*maxx = font->current->maxx;
}
if ( miny ) {
*miny = font->current->miny;
}
if ( maxy ) {
*maxy = font->current->maxy;
}
if ( advance ) {
*advance = font->current->advance;
}
return 0;
}
//==================================================================================
// Set font style
//==================================================================================
void sge_TTF_SetFontStyle(sge_TTFont *font, Uint8 style)
{
font->style = style;
Flush_Cache(font);
}
//==================================================================================
// Get font style
//==================================================================================
Uint8 sge_TTF_GetFontStyle(sge_TTFont *font)
{
return(font->style);
}
#endif /* _SGE_NOTTF */
//==================================================================================
// Convert the Latin-1 text to UNICODE
//==================================================================================
Uint16 *ASCII_to_UNICODE(Uint16 *unicode, const char *text, int len)
{
int i;
for ( i=0; i < len; ++i ) {
unicode[i] = ((const unsigned char *)text)[i];
}
unicode[i] = 0;
return unicode;
}
Uint16 *sge_Latin1_Uni(const char *text)
{
Uint16 *unicode_text;
int i, unicode_len;
/* Copy the Latin-1 text to a UNICODE text buffer */
unicode_len = strlen(text);
unicode_text = (Uint16 *)malloc((unicode_len+1)*(sizeof *unicode_text));
if ( unicode_text == NULL ) {
SDL_SetError("SGE - Out of memory");
return(NULL);
}
for ( i=0; i < unicode_len; ++i ) {
unicode_text[i] = ((const unsigned char *)text)[i];
}
unicode_text[i] = 0;
return(unicode_text);
}
//==================================================================================
// Convert the UTF-8 text to UNICODE
//==================================================================================
Uint16 *UTF8_to_UNICODE(Uint16 *unicode, const char *utf8, int len)
{
int i, j;
Uint16 ch;
for ( i=0, j=0; i < len; ++i, ++j ) {
ch = ((const unsigned char *)utf8)[i];
if ( ch >= 0xF0 ) {
ch = (Uint16)(utf8[i]&0x07) << 18;
ch |= (Uint16)(utf8[++i]&0x3F) << 12;
ch |= (Uint16)(utf8[++i]&0x3F) << 6;
ch |= (Uint16)(utf8[++i]&0x3F);
} else
if ( ch >= 0xE0 ) {
ch = (Uint16)(utf8[i]&0x3F) << 12;
ch |= (Uint16)(utf8[++i]&0x3F) << 6;
ch |= (Uint16)(utf8[++i]&0x3F);
} else
if ( ch >= 0xC0 ) {
ch = (Uint16)(utf8[i]&0x3F) << 6;
ch |= (Uint16)(utf8[++i]&0x3F);
}
unicode[j] = ch;
}
unicode[j] = 0;
return unicode;
}
Uint16 *sge_UTF8_Uni(const char *text)
{
Uint16 *unicode_text;
int unicode_len;
/* Copy the UTF-8 text to a UNICODE text buffer */
unicode_len = strlen(text);
unicode_text = (Uint16 *)malloc((unicode_len+1)*(sizeof *unicode_text));
if ( unicode_text == NULL ) {
SDL_SetError("SGE - Out of memory");
return(NULL);
}
return UTF8_to_UNICODE(unicode_text, text, unicode_len);
}
#ifndef _SGE_NOTTF
//==================================================================================
// Get the width of the text with the given font
//==================================================================================
SDL_Rect sge_TTF_TextSizeUNI(sge_TTFont *font, const Uint16 *text)
{
SDL_Rect ret; ret.x=0; ret.y=0, ret.w=0, ret.h=0;
const Uint16 *ch;
int x, z;
int minx, maxx;
int miny, maxy;
glyph *glyph;
FT_Error error;
/* Initialize everything to 0 */
if ( ! _sge_TTF_initialized ) {
return ret;
}
minx = miny = 0;
maxx = maxy = 0;
/* Load each character and sum it's bounding box */
x= 0;
for ( ch=text; *ch; ++ch ) {
error = Find_Glyph(font, *ch, CACHED_METRICS);
if ( error ) {
return ret;
}
glyph = font->current;
z = x + glyph->minx;
if ( minx > z ) {
minx = z;
}
if ( font->style & SGE_TTF_BOLD ) {
x += font->glyph_overhang;
}
if ( glyph->advance > glyph->maxx ) {
z = x + glyph->advance;
} else {
z = x + glyph->maxx;
}
if ( maxx < z ) {
maxx = z;
}
x += glyph->advance;
if ( glyph->miny < miny ) {
miny = glyph->miny;
}
if ( glyph->maxy > maxy ) {
maxy = glyph->maxy;
}
}
/* Fill the bounds rectangle */
ret.w = (maxx - minx);
//ret.h = (maxy - miny); /* This is correct, but breaks many applications */
ret.h = font->height;
return ret;
}
SDL_Rect sge_TTF_TextSize(sge_TTFont *font, const char *text)
{
SDL_Rect ret; ret.x=ret.y=ret.w=ret.y=0;
Uint16 *unicode_text;
int unicode_len;
/* Copy the Latin-1 text to a UNICODE text buffer */
unicode_len = strlen(text);
unicode_text = (Uint16 *)malloc((unicode_len+1)*(sizeof *unicode_text));
if ( unicode_text == NULL ) {
SDL_SetError("SGE - Out of memory");
return ret;
}
ASCII_to_UNICODE(unicode_text, text, unicode_len);
/* Render the new text */
ret = sge_TTF_TextSizeUNI(font, unicode_text);
/* Free the text buffer and return */
free(unicode_text);
return ret;
}
/**********************************************************************************/
/** TTF output functions **/
/**********************************************************************************/
//==================================================================================
// TT Render (unicode)
// Returns an 8bit or 32bit(8/8/8/8-alpha) surface with TT text
//==================================================================================
SDL_Surface *sge_TTF_RenderUNICODE(sge_TTFont *font,const Uint16 *text, SDL_Color fg, SDL_Color bg)
{
int xstart, width;
int w, h;
SDL_Surface *textbuf;
SDL_Palette *palette;
int index;
int rdiff, gdiff, bdiff;
const Uint16 *ch;
Uint8 *src, *dst;
Uint32 *dst32;
Uint32 alpha=0;
Uint32 pixel=0;
Uint32 Rmask=0, Gmask=0, Bmask=0, Amask=0;
int row, col;
FT_Error error;
/* Get the dimensions of the text surface */
SDL_Rect ret=sge_TTF_TextSizeUNI(font, text);
w=ret.w; h=ret.h;
if ( !w ) {
SDL_SetError("SGE - Text has zero width");
return(NULL);
}
/* Create the target surface */
width = w;
if(_sge_TTF_AA!=2) /* Allocate an 8-bit pixmap */
textbuf = SDL_AllocSurface(SDL_SWSURFACE, w, h, 8, 0, 0, 0, 0);
else{ /* Allocate an 32-bit alpha pixmap */
if ( SDL_BYTEORDER == SDL_LIL_ENDIAN ) {
Rmask = 0x000000FF;
Gmask = 0x0000FF00;
Bmask = 0x00FF0000;
Amask = 0xFF000000;
} else {
Rmask = 0xFF000000;
Gmask = 0x00FF0000;
Bmask = 0x0000FF00;
Amask = 0x000000FF;
}
textbuf = SDL_AllocSurface(SDL_SWSURFACE, w, h, 32, Rmask, Gmask, Bmask, Amask);
}
if ( textbuf == NULL ) {
SDL_SetError("SGE - Out of memory");
return(NULL);
}
/* Setup our colors */
switch(_sge_TTF_AA){
case 0:{ /* No fancy antialiasing or alpha component */
palette = textbuf->format->palette;
palette->colors[0].r = bg.r;
palette->colors[0].g = bg.g;
palette->colors[0].b = bg.b;
palette->colors[1].r = fg.r;
palette->colors[1].g = fg.g;
palette->colors[1].b = fg.b;
}
break;
case 1:{ /* Fill the palette with NUM_GRAYS levels of shading from bg to fg */
palette = textbuf->format->palette;
rdiff = fg.r - bg.r;
gdiff = fg.g - bg.g;
bdiff = fg.b - bg.b;
for ( index=0; index< NUM_GRAYS; ++index ) {
palette->colors[index].r = bg.r + (index*rdiff)/(NUM_GRAYS-1);
palette->colors[index].g = bg.g + (index*gdiff)/(NUM_GRAYS-1);
palette->colors[index].b = bg.b + (index*bdiff)/(NUM_GRAYS-1);
}
}
break;
case 2:{ /* Alpha component magic */
sge_ClearSurface(textbuf, SDL_MapRGBA(textbuf->format, bg.r,bg.g,bg.b,SDL_ALPHA_TRANSPARENT));
//pixel = (fg.r<<16)|(fg.g<<8)|fg.b;
pixel = (fg.b<<16)|(fg.g<<8)|fg.r;
}
break;
}
/* Load and render each character */
xstart = 0;
for ( ch=text; *ch; ++ch ) {
error = Find_Glyph(font, *ch, CACHED_METRICS|CACHED_PIXMAP);
if ( ! error ) {
w = font->current->pixmap.width;
src = (Uint8 *)font->current->pixmap.buffer;
for ( row = 0; row < font->current->pixmap.rows; ++row ) {
dst = (Uint8 *)textbuf->pixels + (row + font->current->yoffset)* textbuf->pitch + xstart + font->current->minx;
switch(_sge_TTF_AA){
case 0:{ /* Normal */
src = font->current->pixmap.buffer + row * font->current->pixmap.pitch;
for ( col=w; col>0; --col ) {
*dst++ |= (*src++<NUM_GRAYS/2)? 0:1;
}
}
break;
case 1:{ /* Antialiasing */
src = font->current->pixmap.buffer + row * font->current->pixmap.pitch;
for ( col=w; col>0; --col ) {
*dst++ |= *src++;
}
}
break;
case 2:{ /* Alpha */
dst32 = (Uint32 *)textbuf->pixels + (row + font->current->yoffset)* textbuf->pitch/4 + xstart + font->current->minx;
for ( col=w; col>0; --col ) {
alpha = *src++;
*dst32++ |= pixel | (alpha << 24);
}
}
break;
}
}
xstart += font->current->advance;
if ( font->style & SGE_TTF_BOLD ) {
xstart += font->glyph_overhang;
}
}
}
/* Handle the underline style */
if ( font->style & SGE_TTF_UNDERLINE ) {
int row_offset;
row_offset = font->ascent - font->underline_offset - 1;
if ( row_offset > textbuf->h ) {
row_offset = (textbuf->h-1) - font->underline_height;
}
if(_sge_TTF_AA==0){
dst = (Uint8 *)textbuf->pixels + row_offset * textbuf->pitch;
for ( row=font->underline_height; row>0; --row ) {
memset(dst, 1, textbuf->w );
dst += textbuf->pitch;
}
}else if(_sge_TTF_AA==1){
dst = (Uint8 *)textbuf->pixels + row_offset * textbuf->pitch;
for ( row=font->underline_height; row>0; --row ) {
memset(dst, NUM_GRAYS - 1, textbuf->w );
dst += textbuf->pitch;
}
}else{
pixel |= Amask;
dst32 = (Uint32 *)textbuf->pixels+row_offset*textbuf->pitch/4;
for ( row=font->underline_height; row>0; --row ) {
for ( col=0; col < textbuf->w; ++col ) {
dst32[col] = pixel;
}
dst32 += textbuf->pitch/4;
}
}
}
return(textbuf);
}
//==================================================================================
// Renders the Unicode string to TrueType on surface, with the color fcolor.
// bcolor is the target color for the antialiasing.
// Alpha sets the transparency of the text (255-solid, 0-max).
//==================================================================================
SDL_Rect sge_tt_textout_UNI(SDL_Surface *Surface, sge_TTFont *font, const Uint16 *uni, Sint16 x, Sint16 y, Uint32 fcolor, Uint32 bcolor, int Alpha)
{
SDL_Rect ret; ret.x=0; ret.y=0; ret.w=0; ret.h=0;
SDL_Color temp;
SDL_Surface *text;
text=sge_TTF_RenderUNICODE(font,uni,sge_GetRGB(Surface,fcolor),sge_GetRGB(Surface,bcolor));
if(text==NULL){return ret;}
/* Align the surface text to the baseline */
Uint16 ascent=font->ascent;
temp=sge_GetRGB(Surface,bcolor);
sge_BlitTransparent(text,Surface,0,0,x,y-ascent,text->w,text->h,SDL_MapRGB(text->format,temp.r,temp.g,temp.b),Alpha);
sge_UpdateRect(Surface,x,y-ascent,text->w,text->h);
ret.x=x; ret.y=y-ascent; ret.w=text->w; ret.h=text->h;
SDL_FreeSurface(text);
return ret;
}
//==================================================================================
// Renders the Unicode string to TrueType on surface, with the color fcolor.
// bcolor is the target color for the antialiasing.
// Alpha sets the transparency of the text (0-solid, 255-max). (RGB)
//==================================================================================
SDL_Rect sge_tt_textout_UNI(SDL_Surface *Surface, sge_TTFont *font, const Uint16 *uni, Sint16 x, Sint16 y, Uint8 fR, Uint8 fG, Uint8 fB, Uint8 bR, Uint8 bG, Uint8 bB, int Alpha)
{
SDL_Rect ret; ret.x=0; ret.y=0; ret.w=0; ret.h=0;
SDL_Surface *text;
text=sge_TTF_RenderUNICODE(font,uni,sge_FillPaletteEntry(fR,fG,fB),sge_FillPaletteEntry(bR,bG,bB));
if(text==NULL){return ret;}
/* Align the surface text to the baseline */
Uint16 ascent=font->ascent;
sge_BlitTransparent(text,Surface,0,0,x,y-ascent,text->w,text->h,SDL_MapRGB(text->format,bR,bG,bB),Alpha);
sge_UpdateRect(Surface,x,y-ascent,text->w,text->h);
ret.x=x; ret.y=y-ascent; ret.w=text->w; ret.h=text->h;
SDL_FreeSurface(text);
return ret;
}
//==================================================================================
// Renders the Latin-1 string to TrueType on surface, with the color fcolor.
// bcolor is the target color for the antialiasing.
// Alpha sets the transparency of the text (0-solid, 255-max).
//==================================================================================
SDL_Rect sge_tt_textout(SDL_Surface *Surface, sge_TTFont *font, const char *string, Sint16 x, Sint16 y, Uint32 fcolor, Uint32 bcolor, int Alpha)
{
SDL_Rect ret;
Uint16 *uni;
uni=sge_Latin1_Uni(string);
ret=sge_tt_textout_UNI(Surface,font,uni,x,y,fcolor,bcolor,Alpha);
free(uni);
return ret;
}
//==================================================================================
// Renders the Latin-1 string to TrueType on surface, with the color fcolor.
// bcolor is the target color for the antialiasing.
// Alpha sets the transparency of the text (0-solid, 255-max). (RGB)
//==================================================================================
SDL_Rect sge_tt_textout(SDL_Surface *Surface, sge_TTFont *font, const char *string, Sint16 x, Sint16 y, Uint8 fR, Uint8 fG, Uint8 fB, Uint8 bR, Uint8 bG, Uint8 bB, int Alpha)
{
SDL_Rect ret;
Uint16 *uni;
uni=sge_Latin1_Uni(string);
ret=sge_tt_textout_UNI(Surface,font,uni,x,y, fR,fG,fB, bR,bG,bB, Alpha);
free(uni);
return ret;
}
//==================================================================================
// Renders the UTF-8 string to TrueType on surface, with the color fcolor.
// bcolor is the target color for the antialiasing.
// Alpha sets the transparency of the text (0-solid, 255-max).
//==================================================================================
SDL_Rect sge_tt_textout_UTF8(SDL_Surface *Surface, sge_TTFont *font, const char *string, Sint16 x, Sint16 y, Uint32 fcolor, Uint32 bcolor, int Alpha)
{
SDL_Rect ret;
Uint16 *uni;
uni=sge_UTF8_Uni(string);
ret=sge_tt_textout_UNI(Surface,font,uni,x,y,fcolor,bcolor,Alpha);
free(uni);
return ret;
}
//==================================================================================
// Renders the UTF-8 string to TrueType on surface, with the color fcolor.
// bcolor is the target color for the antialiasing.
// Alpha sets the transparency of the text (0-solid, 255-max). (RGB)
//==================================================================================
SDL_Rect sge_tt_textout_UTF8(SDL_Surface *Surface, sge_TTFont *font, const char *string, Sint16 x, Sint16 y, Uint8 fR, Uint8 fG, Uint8 fB, Uint8 bR, Uint8 bG, Uint8 bB, int Alpha)
{
SDL_Rect ret;
Uint16 *uni;
uni=sge_UTF8_Uni(string);
ret=sge_tt_textout_UNI(Surface,font,uni,x,y, fR,fG,fB, bR,bG,bB, Alpha);
free(uni);
return ret;
}
//==================================================================================
// Renders the formatet Latin-1 string to TrueType on surface, with the color fcolor.
// bcolor is the target color for the antialiasing.
// Alpha sets the transparency of the text (0-solid, 255-max). (RGB ONLY)
// * just like printf(char *format,...) *
//==================================================================================
SDL_Rect sge_tt_textoutf(SDL_Surface *Surface, sge_TTFont *font, Sint16 x, Sint16 y, Uint8 fR, Uint8 fG, Uint8 fB, Uint8 bR, Uint8 bG, Uint8 bB, int Alpha ,const char *format,...)
{
char buf[256];
va_list ap;
#ifdef __WIN32__
va_start((va_list*)ap, format); //Stupid win32 crosscompiler
#else
va_start(ap, format);
#endif
vsprintf(buf, format, ap);
va_end(ap);
return sge_tt_textout(Surface, font, buf, x,y, fR,fG,fB, bR,bG,bB, Alpha);
}
/**********************************************************************************/
/** TTF 'input' functions **/
/**********************************************************************************/
// First some internel functions for TTF input
//==================================================================================
// Fast update function for TTF input
//
// type=0 - in ret smaller then out ret
// type=1 - in ret bigger then out ret
// type=3 - safe
//==================================================================================
SDL_Rect fast_update(SDL_Surface *Surface,SDL_Surface *buffer,SDL_Rect ret, int type,sge_TTFont *font,Uint16 *string, Sint16 x,Sint16 y, Uint32 fcol, Uint32 bcol,int Alpha)
{
if(type==0){
sge_Update_OFF();
sge_FilledRect(Surface, ret.x, ret.y, ret.x+ret.w, ret.y+ret.h, bcol);
ret=sge_tt_textout_UNI(Surface,font,string, x,y, fcol, bcol, 0);
sge_Update_ON();
sge_UpdateRect(Surface, ret.x, ret.y, ret.w, ret.h);
}
else if(type==1){
SDL_Rect temp;
sge_Update_OFF();
sge_FilledRect(Surface, ret.x, ret.y, ret.x+ret.w, ret.y+ret.h, bcol);
temp=sge_tt_textout_UNI(Surface,font,string, x,y, fcol, bcol, 0);
sge_Update_ON();
sge_UpdateRect(Surface, ret.x, ret.y, ret.w, ret.h);
ret=temp;
}
else{
SDL_Rect temp;
sge_Update_OFF();
sge_FilledRect(Surface, ret.x, ret.y, ret.x+ret.w, ret.y+ret.h, bcol);
temp=sge_tt_textout_UNI(Surface,font,string, x,y, fcol, bcol, 0);
sge_Update_ON();
if(ret.w>=temp.w){
sge_UpdateRect(Surface, ret.x, ret.y, ret.w, ret.h);
}
else{
sge_UpdateRect(Surface, temp.x, temp.y, temp.w, temp.h);
}
ret=temp;
}
return ret;
}
//==================================================================================
// Update function for TTF input that preserve background
//
// type=0 - in ret smaller then out ret
// type=1 - in ret bigger then out ret
// type=3 - safe
//==================================================================================
SDL_Rect nice_update(SDL_Surface *Surface,SDL_Surface *buffer,SDL_Rect ret, int type,sge_TTFont *font,Uint16 *string, Sint16 x,Sint16 y, Uint32 fcol, Uint32 bcol, int Alpha)
{
if(type==0){
sge_Update_OFF();
sge_Blit(buffer,Surface, ret.x, ret.y, ret.x, ret.y, ret.w, ret.h);
ret=sge_tt_textout_UNI(Surface,font,string, x,y, fcol, bcol, Alpha);
sge_Update_ON();
sge_UpdateRect(Surface, ret.x, ret.y, ret.w, ret.h);
}
else if(type==1){
SDL_Rect temp;
sge_Update_OFF();
sge_Blit(buffer,Surface, ret.x, ret.y, ret.x, ret.y, ret.w, ret.h);
temp=sge_tt_textout_UNI(Surface,font,string, x,y, fcol, bcol, Alpha);
sge_Update_ON();
sge_UpdateRect(Surface, ret.x, ret.y, ret.w, ret.h);
ret=temp;
}
else{
SDL_Rect temp;
sge_Update_OFF();
sge_Blit(buffer,Surface, ret.x, ret.y, ret.x, ret.y, ret.w, ret.h);
temp=sge_tt_textout_UNI(Surface,font,string, x,y, fcol, bcol, Alpha);
sge_Update_ON();
if(ret.w>=temp.w){
sge_UpdateRect(Surface, ret.x, ret.y, ret.w, ret.h);
}
else{
sge_UpdateRect(Surface, temp.x, temp.y, temp.w, temp.h);
}
ret=temp;
}
return ret;
}
#endif /* _SGE_NOTTF */
//==================================================================================
// Handle keyrepeats
//==================================================================================
int keyrepeat(SDL_Event *event, int wait)
{
int keydown=1,c=0,ret=0;
SDL_Event ev;
do{
if(SDL_PollEvent(&ev)==1){
if(ev.type==SDL_QUIT){ret=-1;keydown=0;}
if(ev.type==SDL_KEYUP || ev.type==SDL_KEYDOWN){ //Keyrepeat cancelled
keydown=0;
if(ev.type==SDL_KEYDOWN){
SDL_PeepEvents(&ev,1, SDL_ADDEVENT, 0); //Return the newly pressed key to the event queue
}
}
}
SDL_Delay(10);
c++;
if(c>wait && keydown==1){ //trigers keyrepeat
ret=1;
SDL_PeepEvents(event,1, SDL_ADDEVENT, 0); //Return the old key to the event queue
keydown=0;
}
}while(keydown==1);
return ret;
}
//==================================================================================
// Insert a element
//==================================================================================
void insert_char(Uint16 *string, Uint16 ch, int pos, int max)
{
if(pos>max || pos<0){return;}
else if(pos==max){string[pos]=ch;}
else{
for(int i=max; i>=pos; i--){
string[i+1]=string[i];
}
string[pos]=ch;
}
}
//==================================================================================
// Delete a element
//==================================================================================
void delete_char(Uint16 *string, int pos, int max)
{
if(pos>max || pos<0){return;}
else if(pos==max){string[pos]=0;}
else{
for(int i=pos; i<=max-1; i++){
string[i]=string[i+1];
}
string[max]=0;
}
}
#ifndef _SGE_NOTTF
// These functions handle keyboard input and shows the result on screen. The text
// can be edited with [Backspace], [Delete], [Left arrow] and [Right arrow].
// Text input is terminated when [Return] or [Enter] is pressed, or if a quit event
// is recived.
// The sge_tt_input functions puts the result in 'string'.
//
// Flags: SGE_IBG - Keeps background, else bye bye background
// SGE_IDEL - Delete text on exit
// SGE_INOKR - No keyrepeat
// (use OR | to give more than one)
//
// If you want a 'default' text you can copy it to string before call and set pos to
// the first empty element in string - ex. "Hello" => pos=5. If not - zero.
// len is the max numbers of chars editable - ex. if you set the default text to "100"
// and only want 3 digits out, set len to 3. string should have atleast len+1 elements
// allocated
// This is *not* a fast, optimized function - but it gets the job done...
// Return:
// Zero or above - the lenght of the string
// -1 recieved a quit event (the lenght is lost)
// -2 invalid indata
// -3 out of memory
//==================================================================================
// Text input UNICODE (the core)
//==================================================================================
int sge_tt_input_UNI(SDL_Surface *screen,sge_TTFont *font,Uint16 *string, Uint8 flags, int pos,int len,Sint16 x,Sint16 y, Uint32 fcol, Uint32 bcol, int Alpha)
{
if(len<pos || pos<0 || len<0){return -2;}
Uint16 cur=124;//The charactar for the cursor - '|'
int max; //The strings size
/* Set update function */
SDL_Rect (*_update)(SDL_Surface *screen,SDL_Surface *buffer,SDL_Rect ret, int type,sge_TTFont *font,Uint16 *string, Sint16 x,Sint16 y, Uint32 fcol, Uint32 bcol, int Alpha);
SDL_Surface *buffer;
if(flags&SGE_FLAG1){ /* Keep background? */
_update=nice_update;
buffer=SDL_DisplayFormat(screen); /* Fixme: Yum! Memory! */
if(buffer==NULL){SDL_SetError("SGE - Out of memory");return -3;}
}
else{ /* nope */
_update=fast_update;
buffer=NULL;
Alpha=0;
}
SDL_Rect ret;
max=pos;
string[pos+1]=0;
SDL_EnableUNICODE(1);
/* Init cursor */
string[pos]=cur;
ret=sge_tt_textout_UNI(screen,font,string, x,y, fcol, bcol, Alpha);
SDL_Event event;
int quit=0;
do{
/* Check events */
SDL_WaitEvent(&event);
if(event.type==SDL_QUIT){quit=-1;}
else if(event.type==SDL_KEYDOWN && event.key.keysym.sym==SDLK_ESCAPE){quit=1;}
else if(event.type==SDL_KEYDOWN && (event.key.keysym.sym==SDLK_RETURN || event.key.keysym.sym==SDLK_KP_ENTER)){quit=1;}
else if(event.type==SDL_KEYDOWN && event.key.keysym.sym==SDLK_BACKSPACE){
if(pos>0){
/* Delete char cursor-1 */
delete_char(string,pos-1,max); pos--; max--;
ret=_update(screen,buffer,ret,1,font,string, x,y, fcol, bcol, Alpha);
/* Handle keyrepeat */
if(!(flags&SGE_FLAG3))
if(keyrepeat(&event, 20)==-1){quit=-1;}
}
}
else if(event.type==SDL_KEYDOWN && event.key.keysym.sym==SDLK_RIGHT){
if(pos!=max && pos!=len){
/* Move cursor right */
delete_char(string,pos,max);pos++;
insert_char(string,cur,pos,max);
ret=_update(screen,buffer,ret,3,font,string, x,y, fcol, bcol, Alpha);
/* Handle keyrepeat */
if(!(flags&SGE_FLAG3))
if(keyrepeat(&event, 20)==-1){quit=-1;}
}
}
else if(event.type==SDL_KEYDOWN && event.key.keysym.sym==SDLK_LEFT){
if(pos>0){
/* Move cursor left */
delete_char(string,pos,max);pos--;
insert_char(string,cur,pos,max);
ret=_update(screen,buffer,ret,3,font,string, x,y, fcol, bcol, Alpha);
/* Handle keyrepeat */
if(!(flags&SGE_FLAG3))
if(keyrepeat(&event, 20)==-1){quit=-1;}
}
}
else if(event.type==SDL_KEYDOWN && event.key.keysym.sym==SDLK_DELETE){
/* Delete char cursor+1 */
if(pos!=max && pos!=len){
delete_char(string,pos+1,max);max--;
ret=_update(screen,buffer,ret,1,font,string, x,y, fcol, bcol, Alpha);
/* Handle keyrepeat */
if(!(flags&SGE_FLAG3))
if(keyrepeat(&event, 20)==-1){quit=-1;}
}
}
else if(event.type==SDL_KEYDOWN && event.key.keysym.unicode!=0){
/* Insert new char */
if(max!=len){
max++;
insert_char(string, event.key.keysym.unicode, pos,max); pos++;
ret=_update(screen,buffer,ret,0,font,string, x,y, fcol, bcol, Alpha);
/* Handle keyrepeat */
if(!(flags&SGE_FLAG3))
if(keyrepeat(&event, 40)==-1){quit=-1;}
}
}
}while(quit==0);
/* Remove the cursor from string */
delete_char(string,pos,max);
if(flags&SGE_FLAG2){ //Remove the text
if(flags&SGE_FLAG1){
sge_Blit(buffer,screen, ret.x, ret.y, ret.x, ret.y, ret.w, ret.h);
sge_UpdateRect(screen, ret.x, ret.y, ret.w, ret.h);
}
else{
sge_FilledRect(screen,ret.x, ret.y, ret.x+ret.w, ret.y+ret.h,bcol);
}
}
else{ //Draw text without cursor
ret=_update(screen,buffer,ret,1,font,string, x,y, fcol, bcol, Alpha);
}
if(flags&SGE_FLAG1){SDL_FreeSurface(buffer);}
if(quit==-1){return -1;} //Waaa! The user killed me!
return max;
}
//==================================================================================
// Text input UNICODE (RGB)
//==================================================================================
int sge_tt_input_UNI(SDL_Surface *screen,sge_TTFont *font,Uint16 *string,Uint8 flags, int pos,int len,Sint16 x,Sint16 y, Uint8 fR, Uint8 fG, Uint8 fB, Uint8 bR,Uint8 bG,Uint8 bB, int Alpha)
{
return sge_tt_input_UNI(screen,font,string,flags,pos,len,x,y,SDL_MapRGB(screen->format, fR,fG,fB),SDL_MapRGB(screen->format, bR,bG,bB),Alpha);
}
//==================================================================================
// Text input Latin1
//
// Will fail miserable if ret<0!
//==================================================================================
int sge_tt_input(SDL_Surface *screen,sge_TTFont *font,char *string,Uint8 flags, int pos,int len,Sint16 x,Sint16 y, Uint32 fcol, Uint32 bcol, int Alpha)
{
if(len<pos || pos<0 || len<0){return -2;}
#ifndef __GNUC__
Uint16 *uni=new Uint16[len+2]; //ANSI C++
#else
Uint16 uni[len+2];
#endif
int ret;
int i;
if(pos!=0){
for(i=0; i<pos; i++){ //Convert Latin1 => Uni
uni[i]=(unsigned char)string[i];
}
}
uni[pos]=0;
ret=sge_tt_input_UNI(screen,font,uni,flags,pos,len,x,y,fcol,bcol,Alpha);
memset(string,0,sizeof(char)*(pos+1));
if(ret>0){
for( i=0; i<=ret; i++){ //Convert Uni => Latin1
string[i] = (char)uni[i];
}
}
#ifndef __GNUC__
delete[] uni;
#endif
return ret;
}
//==================================================================================
// Text input Latin1 (RGB)
//==================================================================================
int sge_tt_input(SDL_Surface *screen,sge_TTFont *font,char *string,Uint8 flags, int pos,int len,Sint16 x,Sint16 y, Uint8 fR, Uint8 fG, Uint8 fB, Uint8 bR,Uint8 bG,Uint8 bB, int Alpha)
{
return sge_tt_input(screen,font,string,flags,pos,len,x,y,SDL_MapRGB(screen->format, fR,fG,fB),SDL_MapRGB(screen->format, bR,bG,bB),Alpha);
}
#endif /* _SGE_NOTTF */

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jun 16, 12:41 AM (2 w, 1 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
69957
Default Alt Text
(42 KB)

Event Timeline