diff --git a/share/grafx2/skins/unicode_0410-044F.png b/share/grafx2/skins/unicode_0410-044F.png new file mode 100644 index 00000000..c5b70d5c Binary files /dev/null and b/share/grafx2/skins/unicode_0410-044F.png differ diff --git a/src/buttons.c b/src/buttons.c index 3fc89f10..69e169c9 100644 --- a/src/buttons.c +++ b/src/buttons.c @@ -1459,7 +1459,7 @@ void Button_Skins(void) T_Fileselector_item* fontName; selected_font = Window_attribute2; // Get the index of the chosen font. fontName = Get_item_by_index(&Font_files_list,selected_font); - new_font = Load_font(fontName->Full_name); + new_font = Load_font(fontName->Full_name, 1); if (new_font) { free(Menu_font); @@ -1498,7 +1498,7 @@ void Button_Skins(void) Set_current_skin(skinsdir, gfx); } // (Re-)load the selected font - new_font = Load_font(Get_item_by_index(&Font_files_list,selected_font)->Full_name); + new_font = Load_font(Get_item_by_index(&Font_files_list,selected_font)->Full_name, 1); if (new_font) { const char * fname; diff --git a/src/global.h b/src/global.h index 6b669065..8ddbd191 100644 --- a/src/global.h +++ b/src/global.h @@ -646,6 +646,9 @@ GFX2_GLOBAL byte Resolution_in_command_line; /// Pointer to the font selected for menus. GFX2_GLOBAL byte * Menu_font; +/// additional fonts for unicode characters +GFX2_GLOBAL T_Unicode_Font * Unicode_fonts; + /// Pointer to the current active skin. GFX2_GLOBAL T_Gui_skin * Gfx; diff --git a/src/init.c b/src/init.c index 4b34a50c..a300227b 100644 --- a/src/init.c +++ b/src/init.c @@ -701,27 +701,36 @@ T_Gui_skin * Load_graphics(const char * skin_file, T_Gradient_array *gradients) // ---- font loading ----- -byte Parse_font(SDL_Surface * image, byte * font) +static byte * Parse_font(SDL_Surface * image, int is_main) { + byte * font; int character; byte color; int x, y; int chars_per_line; + int character_count; // Check image size if (image->w % 8) { sprintf(Gui_loading_error_message, "Error in font file: Image width is not a multiple of 8.\n"); - return 1; + return NULL; } - if (image->w * image->h < 8*8*256) + character_count = (image->w * image->h) / (8*8); + if (is_main && character_count < 256) { sprintf(Gui_loading_error_message, "Error in font file: Image is too small to be a 256-character 8x8 font.\n"); - return 1; + return NULL; + } + font = (byte *)malloc(8*8*character_count); + if (font == NULL) + { + sprintf(Gui_loading_error_message, "Not enough memory to read font file\n"); + return NULL; } chars_per_line = image->w/8; - for (character=0; character < 256; character++) + for (character=0; character < character_count; character++) { for (y=0; y<8; y++) { @@ -732,19 +741,20 @@ byte Parse_font(SDL_Surface * image, byte * font) if (color > 1) { sprintf(Gui_loading_error_message, "Error in font file: Only colors 0 and 1 can be used for the font.\n"); - return 1; + free(font); + return NULL; } // Put it in font. 0 = BG, 1 = FG. font[character*64 + y*8 + x]=color; } } } - return 0; + return font; } -byte * Load_font(const char * font_name) +byte * Load_font(const char * font_name, int is_main) { - byte * font; + byte * font = NULL; char filename[MAX_PATH_CHARACTERS]; SDL_Surface * image; @@ -754,13 +764,6 @@ byte * Load_font(const char * font_name) return NULL; } - font = (byte *)malloc(8*8*256); - if (font == NULL) - { - sprintf(Gui_loading_error_message, "Not enough memory to read font file\n"); - return NULL; - } - // Read the file containing the image sprintf(filename,"%s" SKINS_SUBDIRECTORY "%s%s", Data_directory, PATH_SEPARATOR, font_name); @@ -768,19 +771,41 @@ byte * Load_font(const char * font_name) if (!image) { sprintf(Gui_loading_error_message, "Unable to load the skin image (missing? not an image file?)\n"); - free(font); - return NULL; - } - if (Parse_font(image, font)) - { - SDL_FreeSurface(image); - free(font); return NULL; } + font = Parse_font(image, is_main); SDL_FreeSurface(image); return font; } +static void Load_Unicode_font(const char * filename) +{ + T_Unicode_Font * ufont; + byte * font; + unsigned int first, last; + + if (sscanf(filename, "unicode_%04X-%04X.png", &first, &last) == 2) + { + font = Load_font(filename, 0); + if (font) + { + ufont = malloc(sizeof(T_Unicode_Font)); + ufont->FirstChar = first; + ufont->LastChar = last; + ufont->FontData = font; + ufont->Next = Unicode_fonts; + Unicode_fonts = ufont; + } + } + else + Warning("Could not parse filename"); +} + +void Load_Unicode_fonts(void) +{ + // TODO : for each unicode*.png file in skin directory + Load_Unicode_font("unicode_0410-044F.png"); +} // Initialisation des boutons: diff --git a/src/init.h b/src/init.h index 14714cac..eafcc214 100644 --- a/src/init.h +++ b/src/init.h @@ -47,4 +47,7 @@ extern char Gui_loading_error_message[512]; /// successful. /// If an error is encountered, it frees what needs it, prints an error message /// in ::Gui_loading_error_message, and returns NULL. -byte * Load_font(const char * font_name); +byte * Load_font(const char * font_name, int is_main); + +/// Load fonts for additional Unicode characters +void Load_Unicode_fonts(void); diff --git a/src/main.c b/src/main.c index 3d96e27d..4efa10ad 100644 --- a/src/main.c +++ b/src/main.c @@ -745,12 +745,13 @@ int Init_program(int argc,char * argv[]) Copy_preset_sieve(0); // Font - if (!(Menu_font=Load_font(Config.Font_file))) - if (!(Menu_font=Load_font(DEFAULT_FONT_FILENAME))) + if (!(Menu_font=Load_font(Config.Font_file, 1))) + if (!(Menu_font=Load_font(DEFAULT_FONT_FILENAME, 1))) { printf("Unable to open the default font file: %s\n", DEFAULT_FONT_FILENAME); Error(ERROR_GUI_MISSING); } + Load_Unicode_fonts(); memcpy(Main.palette, Gfx->Default_palette, sizeof(T_Palette)); @@ -993,6 +994,16 @@ void Program_shutdown(void) free(Gfx); Gfx=NULL; + free(Menu_font); + Menu_font = NULL; + while (Unicode_fonts != NULL) + { + T_Unicode_Font * ufont = Unicode_fonts->Next; + free(Unicode_fonts->FontData); + free(Unicode_fonts); + Unicode_fonts = ufont; + } + // On prend bien soin de passer dans le répertoire initial: if (chdir(Initial_directory)!=-1) { diff --git a/src/struct.h b/src/struct.h index e85d4f81..1e6177ba 100644 --- a/src/struct.h +++ b/src/struct.h @@ -549,7 +549,7 @@ typedef struct T_Selector_settings char Directory[MAX_PATH_CHARACTERS]; ///< Directory currently browsed } T_Selector_settings; -// structure for Main or Spare page global data +/// structure for Main or Spare page global data typedef struct { /// Palette @@ -618,4 +618,12 @@ typedef struct T_List_of_pages * backups; } T_Document; +typedef struct T_Unicode_Font +{ + struct T_Unicode_Font * Next; + dword FirstChar; + dword LastChar; + byte * FontData; +} T_Unicode_Font; + #endif diff --git a/src/unicode.c b/src/unicode.c new file mode 100644 index 00000000..3517d7b6 --- /dev/null +++ b/src/unicode.c @@ -0,0 +1,81 @@ +/* vim:expandtab:ts=2 sw=2: +*/ +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2018 Thomas Bernard + Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) + + Grafx2 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; version 2 + of the License. + + Grafx2 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 Grafx2; if not, see +*/ + +#include +#include + +#include "unicode.h" + +size_t Unicode_strlen(const word * str) +{ + size_t len; + + len = 0; + while(str[len] != 0) + len++; + return len; +} + +/// equivalent of strdup() for our Unicode strings +word * Unicode_strdup(const word * str) +{ + size_t byte_size; + word * new_str; + + byte_size = Unicode_strlen(str) * 2 + 2; + new_str = malloc(byte_size); + if (new_str != NULL) + memcpy(new_str, str, byte_size); + return new_str; +} + +/// Compare an unicode string with a regular Latin1 string +int Unicode_char_strcmp(const word * s1, const char * s2) +{ + const byte * str2 = (const byte *)s2; + + while (*s1 == *str2) + { + if (*s1 == 0) return 0; + s1++; + str2++; + } + return (*s1 > *str2) ? 1 : -1; +} + +/// Copy a regular Latin1 string to an unicode string +void Unicode_char_strlcpy(word * dst, const char * src, size_t len) +{ + const byte * s = (const byte *)src; + + if (len == 0) + return; + while (len > 1) + { + *dst = *s; + if (*s == '\0') + return; + dst++; + s++; + len--; + } + *dst = 0; +} diff --git a/src/unicode.h b/src/unicode.h new file mode 100644 index 00000000..c3948904 --- /dev/null +++ b/src/unicode.h @@ -0,0 +1,39 @@ +/* vim:expandtab:ts=2 sw=2: +*/ +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2018 Thomas Bernard + Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) + + Grafx2 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; version 2 + of the License. + + Grafx2 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 Grafx2; if not, see +*/ +#ifndef UNICODE_H_INCLUDED +#define UNICODE_H_INCLUDED + +#include "struct.h" + +/// equivalent of strlen() for out Unicode strings +/// return the number of characters (words), so there is twice as much bytes +size_t Unicode_strlen(const word * str); + +/// equivalent of strdup() for our Unicode strings +word * Unicode_strdup(const word * str); + +/// Compare an unicode string with a regular Latin1 string +int Unicode_char_strcmp(const word * s1, const char * s2); + +/// Copy a regular Latin1 string to an unicode string +void Unicode_char_strlcpy(word * dst, const char * src, size_t len); + +#endif diff --git a/src/windows.c b/src/windows.c index 60d08bb2..60540bbb 100644 --- a/src/windows.c +++ b/src/windows.c @@ -708,13 +708,25 @@ void Print_general(short x,short y,const char * str,byte text_color,byte backgro } /// Draws a char in a window -void Print_char_in_window(short x_pos,short y_pos,const unsigned char c,byte text_color,byte background_color) +void Print_char_in_window(short x_pos, short y_pos, unsigned int c,byte text_color,byte background_color) { short x,y; - byte *pixel; + const byte *pixel; // Premier pixel du caractère - pixel=Menu_font + (c<<6); - + if (c < 256) + pixel=Menu_font + (c<<6); + else + { + T_Unicode_Font * ufont; + pixel=Menu_font + (1<<6); // dummy character + for (ufont = Unicode_fonts; ufont != NULL; ufont = ufont->Next) + if (ufont->FirstChar <= c && c <= ufont->LastChar) + { + pixel = ufont->FontData + ((c - ufont->FirstChar) << 6); + break; + } + } + for (y=0;y<8;y++) for (x=0;x<8;x++) Pixel_in_window(x_pos+x, y_pos+y, @@ -739,16 +751,31 @@ void Print_in_window_limited(short x,short y,const char * str,byte size,byte tex void Print_in_window(short x,short y,const char * str,byte text_color,byte background_color) { short x_pos = x; - int index; + const unsigned char * p = (const unsigned char *)str; - for (index=0;str[index]!='\0';index++) + while (*p !='\0') { - Print_char_in_window(x,y,str[index],text_color,background_color); + Print_char_in_window(x,y,*p++,text_color,background_color); x+=8; } - Update_window_area(x_pos,y,8*strlen(str),8); + Update_window_area(x_pos,y,x-x_pos,8); } +/// Draws a string in a window +void Print_in_window_utf16(short x,short y,const word * str,byte text_color,byte background_color) +{ + short x_pos = x; + const word * p = str; + + while (*p != 0) + { + Print_char_in_window(x,y,*p++,text_color,background_color); + x+=8; + } + Update_window_area(x_pos,y,x-x_pos,8); +} + + // Draws a string in the menu's status bar void Print_in_menu(const char * str, short position) { diff --git a/src/windows.h b/src/windows.h index 0b2ea718..91569587 100644 --- a/src/windows.h +++ b/src/windows.h @@ -67,8 +67,9 @@ word Palette_cells_Y(void); void Print_general(short x,short y,const char * str,byte text_color,byte background_color); void Print_in_window(short x,short y,const char * str,byte text_color,byte background_color); +void Print_in_window_utf16(short x,short y,const word * str,byte text_color,byte background_color); void Print_in_window_limited(short x,short y,const char * str,byte size,byte text_color,byte background_color); -void Print_char_in_window(short x_pos,short y_pos,const unsigned char c,byte text_color,byte background_color); +void Print_char_in_window(short x_pos,short y_pos, unsigned int c,byte text_color,byte background_color); void Print_in_menu(const char * str, short position); void Print_coordinates(void); void Print_filename(void);