mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-20 06:58:20 +00:00
improved the font system even futher. utf8 is now used everywhere. it uses less memory as well
This commit is contained in:
parent
9254ca61f1
commit
69511102de
|
@ -1188,6 +1188,139 @@ void gui_messagebox(const char *title, const char *message)
|
||||||
int str_isspace(char c) { return c == ' ' || c == '\n' || c == '\t'; }
|
int str_isspace(char c) { return c == ' ' || c == '\n' || c == '\t'; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int str_utf8_isstart(char c)
|
||||||
|
{
|
||||||
|
if((c&0xC0) == 0x80) /* 10xxxxxx */
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int str_utf8_rewind(const char *str, int cursor)
|
||||||
|
{
|
||||||
|
while(cursor)
|
||||||
|
{
|
||||||
|
cursor--;
|
||||||
|
if(str_utf8_isstart(*(str + cursor)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
int str_utf8_forward(const char *str, int cursor)
|
||||||
|
{
|
||||||
|
const char *buf = str + cursor;
|
||||||
|
if(!buf[0])
|
||||||
|
return cursor;
|
||||||
|
|
||||||
|
if((*buf&0x80) == 0x0) /* 0xxxxxxx */
|
||||||
|
return cursor+1;
|
||||||
|
else if((*buf&0xE0) == 0xC0) /* 110xxxxx */
|
||||||
|
{
|
||||||
|
if(!buf[1]) return cursor+1;
|
||||||
|
return cursor+2;
|
||||||
|
}
|
||||||
|
else if((*buf & 0xF0) == 0xE0) /* 1110xxxx */
|
||||||
|
{
|
||||||
|
if(!buf[1]) return cursor+1;
|
||||||
|
if(!buf[2]) return cursor+2;
|
||||||
|
return cursor+2;
|
||||||
|
}
|
||||||
|
else if((*buf & 0xF8) == 0xF0) /* 11110xxx */
|
||||||
|
{
|
||||||
|
if(!buf[1]) return cursor+1;
|
||||||
|
if(!buf[2]) return cursor+2;
|
||||||
|
if(!buf[3]) return cursor+3;
|
||||||
|
return cursor+3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* invalid */
|
||||||
|
return cursor+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int str_utf8_encode(char *ptr, int chr)
|
||||||
|
{
|
||||||
|
/* encode */
|
||||||
|
if(chr <= 0x7F)
|
||||||
|
{
|
||||||
|
ptr[0] = (char)chr;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if(chr <= 0x7FF)
|
||||||
|
{
|
||||||
|
ptr[0] = 0xC0|((chr>>6)&0x1F);
|
||||||
|
ptr[1] = 0x80|(chr&0x3F);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
else if(chr <= 0xFFFF)
|
||||||
|
{
|
||||||
|
ptr[0] = 0xE0|((chr>>12)&0x0F);
|
||||||
|
ptr[1] = 0xC0|((chr>>6)&0x3F);
|
||||||
|
ptr[2] = 0xC0|(chr&0x3F);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
else if(chr <= 0x10FFFF)
|
||||||
|
{
|
||||||
|
ptr[0] = 0xF0|((chr>>18)&0x07);
|
||||||
|
ptr[1] = 0xC0|((chr>>12)&0x3F);
|
||||||
|
ptr[2] = 0xC0|((chr>>6)&0x3F);
|
||||||
|
ptr[3] = 0xC0|(chr&0x3F);
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int str_utf8_decode(const char **ptr)
|
||||||
|
{
|
||||||
|
const char *buf = *ptr;
|
||||||
|
int ch = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if((*buf&0x80) == 0x0) /* 0xxxxxxx */
|
||||||
|
{
|
||||||
|
ch = *buf;
|
||||||
|
buf++;
|
||||||
|
}
|
||||||
|
else if((*buf&0xE0) == 0xC0) /* 110xxxxx */
|
||||||
|
{
|
||||||
|
ch = (*buf++ & 0x3F) << 6; if(!(*buf)) break;
|
||||||
|
ch += (*buf++ & 0x3F);
|
||||||
|
if(ch == 0) ch = -1;
|
||||||
|
}
|
||||||
|
else if((*buf & 0xF0) == 0xE0) /* 1110xxxx */
|
||||||
|
{
|
||||||
|
ch = (*buf++ & 0x1F) << 12; if(!(*buf)) break;
|
||||||
|
ch += (*buf++ & 0x3F) << 6; if(!(*buf)) break;
|
||||||
|
ch += (*buf++ & 0x3F);
|
||||||
|
if(ch == 0) ch = -1;
|
||||||
|
}
|
||||||
|
else if((*buf & 0xF8) == 0xF0) /* 11110xxx */
|
||||||
|
{
|
||||||
|
ch = (*buf++ & 0x0F) << 18; if(!(*buf)) break;
|
||||||
|
ch += (*buf++ & 0x3F) << 12; if(!(*buf)) break;
|
||||||
|
ch += (*buf++ & 0x3F) << 6; if(!(*buf)) break;
|
||||||
|
ch += (*buf++ & 0x3F);
|
||||||
|
if(ch == 0) ch = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* invalid */
|
||||||
|
buf++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ptr = buf;
|
||||||
|
return ch;
|
||||||
|
} while(0);
|
||||||
|
|
||||||
|
/* out of bounds */
|
||||||
|
*ptr = buf;
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -947,6 +947,69 @@ int str_isspace(char c);
|
||||||
*/
|
*/
|
||||||
void gui_messagebox(const char *title, const char *message);
|
void gui_messagebox(const char *title, const char *message);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Function: str_utf8_rewind
|
||||||
|
Moves a cursor backwards in an utf8 string
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
str - utf8 string
|
||||||
|
cursor - position in the string
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
New cursor position.
|
||||||
|
|
||||||
|
Remarks:
|
||||||
|
- Won't move the cursor less then 0
|
||||||
|
*/
|
||||||
|
int str_utf8_rewind(const char *str, int cursor);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Function: str_utf8_forward
|
||||||
|
Moves a cursor forwards in an utf8 string
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
str - utf8 string
|
||||||
|
cursor - position in the string
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
New cursor position.
|
||||||
|
|
||||||
|
Remarks:
|
||||||
|
- Won't move the cursor beyond the zero termination marker
|
||||||
|
*/
|
||||||
|
int str_utf8_forward(const char *str, int cursor);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Function: str_utf8_decode
|
||||||
|
Decodes an utf8 character
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
ptr - pointer to an utf8 string. this pointer will be moved forward
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Unicode value for the character. -1 for invalid characters and 0 for end of string.
|
||||||
|
|
||||||
|
Remarks:
|
||||||
|
- This function will also move the pointer forward.
|
||||||
|
*/
|
||||||
|
int str_utf8_decode(const char **ptr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Function: str_utf8_encode
|
||||||
|
Encode an utf8 character
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
ptr - Pointer to a buffer that should recive the data. Should be able to hold at least 4 bytes.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Number of bytes put into the buffer.
|
||||||
|
|
||||||
|
Remarks:
|
||||||
|
- Does not do zero termination of the string.
|
||||||
|
*/
|
||||||
|
int str_utf8_encode(char *ptr, int chr);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -121,6 +121,9 @@ typedef struct FONTSIZEDATA
|
||||||
int num_x_chars;
|
int num_x_chars;
|
||||||
int num_y_chars;
|
int num_y_chars;
|
||||||
|
|
||||||
|
int char_max_width;
|
||||||
|
int char_max_height;
|
||||||
|
|
||||||
FONTCHAR characters[MAX_CHARACTERS*MAX_CHARACTERS];
|
FONTCHAR characters[MAX_CHARACTERS*MAX_CHARACTERS];
|
||||||
|
|
||||||
int current_character;
|
int current_character;
|
||||||
|
@ -201,35 +204,87 @@ static void grow(unsigned char *in, unsigned char *out, int w, int h)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void font_init_texture(FONTSIZEDATA *font, int width, int height)
|
static void font_init_texture(FONTSIZEDATA *sizedata, int charwidth, int charheight, int xchars, int ychars)
|
||||||
{
|
{
|
||||||
|
static int font_memory_usage = 0;
|
||||||
int i;
|
int i;
|
||||||
|
int width = charwidth*xchars;
|
||||||
|
int height = charheight*ychars;
|
||||||
void *mem = mem_alloc(width*height, 1);
|
void *mem = mem_alloc(width*height, 1);
|
||||||
mem_zero(mem, width*height);
|
mem_zero(mem, width*height);
|
||||||
|
|
||||||
font->texture_width = width;
|
if(sizedata->textures[0] == 0)
|
||||||
font->texture_height = height;
|
glGenTextures(2, sizedata->textures);
|
||||||
font->num_x_chars = 32;
|
else
|
||||||
font->num_y_chars = 32;
|
font_memory_usage -= sizedata->texture_width*sizedata->texture_height*2;
|
||||||
font->current_character = 0;
|
|
||||||
glGenTextures(2, font->textures);
|
sizedata->num_x_chars = xchars;
|
||||||
|
sizedata->num_y_chars = ychars;
|
||||||
|
sizedata->texture_width = width;
|
||||||
|
sizedata->texture_height = height;
|
||||||
|
sizedata->current_character = 0;
|
||||||
|
|
||||||
for(i = 0; i < 2; i++)
|
for(i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
glBindTexture(GL_TEXTURE_2D, font->textures[i]);
|
glBindTexture(GL_TEXTURE_2D, sizedata->textures[i]);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, font_texture_format, width, height, 0, font_texture_format, GL_UNSIGNED_BYTE, mem);
|
glTexImage2D(GL_TEXTURE_2D, 0, font_texture_format, width, height, 0, font_texture_format, GL_UNSIGNED_BYTE, mem);
|
||||||
|
font_memory_usage += width*height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dbg_msg("", "font memory usage: %d", font_memory_usage);
|
||||||
|
|
||||||
mem_free(mem);
|
mem_free(mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void font_increase_texture_size(FONTSIZEDATA *sizedata)
|
||||||
|
{
|
||||||
|
if(sizedata->texture_width < sizedata->texture_height)
|
||||||
|
sizedata->num_x_chars <<= 1;
|
||||||
|
else
|
||||||
|
sizedata->num_y_chars <<= 1;
|
||||||
|
font_init_texture(sizedata, sizedata->char_max_width, sizedata->char_max_height, sizedata->num_x_chars, sizedata->num_y_chars);
|
||||||
|
}
|
||||||
|
|
||||||
static void font_init_index(FONT *font, int index)
|
static void font_init_index(FONT *font, int index)
|
||||||
{
|
{
|
||||||
font->sizes[index].font_size = font_sizes[index];
|
int outline_thickness = 1;
|
||||||
|
FONTSIZEDATA *sizedata = &font->sizes[index];
|
||||||
|
|
||||||
|
sizedata->font_size = font_sizes[index];
|
||||||
|
FT_Set_Pixel_Sizes(font->ft_face, 0, sizedata->font_size);
|
||||||
|
|
||||||
|
if(sizedata->font_size >= 18)
|
||||||
|
outline_thickness = 2;
|
||||||
|
|
||||||
|
{
|
||||||
|
unsigned glyph_index;
|
||||||
|
int charcode;
|
||||||
|
int max_h = 0;
|
||||||
|
int max_w = 0;
|
||||||
|
|
||||||
|
charcode = FT_Get_First_Char(font->ft_face, &glyph_index);
|
||||||
|
while(glyph_index != 0)
|
||||||
|
{
|
||||||
|
/* do stuff */
|
||||||
|
FT_Load_Glyph(font->ft_face, glyph_index, FT_LOAD_DEFAULT);
|
||||||
|
|
||||||
|
if(font->ft_face->glyph->metrics.width > max_w) max_w = font->ft_face->glyph->metrics.width;
|
||||||
|
if(font->ft_face->glyph->metrics.height > max_h) max_h = font->ft_face->glyph->metrics.height;
|
||||||
|
charcode = FT_Get_Next_Char(font->ft_face, charcode, &glyph_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
max_w = (max_w>>6)+2+outline_thickness*2;
|
||||||
|
max_h = (max_h>>6)+2+outline_thickness*2;
|
||||||
|
|
||||||
|
for(sizedata->char_max_width = 1; sizedata->char_max_width < max_w; sizedata->char_max_width <<= 1);
|
||||||
|
for(sizedata->char_max_height = 1; sizedata->char_max_height < max_h; sizedata->char_max_height <<= 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//dbg_msg("font", "init size %d, texture size %d %d", font->sizes[index].font_size, w, h);
|
||||||
//FT_New_Face(ft_library, "data/fonts/vera.ttf", 0, &font->ft_face);
|
//FT_New_Face(ft_library, "data/fonts/vera.ttf", 0, &font->ft_face);
|
||||||
font_init_texture(&font->sizes[index], 1024*2, 1024*2);
|
font_init_texture(sizedata, sizedata->char_max_width, sizedata->char_max_height, 8, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
static FONTSIZEDATA *font_get_size(FONT *font, int pixelsize)
|
static FONTSIZEDATA *font_get_size(FONT *font, int pixelsize)
|
||||||
|
@ -279,6 +334,13 @@ static int font_get_slot(FONTSIZEDATA *sizedata)
|
||||||
if(sizedata->characters[i].touch_time < sizedata->characters[oldest].touch_time)
|
if(sizedata->characters[i].touch_time < sizedata->characters[oldest].touch_time)
|
||||||
oldest = i;
|
oldest = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(time_get()-sizedata->characters[oldest].touch_time < time_freq())
|
||||||
|
{
|
||||||
|
font_increase_texture_size(sizedata);
|
||||||
|
return font_get_slot(sizedata);
|
||||||
|
}
|
||||||
|
|
||||||
return oldest;
|
return oldest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -286,7 +348,7 @@ static int font_get_slot(FONTSIZEDATA *sizedata)
|
||||||
static int font_render_glyph(FONT *font, FONTSIZEDATA *sizedata, int chr)
|
static int font_render_glyph(FONT *font, FONTSIZEDATA *sizedata, int chr)
|
||||||
{
|
{
|
||||||
FT_Bitmap *bitmap;
|
FT_Bitmap *bitmap;
|
||||||
int slot_id = sizedata->current_character;
|
int slot_id = 0;
|
||||||
int slot_w = sizedata->texture_width / sizedata->num_x_chars;
|
int slot_w = sizedata->texture_width / sizedata->num_x_chars;
|
||||||
int slot_h = sizedata->texture_height / sizedata->num_y_chars;
|
int slot_h = sizedata->texture_height / sizedata->num_y_chars;
|
||||||
int slot_size = slot_w*slot_h;
|
int slot_size = slot_w*slot_h;
|
||||||
|
@ -297,7 +359,7 @@ static int font_render_glyph(FONT *font, FONTSIZEDATA *sizedata, int chr)
|
||||||
|
|
||||||
FT_Set_Pixel_Sizes(font->ft_face, 0, sizedata->font_size);
|
FT_Set_Pixel_Sizes(font->ft_face, 0, sizedata->font_size);
|
||||||
|
|
||||||
if(FT_Load_Char(font->ft_face, chr, FT_LOAD_RENDER))
|
if(FT_Load_Char(font->ft_face, chr, FT_LOAD_RENDER|FT_LOAD_NO_BITMAP))
|
||||||
{
|
{
|
||||||
dbg_msg("font", "error loading glyph %d", chr);
|
dbg_msg("font", "error loading glyph %d", chr);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -412,7 +474,7 @@ static FONTCHAR *font_get_char(FONT *font, FONTSIZEDATA *sizedata, int chr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* must only be called from the rendering function as the font must be set to the correct size */
|
/* must only be called from the rendering function as the font must be set to the correct size */
|
||||||
static void font_setsize(FONT *font, int size)
|
static void font_render_setup(FONT *font, int size)
|
||||||
{
|
{
|
||||||
FT_Set_Pixel_Sizes(font->ft_face, 0, size);
|
FT_Set_Pixel_Sizes(font->ft_face, 0, size);
|
||||||
}
|
}
|
||||||
|
@ -420,57 +482,10 @@ static void font_setsize(FONT *font, int size)
|
||||||
static float font_kerning(FONT *font, int left, int right)
|
static float font_kerning(FONT *font, int left, int right)
|
||||||
{
|
{
|
||||||
FT_Vector kerning = {0,0};
|
FT_Vector kerning = {0,0};
|
||||||
FT_Get_Kerning(font->ft_face, left, right, FT_KERNING_DEFAULT, &kerning );
|
FT_Get_Kerning(font->ft_face, left, right, FT_KERNING_DEFAULT, &kerning);
|
||||||
return (kerning.x>>6);
|
return (kerning.x>>6);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int utf8_decode(const unsigned char **ptr)
|
|
||||||
{
|
|
||||||
const unsigned char *buf = *ptr;
|
|
||||||
int ch = 0;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if((*buf&0x80) == 0x0) /* 0xxxxxxx */
|
|
||||||
{
|
|
||||||
ch = *buf;
|
|
||||||
buf++;
|
|
||||||
}
|
|
||||||
else if((*buf&0xE0) == 0xC0) /* 110xxxxx */
|
|
||||||
{
|
|
||||||
ch = (*buf++ & 0x3F) << 6; if(!(*buf)) break;
|
|
||||||
ch += (*buf++ & 0x3F);
|
|
||||||
if(ch == 0) ch = -1;
|
|
||||||
}
|
|
||||||
else if((*buf & 0xF0) == 0xE0) /* 1110xxxx */
|
|
||||||
{
|
|
||||||
ch = (*buf++ & 0x1F) << 12; if(!(*buf)) break;
|
|
||||||
ch += (*buf++ & 0x3F) << 6; if(!(*buf)) break;
|
|
||||||
ch += (*buf++ & 0x3F);
|
|
||||||
if(ch == 0) ch = -1;
|
|
||||||
}
|
|
||||||
else if((*buf & 0xF8) == 0xF0) /* 11110xxx */
|
|
||||||
{
|
|
||||||
ch = (*buf++ & 0x0F) << 18; if(!(*buf)) break;
|
|
||||||
ch += (*buf++ & 0x3F) << 12; if(!(*buf)) break;
|
|
||||||
ch += (*buf++ & 0x3F) << 6; if(!(*buf)) break;
|
|
||||||
ch += (*buf++ & 0x3F);
|
|
||||||
if(ch == 0) ch = -1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* valid */
|
|
||||||
*ptr = buf;
|
|
||||||
return ch;
|
|
||||||
} while(0);
|
|
||||||
|
|
||||||
/* invalid */
|
|
||||||
*ptr = buf;
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void gfx_text_ex(TEXT_CURSOR *cursor, const char *text, int length)
|
void gfx_text_ex(TEXT_CURSOR *cursor, const char *text, int length)
|
||||||
{
|
{
|
||||||
FONT *font = cursor->font;
|
FONT *font = cursor->font;
|
||||||
|
@ -512,7 +527,7 @@ void gfx_text_ex(TEXT_CURSOR *cursor, const char *text, int length)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
sizedata = font_get_size(font, actual_size);
|
sizedata = font_get_size(font, actual_size);
|
||||||
font_setsize(font, actual_size);
|
font_render_setup(font, actual_size);
|
||||||
|
|
||||||
/* set length */
|
/* set length */
|
||||||
if(length < 0)
|
if(length < 0)
|
||||||
|
@ -527,8 +542,8 @@ void gfx_text_ex(TEXT_CURSOR *cursor, const char *text, int length)
|
||||||
|
|
||||||
for(;i < 2; i++)
|
for(;i < 2; i++)
|
||||||
{
|
{
|
||||||
const unsigned char *current = (unsigned char *)text;
|
const char *current = (char *)text;
|
||||||
const unsigned char *end = current+length;
|
const char *end = current+length;
|
||||||
//int to_render = length;
|
//int to_render = length;
|
||||||
draw_x = cursor_x;
|
draw_x = cursor_x;
|
||||||
draw_y = cursor_y;
|
draw_y = cursor_y;
|
||||||
|
@ -553,7 +568,7 @@ void gfx_text_ex(TEXT_CURSOR *cursor, const char *text, int length)
|
||||||
{
|
{
|
||||||
int new_line = 0;
|
int new_line = 0;
|
||||||
//int this_batch = (int)(end-current);
|
//int this_batch = (int)(end-current);
|
||||||
const unsigned char *batch_end = end;
|
const char *batch_end = end;
|
||||||
if(cursor->line_width > 0 && !(cursor->flags&TEXTFLAG_STOP_AT_END))
|
if(cursor->line_width > 0 && !(cursor->flags&TEXTFLAG_STOP_AT_END))
|
||||||
{
|
{
|
||||||
int wlen = word_length((char *)current);
|
int wlen = word_length((char *)current);
|
||||||
|
@ -599,19 +614,23 @@ void gfx_text_ex(TEXT_CURSOR *cursor, const char *text, int length)
|
||||||
|
|
||||||
while(current < batch_end)
|
while(current < batch_end)
|
||||||
{
|
{
|
||||||
|
const char *tmp;
|
||||||
float advance = 0;
|
float advance = 0;
|
||||||
int character = 0;
|
int character = 0;
|
||||||
|
int nextcharacter = 0;
|
||||||
FONTCHAR *chr;
|
FONTCHAR *chr;
|
||||||
|
|
||||||
// TODO: UTF-8 decode
|
// TODO: UTF-8 decode
|
||||||
character = utf8_decode(¤t);
|
character = str_utf8_decode(¤t);
|
||||||
|
tmp = current;
|
||||||
|
nextcharacter = str_utf8_decode(&tmp);
|
||||||
|
|
||||||
if(character == '\n')
|
if(character == '\n')
|
||||||
{
|
{
|
||||||
draw_x = cursor->start_x;
|
draw_x = cursor->start_x;
|
||||||
draw_y += size;
|
draw_y += size;
|
||||||
draw_x = (int)(draw_x * fake_to_screen_x) / fake_to_screen_x; /* realign */
|
draw_x = (int)(draw_x * fake_to_screen_x) / fake_to_screen_x; /* realign */
|
||||||
draw_y = (int)(draw_y * fake_to_screen_y) / fake_to_screen_y;
|
draw_y = (int)(draw_y * fake_to_screen_y) / fake_to_screen_y;
|
||||||
/* current++; */
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -625,7 +644,7 @@ void gfx_text_ex(TEXT_CURSOR *cursor, const char *text, int length)
|
||||||
gfx_quads_drawTL(draw_x+chr->offset_x*size, draw_y+chr->offset_y*size, chr->width*size, chr->height*size);
|
gfx_quads_drawTL(draw_x+chr->offset_x*size, draw_y+chr->offset_y*size, chr->width*size, chr->height*size);
|
||||||
}
|
}
|
||||||
|
|
||||||
advance = chr->advance_x; /* + font_kerning(font, character, *(current+1));*/
|
advance = chr->advance_x + font_kerning(font, character, nextcharacter)/size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cursor->flags&TEXTFLAG_STOP_AT_END && draw_x+advance*size-cursor->start_x > cursor->line_width)
|
if(cursor->flags&TEXTFLAG_STOP_AT_END && draw_x+advance*size-cursor->start_x > cursor->line_width)
|
||||||
|
|
|
@ -49,11 +49,11 @@ enum
|
||||||
static INPUT_EVENT input_events[INPUT_BUFFER_SIZE];
|
static INPUT_EVENT input_events[INPUT_BUFFER_SIZE];
|
||||||
static int num_events = 0;
|
static int num_events = 0;
|
||||||
|
|
||||||
static void add_event(char c, int key, int flags)
|
static void add_event(int unicode, int key, int flags)
|
||||||
{
|
{
|
||||||
if(num_events != INPUT_BUFFER_SIZE)
|
if(num_events != INPUT_BUFFER_SIZE)
|
||||||
{
|
{
|
||||||
input_events[num_events].ch = c;
|
input_events[num_events].unicode = unicode;
|
||||||
input_events[num_events].key = key;
|
input_events[num_events].key = key;
|
||||||
input_events[num_events].flags = flags;
|
input_events[num_events].flags = flags;
|
||||||
num_events++;
|
num_events++;
|
||||||
|
@ -178,8 +178,8 @@ void inp_update()
|
||||||
{
|
{
|
||||||
/* handle keys */
|
/* handle keys */
|
||||||
case SDL_KEYDOWN:
|
case SDL_KEYDOWN:
|
||||||
if(event.key.keysym.unicode < 255)
|
/*if(event.key.keysym.unicode < 255) */
|
||||||
add_event(event.key.keysym.unicode, 0, 0);
|
add_event(event.key.keysym.unicode, 0, 0);
|
||||||
key = event.key.keysym.sym;
|
key = event.key.keysym.sym;
|
||||||
break;
|
break;
|
||||||
case SDL_KEYUP:
|
case SDL_KEYUP:
|
||||||
|
|
|
@ -671,5 +671,4 @@ void gfx_text_ex(TEXT_CURSOR *cursor, const char *text, int length);
|
||||||
struct FONT *gfx_font_load(const char *filename);
|
struct FONT *gfx_font_load(const char *filename);
|
||||||
void gfx_font_destroy(struct FONT *font);
|
void gfx_font_destroy(struct FONT *font);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -20,7 +20,7 @@ enum
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
int flags;
|
int flags;
|
||||||
unsigned char ch;
|
int unicode;
|
||||||
int key;
|
int key;
|
||||||
} INPUT_EVENT;
|
} INPUT_EVENT;
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
#include <game/generated/gc_data.hpp>
|
#include <game/generated/gc_data.hpp>
|
||||||
#include <game/client/gameclient.hpp>
|
#include <game/client/gameclient.hpp>
|
||||||
|
#include <game/client/lineinput.hpp>
|
||||||
#include <mastersrv/mastersrv.h>
|
#include <mastersrv/mastersrv.h>
|
||||||
|
|
||||||
vec4 MENUS::gui_color;
|
vec4 MENUS::gui_color;
|
||||||
|
@ -199,7 +200,7 @@ void MENUS::ui_draw_checkbox_number(const void *id, const char *text, int checke
|
||||||
ui_draw_checkbox_common(id, text, buf, r);
|
ui_draw_checkbox_common(id, text, buf, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MENUS::ui_do_edit_box(void *id, const RECT *rect, char *str, int str_size, float font_size, bool hidden)
|
int MENUS::ui_do_edit_box(void *id, const RECT *rect, char *str, unsigned str_size, float font_size, bool hidden)
|
||||||
{
|
{
|
||||||
int inside = ui_mouse_inside(rect);
|
int inside = ui_mouse_inside(rect);
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
@ -229,48 +230,7 @@ int MENUS::ui_do_edit_box(void *id, const RECT *rect, char *str, int str_size, f
|
||||||
for(int i = 0; i < num_inputevents; i++)
|
for(int i = 0; i < num_inputevents; i++)
|
||||||
{
|
{
|
||||||
len = strlen(str);
|
len = strlen(str);
|
||||||
INPUT_EVENT e = inputevents[i];
|
LINEINPUT::manipulate(inputevents[i], str, str_size, &len, &at_index);
|
||||||
char c = e.ch;
|
|
||||||
int k = e.key;
|
|
||||||
|
|
||||||
if (at_index > len)
|
|
||||||
at_index = len;
|
|
||||||
|
|
||||||
if (!(c >= 0 && c < 32) && c != 127)
|
|
||||||
{
|
|
||||||
if (len < str_size - 1 && at_index < str_size - 1)
|
|
||||||
{
|
|
||||||
memmove(str + at_index + 1, str + at_index, len - at_index + 1);
|
|
||||||
str[at_index] = c;
|
|
||||||
at_index++;
|
|
||||||
r = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(e.flags&INPFLAG_PRESS)
|
|
||||||
{
|
|
||||||
if (k == KEY_BACKSPACE && at_index > 0)
|
|
||||||
{
|
|
||||||
memmove(str + at_index - 1, str + at_index, len - at_index + 1);
|
|
||||||
at_index--;
|
|
||||||
r = 1;
|
|
||||||
}
|
|
||||||
else if (k == KEY_DELETE && at_index < len)
|
|
||||||
{
|
|
||||||
memmove(str + at_index, str + at_index + 1, len - at_index);
|
|
||||||
r = 1;
|
|
||||||
}
|
|
||||||
else if (k == KEY_RETURN)
|
|
||||||
ui_clear_last_active_item();
|
|
||||||
else if (k == KEY_LEFT && at_index > 0)
|
|
||||||
at_index--;
|
|
||||||
else if (k == KEY_RIGHT && at_index < len)
|
|
||||||
at_index++;
|
|
||||||
else if (k == KEY_HOME)
|
|
||||||
at_index = 0;
|
|
||||||
else if (k == KEY_END)
|
|
||||||
at_index = len;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ class MENUS : public COMPONENT
|
||||||
static void ui_draw_checkbox_common(const void *id, const char *text, const char *boxtext, const RECT *r);
|
static void ui_draw_checkbox_common(const void *id, const char *text, const char *boxtext, const RECT *r);
|
||||||
static void ui_draw_checkbox(const void *id, const char *text, int checked, const RECT *r, const void *extra);
|
static void ui_draw_checkbox(const void *id, const char *text, int checked, const RECT *r, const void *extra);
|
||||||
static void ui_draw_checkbox_number(const void *id, const char *text, int checked, const RECT *r, const void *extra);
|
static void ui_draw_checkbox_number(const void *id, const char *text, int checked, const RECT *r, const void *extra);
|
||||||
static int ui_do_edit_box(void *id, const RECT *rect, char *str, int str_size, float font_size, bool hidden=false);
|
static int ui_do_edit_box(void *id, const RECT *rect, char *str, unsigned str_size, float font_size, bool hidden=false);
|
||||||
|
|
||||||
static float ui_do_scrollbar_v(const void *id, const RECT *rect, float current);
|
static float ui_do_scrollbar_v(const void *id, const RECT *rect, float current);
|
||||||
static float ui_do_scrollbar_h(const void *id, const RECT *rect, float current);
|
static float ui_do_scrollbar_h(const void *id, const RECT *rect, float current);
|
||||||
|
|
|
@ -21,23 +21,30 @@ void LINEINPUT::set(const char *string)
|
||||||
cursor_pos = len;
|
cursor_pos = len;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LINEINPUT::process_input(INPUT_EVENT e)
|
void LINEINPUT::manipulate(INPUT_EVENT e, char *str, int str_max_size, int *str_len_ptr, int *cursor_pos_ptr)
|
||||||
{
|
{
|
||||||
|
int cursor_pos = *cursor_pos_ptr;
|
||||||
|
int len = *str_len_ptr;
|
||||||
|
|
||||||
if(cursor_pos > len)
|
if(cursor_pos > len)
|
||||||
cursor_pos = len;
|
cursor_pos = len;
|
||||||
|
|
||||||
char c = e.ch;
|
int code = e.unicode;
|
||||||
int k = e.key;
|
int k = e.key;
|
||||||
|
|
||||||
// 127 is produced on Mac OS X and corresponds to the delete key
|
// 127 is produced on Mac OS X and corresponds to the delete key
|
||||||
if (!(c >= 0 && c < 32) && c != 127)
|
if (!(code >= 0 && code < 32) && code != 127)
|
||||||
{
|
{
|
||||||
if (len < sizeof(str) - 1 && cursor_pos < sizeof(str) - 1)
|
char tmp[8];
|
||||||
|
int charsize = str_utf8_encode(tmp, code);
|
||||||
|
|
||||||
|
if (len < str_max_size - charsize && cursor_pos < str_max_size - charsize)
|
||||||
{
|
{
|
||||||
memmove(str + cursor_pos + 1, str + cursor_pos, len - cursor_pos + 1);
|
memmove(str + cursor_pos + charsize, str + cursor_pos, len - cursor_pos + charsize);
|
||||||
str[cursor_pos] = c;
|
for(int i = 0; i < charsize; i++)
|
||||||
cursor_pos++;
|
str[cursor_pos+i] = tmp[i];
|
||||||
len++;
|
cursor_pos += charsize;
|
||||||
|
len += charsize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,22 +52,34 @@ void LINEINPUT::process_input(INPUT_EVENT e)
|
||||||
{
|
{
|
||||||
if (k == KEY_BACKSPACE && cursor_pos > 0)
|
if (k == KEY_BACKSPACE && cursor_pos > 0)
|
||||||
{
|
{
|
||||||
memmove(str + cursor_pos - 1, str + cursor_pos, len - cursor_pos + 1);
|
int new_cursor_pos = str_utf8_rewind(str, cursor_pos);
|
||||||
cursor_pos--;
|
int charsize = cursor_pos-new_cursor_pos;
|
||||||
len--;
|
memmove(str+new_cursor_pos, str+cursor_pos, len - charsize + 1); // +1 == null term
|
||||||
|
cursor_pos = new_cursor_pos;
|
||||||
|
len -= charsize;
|
||||||
}
|
}
|
||||||
else if (k == KEY_DELETE && cursor_pos < len)
|
else if (k == KEY_DELETE && cursor_pos < len)
|
||||||
{
|
{
|
||||||
memmove(str + cursor_pos, str + cursor_pos + 1, len - cursor_pos);
|
int p = str_utf8_forward(str, cursor_pos);
|
||||||
len--;
|
int charsize = p-cursor_pos;
|
||||||
|
memmove(str + cursor_pos, str + cursor_pos + charsize, len - cursor_pos - charsize + 1); // +1 == null term
|
||||||
|
len -= charsize;
|
||||||
}
|
}
|
||||||
else if (k == KEY_LEFT && cursor_pos > 0)
|
else if (k == KEY_LEFT && cursor_pos > 0)
|
||||||
cursor_pos--;
|
cursor_pos = str_utf8_rewind(str, cursor_pos);
|
||||||
else if (k == KEY_RIGHT && cursor_pos < len)
|
else if (k == KEY_RIGHT && cursor_pos < len)
|
||||||
cursor_pos++;
|
cursor_pos = str_utf8_forward(str, cursor_pos);
|
||||||
else if (k == KEY_HOME)
|
else if (k == KEY_HOME)
|
||||||
cursor_pos = 0;
|
cursor_pos = 0;
|
||||||
else if (k == KEY_END)
|
else if (k == KEY_END)
|
||||||
cursor_pos = len;
|
cursor_pos = len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*cursor_pos_ptr = cursor_pos;
|
||||||
|
*str_len_ptr = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LINEINPUT::process_input(INPUT_EVENT e)
|
||||||
|
{
|
||||||
|
manipulate(e, str, sizeof(str), &len, &cursor_pos);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,11 @@
|
||||||
class LINEINPUT
|
class LINEINPUT
|
||||||
{
|
{
|
||||||
char str[256];
|
char str[256];
|
||||||
unsigned len;
|
int len;
|
||||||
unsigned cursor_pos;
|
int cursor_pos;
|
||||||
public:
|
public:
|
||||||
|
static void manipulate(INPUT_EVENT e, char *str, int str_max_size, int *str_len, int *cursor_pos);
|
||||||
|
|
||||||
class CALLBACK
|
class CALLBACK
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -18,6 +18,7 @@ extern "C" {
|
||||||
#include <game/client/render.hpp>
|
#include <game/client/render.hpp>
|
||||||
|
|
||||||
#include "ed_editor.hpp"
|
#include "ed_editor.hpp"
|
||||||
|
#include <game/client/lineinput.hpp>
|
||||||
|
|
||||||
static int checker_texture = 0;
|
static int checker_texture = 0;
|
||||||
static int background_texture = 0;
|
static int background_texture = 0;
|
||||||
|
@ -209,44 +210,7 @@ int ui_do_edit_box(void *id, const RECT *rect, char *str, int str_size, float fo
|
||||||
for(int i = 0; i < inp_num_events(); i++)
|
for(int i = 0; i < inp_num_events(); i++)
|
||||||
{
|
{
|
||||||
len = strlen(str);
|
len = strlen(str);
|
||||||
|
LINEINPUT::manipulate(inp_get_event(i), str, str_size, &len, &at_index);
|
||||||
INPUT_EVENT e = inp_get_event(i);
|
|
||||||
char c = e.ch;
|
|
||||||
int k = e.key;
|
|
||||||
|
|
||||||
if (at_index > len)
|
|
||||||
at_index = len;
|
|
||||||
|
|
||||||
if (!(c >= 0 && c < 32) && c != 127)
|
|
||||||
{
|
|
||||||
if (len < str_size - 1 && at_index < str_size - 1)
|
|
||||||
{
|
|
||||||
memmove(str + at_index + 1, str + at_index, len - at_index + 1);
|
|
||||||
str[at_index] = c;
|
|
||||||
at_index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(e.flags&INPFLAG_PRESS)
|
|
||||||
{
|
|
||||||
if (k == KEY_BACKSPACE && at_index > 0)
|
|
||||||
{
|
|
||||||
memmove(str + at_index - 1, str + at_index, len - at_index + 1);
|
|
||||||
at_index--;
|
|
||||||
}
|
|
||||||
else if (k == KEY_DELETE && at_index < len)
|
|
||||||
memmove(str + at_index, str + at_index + 1, len - at_index);
|
|
||||||
else if (k == KEY_RETURN)
|
|
||||||
ui_clear_last_active_item();
|
|
||||||
else if (k == KEY_LEFT && at_index > 0)
|
|
||||||
at_index--;
|
|
||||||
else if (k == KEY_RIGHT && at_index < len)
|
|
||||||
at_index++;
|
|
||||||
else if (k == KEY_HOME)
|
|
||||||
at_index = 0;
|
|
||||||
else if (k == KEY_END)
|
|
||||||
at_index = len;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
r = 1;
|
r = 1;
|
||||||
|
|
Loading…
Reference in a new issue