1
0
Fork 0
mirror of https://github.com/ctruLua/ctruLua.git synced 2025-10-27 16:39:29 +00:00

Updated the sftdlib, Added some functions in gfx and gfx.texture

This commit is contained in:
Firew0lf 2015-10-09 00:02:23 +02:00
parent c5337a5b2e
commit dcdeec6525
5 changed files with 484 additions and 48 deletions

View file

@ -105,6 +105,50 @@ void sftd_draw_wtext(sftd_font *font, int x, int y, unsigned int color, unsigned
*/
void sftd_draw_wtextf(sftd_font *font, int x, int y, unsigned int color, unsigned int size, const wchar_t *text, ...);
/**
* @brief Returns the width of the given text in pixels
* @param font the font used to calculate the width
* @param size the font size
* @param text a pointer to the text that will be used to calculate the length
*/
int sftd_get_text_width(sftd_font *font, unsigned int size, const char *text);
/**
* @brief Draws text using a font. The text will wrap after the pixels specified in lineWidth.
* @param font the font to use
* @param x the x coordinate to draw the text to
* @param y the y coordinate to draw the text to
* @param color the color to draw the font
* @param size the font size
* @param lineWidth The length of one line before a line break accours.
* @param text a pointer to the text to draw
*/
void sftd_draw_text_wrap(sftd_font *font, int x, int y, unsigned int color, unsigned int size, unsigned int lineWidth, const char *text);
/**
* @brief Calculates the bounding box of the text wih the given attributes.
* @param boundingWidth Pointer to the address where the width will be stored.
* @param boundingHeight Pointer to the address where the height will be stored.
* @param font the font to use
* @param size the font size
* @param lineWidth The length of one line before a line break accours.
* @param text a pointer to the text to draw
*/
void sftd_calc_bounding_box(int *boundingWidth, int *boundingHeight, sftd_font *font, unsigned int size, unsigned int lineWidth, const char *text);
/**
* @brief Draws formatted text using a font. The text will wrap after the pixels specified in lineWidth.
* @param font the font to use
* @param x the x coordinate to draw the text to
* @param y the y coordinate to draw the text to
* @param color the color to draw the font
* @param size the font size
* @param lineWidth The length of one line before a line break accours.
* @param text a pointer to the text to draw
* @param ... variable arguments
*/
void sftd_draw_textf_wrap(sftd_font *font, int x, int y, unsigned int color, unsigned int size, unsigned int lineWidth, const char *text, ...);
// (ctruLua addition) Based on sftd_draw_wtext, returns the width of the text drawn.
int sftd_width_wtext(sftd_font *font, unsigned int size, const wchar_t *text);

View file

@ -4,6 +4,7 @@
#include <wchar.h>
#include <sf2d.h>
#include <ft2build.h>
#include <string.h>
#include FT_CACHE_H
#include FT_FREETYPE_H
@ -28,6 +29,7 @@ struct sftd_font {
unsigned int buffer_size;
};
};
FTC_Manager ftcmanager;
FTC_CMapCache cmapcache;
FTC_ImageCache imagecache;
texture_atlas *tex_atlas;
@ -65,20 +67,6 @@ int sftd_init()
return 0;
}
error = FTC_Manager_New(
ftlibrary,
0, /* use default */
0, /* use default */
0, /* use default */
&ftc_face_requester, /* use our requester */
NULL, /* user data */
&ftcmanager);
if (error != FT_Err_Ok) {
FT_Done_FreeType(ftlibrary);
return 0;
}
sftd_initialized = 1;
return 1;
}
@ -92,15 +80,17 @@ int sftd_fini()
return 0;
}
FTC_Manager_Done(ftcmanager);
sftd_initialized = 0;
return 1;
}
sftd_font *sftd_load_font_file(const char *filename)
{
FT_Error error;
sftd_font *font = malloc(sizeof(*font));
if (!font)
return NULL;
size_t len = strlen(filename);
@ -108,8 +98,23 @@ sftd_font *sftd_load_font_file(const char *filename)
strcpy(font->filename, filename);
font->filename[len] = '\0';
FTC_CMapCache_New(ftcmanager, &font->cmapcache);
FTC_ImageCache_New(ftcmanager, &font->imagecache);
error = FTC_Manager_New(
ftlibrary,
0, /* use default */
0, /* use default */
0, /* use default */
&ftc_face_requester, /* use our requester */
NULL, /* user data */
&font->ftcmanager);
if (error != FT_Err_Ok) {
free(font->filename);
free(font);
return NULL;
}
FTC_CMapCache_New(font->ftcmanager, &font->cmapcache);
FTC_ImageCache_New(font->ftcmanager, &font->imagecache);
font->from = SFTD_LOAD_FROM_FILE;
font->tex_atlas = texture_atlas_create(ATLAS_DEFAULT_W, ATLAS_DEFAULT_H,
@ -120,12 +125,31 @@ sftd_font *sftd_load_font_file(const char *filename)
sftd_font *sftd_load_font_mem(const void *buffer, unsigned int size)
{
FT_Error error;
sftd_font *font = malloc(sizeof(*font));
if (!font)
return NULL;
font->font_buffer = buffer;
font->buffer_size = size;
FTC_CMapCache_New(ftcmanager, &font->cmapcache);
FTC_ImageCache_New(ftcmanager, &font->imagecache);
error = FTC_Manager_New(
ftlibrary,
0, /* use default */
0, /* use default */
0, /* use default */
&ftc_face_requester, /* use our requester */
NULL, /* user data */
&font->ftcmanager);
if (error != FT_Err_Ok) {
free(font);
return NULL;
}
FTC_CMapCache_New(font->ftcmanager, &font->cmapcache);
FTC_ImageCache_New(font->ftcmanager, &font->imagecache);
font->from = SFTD_LOAD_FROM_MEM;
font->tex_atlas = texture_atlas_create(ATLAS_DEFAULT_W, ATLAS_DEFAULT_H,
@ -138,7 +162,8 @@ void sftd_free_font(sftd_font *font)
{
if (font) {
FTC_FaceID face_id = (FTC_FaceID)font;
FTC_Manager_RemoveFaceID(ftcmanager, face_id);
FTC_Manager_RemoveFaceID(font->ftcmanager, face_id);
FTC_Manager_Done(font->ftcmanager);
if (font->from == SFTD_LOAD_FROM_FILE) {
free(font->filename);
}
@ -183,7 +208,7 @@ void sftd_draw_text(sftd_font *font, int x, int y, unsigned int color, unsigned
{
FTC_FaceID face_id = (FTC_FaceID)font;
FT_Face face;
FTC_Manager_LookupFace(ftcmanager, face_id, &face);
FTC_Manager_LookupFace(font->ftcmanager, face_id, &face);
FT_Int charmap_index;
charmap_index = FT_Get_Charmap_Index(face->charmap);
@ -245,6 +270,7 @@ void sftd_draw_text(sftd_font *font, int x, int y, unsigned int color, unsigned
text++;
}
}
void sftd_draw_textf(sftd_font *font, int x, int y, unsigned int color, unsigned int size, const char *text, ...)
{
char buffer[256];
@ -259,7 +285,7 @@ void sftd_draw_wtext(sftd_font *font, int x, int y, unsigned int color, unsigned
{
FTC_FaceID face_id = (FTC_FaceID)font;
FT_Face face;
FTC_Manager_LookupFace(ftcmanager, face_id, &face);
FTC_Manager_LookupFace(font->ftcmanager, face_id, &face);
FT_Int charmap_index;
charmap_index = FT_Get_Charmap_Index(face->charmap);
@ -332,6 +358,260 @@ void sftd_draw_wtextf(sftd_font *font, int x, int y, unsigned int color, unsigne
va_end(args);
}
int sftd_get_text_width(sftd_font *font, unsigned int size, const char *text)
{
FTC_FaceID face_id = (FTC_FaceID)font;
FT_Face face;
FTC_Manager_LookupFace(font->ftcmanager, face_id, &face);
FT_Int charmap_index;
charmap_index = FT_Get_Charmap_Index(face->charmap);
FT_Glyph glyph;
FT_Bool use_kerning = FT_HAS_KERNING(face);
FT_UInt glyph_index, previous = 0;
int pen_x = 0;
int pen_y = size;
FTC_ScalerRec scaler;
scaler.face_id = face_id;
scaler.width = size;
scaler.height = size;
scaler.pixel = 1;
FT_ULong flags = FT_LOAD_RENDER | FT_LOAD_TARGET_NORMAL;
while (*text) {
glyph_index = FTC_CMapCache_Lookup(font->cmapcache, (FTC_FaceID)font, charmap_index, *text);
if (use_kerning && previous && glyph_index) {
FT_Vector delta;
FT_Get_Kerning(face, previous, glyph_index, FT_KERNING_DEFAULT, &delta);
pen_x += delta.x >> 6;
}
if (!texture_atlas_exists(font->tex_atlas, glyph_index)) {
FTC_ImageCache_LookupScaler(font->imagecache, &scaler, flags, glyph_index, &glyph, NULL);
if (!atlas_add_glyph(font->tex_atlas, glyph_index, (FT_BitmapGlyph)glyph, size)) {
continue;
}
}
bp2d_rectangle rect;
int bitmap_left, bitmap_top;
int advance_x, advance_y;
int glyph_size;
texture_atlas_get(font->tex_atlas, glyph_index,
&rect, &bitmap_left, &bitmap_top,
&advance_x, &advance_y, &glyph_size);
const float draw_scale = size/(float)glyph_size;
pen_x += (advance_x >> 16) * draw_scale;
pen_y += (advance_y >> 16) * draw_scale;
previous = glyph_index;
text++;
}
return pen_x;
}
void sftd_draw_text_wrap(sftd_font *font, int x, int y, unsigned int color, unsigned int size, unsigned int lineWidth, const char *text)
{
FTC_FaceID face_id = (FTC_FaceID)font;
FT_Face face;
FTC_Manager_LookupFace(font->ftcmanager, face_id, &face);
FT_Int charmap_index;
charmap_index = FT_Get_Charmap_Index(face->charmap);
FT_Glyph glyph;
FT_Bool use_kerning = FT_HAS_KERNING(face);
FT_UInt glyph_index, previous = 0;
int pen_x = x;
int pen_y = y + size;
FTC_ScalerRec scaler;
scaler.face_id = face_id;
scaler.width = size;
scaler.height = size;
scaler.pixel = 1;
FT_ULong flags = FT_LOAD_RENDER | FT_LOAD_TARGET_NORMAL;
bool isFirstLine = true;
char buffer[strlen(text)];
sprintf(buffer, text);
char *currentWord;
int currentWordLength;
int currentCharIndex;
currentWord = strtok(buffer, " ");
while (currentWord) {
currentWordLength = strlen(currentWord);
if(pen_x + sftd_get_text_width(font, size, currentWord) >= lineWidth && !isFirstLine) {
pen_x = x;
pen_y += size;
}
isFirstLine = false;
for(currentCharIndex = 0; currentCharIndex < currentWordLength + 1; currentCharIndex++) {
if(currentCharIndex < currentWordLength) {
glyph_index = FTC_CMapCache_Lookup(font->cmapcache, (FTC_FaceID)font, charmap_index, currentWord[currentCharIndex]);
}
else {
glyph_index = FTC_CMapCache_Lookup(font->cmapcache, (FTC_FaceID)font, charmap_index, ' ');
}
// TODO get word size and linewrap if needed
if (use_kerning && previous && glyph_index) {
FT_Vector delta;
FT_Get_Kerning(face, previous, glyph_index, FT_KERNING_DEFAULT, &delta);
pen_x += delta.x >> 6;
}
if (!texture_atlas_exists(font->tex_atlas, glyph_index)) {
FTC_ImageCache_LookupScaler(font->imagecache, &scaler, flags, glyph_index, &glyph, NULL);
if (!atlas_add_glyph(font->tex_atlas, glyph_index, (FT_BitmapGlyph)glyph, size)) {
continue;
}
}
bp2d_rectangle rect;
int bitmap_left, bitmap_top;
int advance_x, advance_y;
int glyph_size;
texture_atlas_get(font->tex_atlas, glyph_index,
&rect, &bitmap_left, &bitmap_top,
&advance_x, &advance_y, &glyph_size);
const float draw_scale = size/(float)glyph_size;
sf2d_draw_texture_part_scale_blend(font->tex_atlas->tex,
pen_x + bitmap_left * draw_scale,
pen_y - bitmap_top * draw_scale,
rect.x, rect.y, rect.w, rect.h,
draw_scale,
draw_scale,
color);
pen_x += (advance_x >> 16) * draw_scale;
pen_y += (advance_y >> 16) * draw_scale;
previous = glyph_index;
}
currentWord = strtok(NULL, " ");
}
}
void sftd_calc_bounding_box(int *boundingWidth, int *boundingHeight, sftd_font *font, unsigned int size, unsigned int lineWidth, const char *text)
{
FTC_FaceID face_id = (FTC_FaceID)font;
FT_Face face;
FTC_Manager_LookupFace(font->ftcmanager, face_id, &face);
FT_Int charmap_index;
charmap_index = FT_Get_Charmap_Index(face->charmap);
FT_Glyph glyph;
FT_Bool use_kerning = FT_HAS_KERNING(face);
FT_UInt glyph_index, previous = 0;
int pen_x = 0;
int pen_y = size;
FTC_ScalerRec scaler;
scaler.face_id = face_id;
scaler.width = size;
scaler.height = size;
scaler.pixel = 1;
FT_ULong flags = FT_LOAD_RENDER | FT_LOAD_TARGET_NORMAL;
bool isFirstLine = true;
char buffer[strlen(text)];
sprintf(buffer, text);
char *currentWord;
int currentWordLength;
int currentCharIndex;
int greatesLineWidth = 0;
currentWord = strtok(buffer, " ");
while (currentWord) {
currentWordLength = strlen(currentWord);
if(pen_x + sftd_get_text_width(font, size, currentWord) >= lineWidth && !isFirstLine) {
if(pen_x > greatesLineWidth) {
greatesLineWidth = pen_x;
}
pen_x = 0;
pen_y += size;
}
isFirstLine = false;
for(currentCharIndex = 0; currentCharIndex < currentWordLength + 1; currentCharIndex++) {
if(currentCharIndex < currentWordLength) {
glyph_index = FTC_CMapCache_Lookup(font->cmapcache, (FTC_FaceID)font, charmap_index, currentWord[currentCharIndex]);
}
else {
glyph_index = FTC_CMapCache_Lookup(font->cmapcache, (FTC_FaceID)font, charmap_index, ' ');
}
// TODO get word size and linewrap if needed
if (use_kerning && previous && glyph_index) {
FT_Vector delta;
FT_Get_Kerning(face, previous, glyph_index, FT_KERNING_DEFAULT, &delta);
pen_x += delta.x >> 6;
}
if (!texture_atlas_exists(font->tex_atlas, glyph_index)) {
FTC_ImageCache_LookupScaler(font->imagecache, &scaler, flags, glyph_index, &glyph, NULL);
if (!atlas_add_glyph(font->tex_atlas, glyph_index, (FT_BitmapGlyph)glyph, size)) {
continue;
}
}
bp2d_rectangle rect;
int bitmap_left, bitmap_top;
int advance_x, advance_y;
int glyph_size;
texture_atlas_get(font->tex_atlas, glyph_index,
&rect, &bitmap_left, &bitmap_top,
&advance_x, &advance_y, &glyph_size);
const float draw_scale = size/(float)glyph_size;
pen_x += (advance_x >> 16) * draw_scale;
pen_y += (advance_y >> 16) * draw_scale;
previous = glyph_index;
}
currentWord = strtok(NULL, " ");
}
*boundingWidth = greatesLineWidth;
*boundingHeight = pen_y;
}
void sftd_draw_textf_wrap(sftd_font *font, int x, int y, unsigned int color, unsigned int size, unsigned int lineWidth, const char *text, ...)
{
char buffer[256];
va_list args;
va_start(args, text);
vsnprintf(buffer, 256, text, args);
sftd_draw_text_wrap(font, x, y, color, size, lineWidth, buffer);
va_end(args);
}
// (ctruLua addition) Based on sftd_draw_wtext, returns the width of the text drawn.
int sftd_width_wtext(sftd_font *font, unsigned int size, const wchar_t *text)
{
@ -390,4 +670,4 @@ int sftd_width_wtext(sftd_font *font, unsigned int size, const wchar_t *text)
}
return pen_x;
}
}

View file

@ -16,6 +16,10 @@ int main()
sftd_init();
sftd_font *font = sftd_load_font_mem(FreeSans_ttf, FreeSans_ttf_size);
const char *someText = "Font drawing on the top screen! Text wraps after 300 pixels... Lorem ipsum dolor sit amet, consetetur sadipscing elit.";
int textWidth = 0;
int textHeight = 0;
while (aptMainLoop()) {
hidScanInput();
@ -24,18 +28,9 @@ int main()
sf2d_start_frame(GFX_TOP, GFX_LEFT);
sftd_draw_textf(font, 10, 10, RGBA8(0, 255, 0, 255), 20, "FPS %f", sf2d_get_fps());
sftd_draw_text(font, 10, 30, RGBA8(255, 0, 0, 255), 20, "Font drawing on the top screen!");
sftd_draw_text(font, 10, 50, RGBA8(0, 255, 0, 255), 15, "Font drawing on the top screen!");
sftd_draw_text(font, 10, 68, RGBA8(0, 0, 255, 255), 25, "Font drawing on the top screen!");
sftd_draw_text(font, 10, 90, RGBA8(255, 255, 0, 255), 10, "Font drawing on the top screen!");
sftd_draw_text(font, 10, 105, RGBA8(255, 0, 255, 255), 8, "Font drawing on the top screen!");
sftd_draw_text(font, 10, 120, RGBA8(0, 255, 255, 255), 30, "Font drawing on the top screen!");
sftd_draw_text(font, 10, 155, RGBA8(255, 0, 0, 255), 20, "Font drawing on the top screen!");
sftd_draw_text(font, 10, 170, RGBA8(0, 255, 0, 255), 2, "Font drawing on the top screen!");
sftd_draw_text(font, 10, 180, RGBA8(0, 0, 255, 255), 10, "Font drawing on the top screen!");
sftd_draw_text(font, 10, 205, RGBA8(255, 255, 0, 255), 170, "Font drawing on the top screen!");
sftd_calc_bounding_box(&textWidth, &textHeight, font, 20, 300, someText);
sf2d_draw_rectangle(10, 40, textWidth, textHeight, RGBA8(0, 100, 0, 255));
sftd_draw_text_wrap(font, 10, 40, RGBA8(255, 255, 255, 255), 20, 300, someText);
sf2d_end_frame();