1
C / Unicode limited to Plane 0 (U+0000 to U+FFFF) in (C)SFML?
« on: July 12, 2022, 12:25:37 pm »
Hi,
I started with CSFML a couple of weeks ago.
I am *not* using SFML but only the C binding, so questions and reports here may or may not also apply to SFML itself.
I just don't know, :-).
When I came to unicode strings I first had to manage some hurdles as my programs(s) should run in a Windows an a Linux enviroment, and handling the locales and wide characters is not alway funny then.
Especially, I miss the UTF_X_toUTF_Y conversion functions in the C binding.
You may consider to add them in a future release ...
But of course, this can also manually be done.
But when I wanted to set a unicode string to an sfText ('sfText_setUnicodeString()') I had to realize that CSFML doesn't accept unicode characters on higher planes beyond U+FFFF.
So I decided to get the character by the font itself (see example below) - same result.
Good for testing is the unicode font 'unifont' from https://www.unifoundry.com/unifont/index.html that virtually contains an image for (nearly) every single code point.
My 'test character' is U+1D11E ('Musical Symbol G Clef') but you'll find that no unicode character at all will work in (C)SFML beyond 'U+FFFF'.
Is this a bug or by design? But if it's by design - why use 4 byte long sfUint32 integers to handle them ...?
I started with CSFML a couple of weeks ago.
I am *not* using SFML but only the C binding, so questions and reports here may or may not also apply to SFML itself.
I just don't know, :-).
When I came to unicode strings I first had to manage some hurdles as my programs(s) should run in a Windows an a Linux enviroment, and handling the locales and wide characters is not alway funny then.
Especially, I miss the UTF_X_toUTF_Y conversion functions in the C binding.
You may consider to add them in a future release ...
But of course, this can also manually be done.
But when I wanted to set a unicode string to an sfText ('sfText_setUnicodeString()') I had to realize that CSFML doesn't accept unicode characters on higher planes beyond U+FFFF.
So I decided to get the character by the font itself (see example below) - same result.
Good for testing is the unicode font 'unifont' from https://www.unifoundry.com/unifont/index.html that virtually contains an image for (nearly) every single code point.
My 'test character' is U+1D11E ('Musical Symbol G Clef') but you'll find that no unicode character at all will work in (C)SFML beyond 'U+FFFF'.
Is this a bug or by design? But if it's by design - why use 4 byte long sfUint32 integers to handle them ...?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <SFML/Graphics.h>
sfRenderWindow* window;
void selectGlyph(void *data)
{
sfUint32 *codePoint = data;
char buffer[8];
while(sfRenderWindow_isOpen(window))
{
printf("Enter hexadecimal code point: ");
do
{
fgets(buffer, 8, stdin);
} while (strcspn(buffer, "\n") == 7);
*codePoint = strtoul(buffer, NULL, 16);
}
}
int main(void)
{
sfVideoMode mode = {160, 160, 32};
sfTexture* texture;
sfSprite* sprite;
sfEvent event;
sfColor bColor;
sfUint32 codePoint = 0x0000;
sfUint32 oldCodePt = 0xFFFF;
sfThread *thread = sfThread_create(selectGlyph, &codePoint);
/* Create the main window */
window = sfRenderWindow_create(mode, "CSFML Unicode Test", (sfDefaultStyle), NULL);
if (!window)
return EXIT_FAILURE;
sfRenderWindow_setVerticalSyncEnabled(window, sfTrue);
sfRenderWindow_setPosition(window, (sfVector2i){50, 50});
/* Create a graphical text to display */
sfFont *font = sfFont_createFromFile("unifont-14.0.04.ttf");
if (!font)
return EXIT_FAILURE;
unsigned int size = 160;
sfThread_launch(thread);
/* Start the game loop */
while (sfRenderWindow_isOpen(window))
{
/* Process events */
while (sfRenderWindow_pollEvent(window, &event))
{
/* Close window : exit */
if (event.type == sfEvtClosed)
sfRenderWindow_close(window);
}
if(codePoint != oldCodePt)
{
sfGlyph glyph = sfFont_getGlyph(font, codePoint, size, sfFalse, 0);
const sfTexture *bitmap = sfFont_getTexture(font, size);
if (!bitmap)
return EXIT_FAILURE;
sfImage *chr = sfTexture_copyToImage(bitmap);
if(glyph.bounds.width > 0 && glyph.bounds.height > 0)
{
sfImage *image = sfImage_create(glyph.bounds.width, glyph.bounds.height);
sfImage_copyImage(image, chr, 0, 0, glyph.textureRect, sfFalse);
texture = sfTexture_createFromImage(image, NULL);
if (!texture)
return EXIT_FAILURE;
sprite = sfSprite_create();
if (!sprite)
return EXIT_FAILURE;
sfSprite_setColor(sprite, sfBlue);
sfSprite_setTexture(sprite, texture, sfFalse);
oldCodePt = codePoint;
bColor = codePoint ? sfYellow : sfRed;
}
else
codePoint = 0;
}
sfRenderWindow_clear(window, bColor);
/* Draw the sprite */
sfRenderWindow_drawSprite(window, sprite, NULL);
/* Update the window */
sfRenderWindow_display(window);
}
/* Cleanup resources */
sfThread_destroy(thread);
sfSprite_destroy(sprite);
sfTexture_destroy(texture);
sfFont_destroy(font);
sfRenderWindow_destroy(window);
return EXIT_SUCCESS;
}
#include <stdlib.h>
#include <string.h>
#include <SFML/Graphics.h>
sfRenderWindow* window;
void selectGlyph(void *data)
{
sfUint32 *codePoint = data;
char buffer[8];
while(sfRenderWindow_isOpen(window))
{
printf("Enter hexadecimal code point: ");
do
{
fgets(buffer, 8, stdin);
} while (strcspn(buffer, "\n") == 7);
*codePoint = strtoul(buffer, NULL, 16);
}
}
int main(void)
{
sfVideoMode mode = {160, 160, 32};
sfTexture* texture;
sfSprite* sprite;
sfEvent event;
sfColor bColor;
sfUint32 codePoint = 0x0000;
sfUint32 oldCodePt = 0xFFFF;
sfThread *thread = sfThread_create(selectGlyph, &codePoint);
/* Create the main window */
window = sfRenderWindow_create(mode, "CSFML Unicode Test", (sfDefaultStyle), NULL);
if (!window)
return EXIT_FAILURE;
sfRenderWindow_setVerticalSyncEnabled(window, sfTrue);
sfRenderWindow_setPosition(window, (sfVector2i){50, 50});
/* Create a graphical text to display */
sfFont *font = sfFont_createFromFile("unifont-14.0.04.ttf");
if (!font)
return EXIT_FAILURE;
unsigned int size = 160;
sfThread_launch(thread);
/* Start the game loop */
while (sfRenderWindow_isOpen(window))
{
/* Process events */
while (sfRenderWindow_pollEvent(window, &event))
{
/* Close window : exit */
if (event.type == sfEvtClosed)
sfRenderWindow_close(window);
}
if(codePoint != oldCodePt)
{
sfGlyph glyph = sfFont_getGlyph(font, codePoint, size, sfFalse, 0);
const sfTexture *bitmap = sfFont_getTexture(font, size);
if (!bitmap)
return EXIT_FAILURE;
sfImage *chr = sfTexture_copyToImage(bitmap);
if(glyph.bounds.width > 0 && glyph.bounds.height > 0)
{
sfImage *image = sfImage_create(glyph.bounds.width, glyph.bounds.height);
sfImage_copyImage(image, chr, 0, 0, glyph.textureRect, sfFalse);
texture = sfTexture_createFromImage(image, NULL);
if (!texture)
return EXIT_FAILURE;
sprite = sfSprite_create();
if (!sprite)
return EXIT_FAILURE;
sfSprite_setColor(sprite, sfBlue);
sfSprite_setTexture(sprite, texture, sfFalse);
oldCodePt = codePoint;
bColor = codePoint ? sfYellow : sfRed;
}
else
codePoint = 0;
}
sfRenderWindow_clear(window, bColor);
/* Draw the sprite */
sfRenderWindow_drawSprite(window, sprite, NULL);
/* Update the window */
sfRenderWindow_display(window);
}
/* Cleanup resources */
sfThread_destroy(thread);
sfSprite_destroy(sprite);
sfTexture_destroy(texture);
sfFont_destroy(font);
sfRenderWindow_destroy(window);
return EXIT_SUCCESS;
}