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();

View file

@ -121,6 +121,19 @@ static int gfx_get3D(lua_State *L) {
return 1;
}
/***
Enable or disable the VBlank waiting.
@function setVBlankWait
@tparam boolean true to enable, false to disable
*/
static int gfx_setVBlankWait(lua_State *L) {
bool enable = lua_toboolean(L, 1);
sf2d_set_vblank_wait(enable);
return 0;
}
/***
Get free VRAM space.
@function vramSpaceFree
@ -255,20 +268,94 @@ static int gfx_text(lua_State *L) {
return 0;
}
/***
Draw a text with a new line after a certain number of pixels.
Warning: No UTF32 support.
@function wrappedText
@tparam integer x text drawing origin horizontal coordinate, in pixels
@tparam integer y text drawing origin vertical coordinate, in pixels
@tparam string text the text to draw
@tparam integer width width of a line, in pixels
@tparam[opt=9] integer size drawing size, in pixels
@tparam[opt=default color] integer color drawing color
@tparam[opt=default font] font font to use
*/
static int gfx_wrappedText(lua_State *L) {
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
size_t len;
const char *text = luaL_checklstring(L, 3, &len);
unsigned int lineWidth = luaL_checkinteger(L, 4);
int size = luaL_optinteger(L, 5, 9);
u32 color = luaL_optinteger(L, 6, color_default);
font_userdata *font = luaL_testudata(L, 7, "LFont");
if (font == NULL) {
lua_getfield(L, LUA_REGISTRYINDEX, "LFontDefault");
font = luaL_testudata(L, -1, "LFont");
if (font == NULL) luaL_error(L, "No default font set and no font object passed");
}
if (font->font == NULL) luaL_error(L, "The font object was unloaded");
// Wide caracters support. (wchar = UTF32 on 3DS.)
// Disabled as sftd_draw_wtext_wrap() doesn't exist.
/*wchar_t wtext[len];
len = mbstowcs(wtext, text, len);
*(wtext+len) = 0x0; // text end */
sftd_draw_text_wrap(font->font, x, y, color, size, lineWidth, text);
return 0;
}
/***
Calculate the size of a text draw with `wrappedText`.
@function calcBoundingBox
@tparam string text The text to check
@tparam integer lineWidth width of a line, in pixels
@tparam[opt=9] integer size drawing size, in pixels
@tparam[opt=default font] font font to use
@treturn integer width of the text, in pixels
@treturn integer height of the text, in pixels
*/
static int gfx_calcBoundingBox(lua_State *L) {
size_t len;
const char *text = luaL_checklstring(L, 1, &len);
unsigned int lineWidth = luaL_checkinteger(L, 2);
int size = luaL_optinteger(L, 3, 9);
font_userdata *font = luaL_testudata(L, 4, "LFont");
if (font == NULL) {
lua_getfield(L, LUA_REGISTRYINDEX, "LFontDefault");
font = luaL_testudata(L, -1, "LFont");
if (font == NULL) luaL_error(L, "No default font set and no font object passed");
}
if (font->font == NULL) luaL_error(L, "The font object was unloaded");
int w, h = 0;
sftd_calc_bounding_box(&w, &h, font->font, size, lineWidth, text);
lua_pushinteger(L, w);
lua_pushinteger(L, h);
return 2;
}
// Functions
static const struct luaL_Reg gfx_lib[] = {
{ "startFrame", gfx_startFrame },
{ "endFrame", gfx_endFrame },
{ "render", gfx_render },
{ "getFPS", gfx_getFPS },
{ "set3D", gfx_set3D },
{ "get3D", gfx_get3D },
{ "vramSpaceFree", gfx_vramSpaceFree },
{ "line", gfx_line },
{ "point", gfx_point },
{ "rectangle", gfx_rectangle },
{ "circle", gfx_circle },
{ "text", gfx_text },
{ "startFrame", gfx_startFrame },
{ "endFrame", gfx_endFrame },
{ "render", gfx_render },
{ "getFPS", gfx_getFPS },
{ "set3D", gfx_set3D },
{ "get3D", gfx_get3D },
{ "setVBlankWait", gfx_setVBlankWait },
{ "vramSpaceFree", gfx_vramSpaceFree },
{ "line", gfx_line },
{ "point", gfx_point },
{ "rectangle", gfx_rectangle },
{ "circle", gfx_circle },
{ "text", gfx_text },
{ "wrappedText", gfx_wrappedText },
{ "calcBoundingBox", gfx_calcBoundingBox },
{ NULL, NULL }
};

View file

@ -76,6 +76,35 @@ static int texture_load(lua_State *L) {
return 1;
}
/***
Create an empty texture.
@function new
@tparam number width Texture width
@tparam number height Texture height
@tparam[opt=PLACE_RAM] number place where to put the loaded texture
@treturn texture the loaded texture object
*/
static int texture_new(lua_State *L) {
int w = luaL_checkinteger(L, 1);
int h = luaL_checkinteger(L, 2);
u8 place = luaL_checkinteger(L, 3);
texture_userdata *texture;
texture = (texture_userdata *)lua_newuserdata(L, sizeof(*texture));
luaL_getmetatable(L, "LTexture");
lua_setmetatable(L, -2);
texture->texture = sf2d_create_texture(w, h, TEXFMT_RGBA8, place);
sf2d_texture_tile32(texture->texture);
texture->scaleX = 1.0f;
texture->scaleY = 1.0f;
texture->blendColor = 0xffffffff;
return 1;
}
/***
Texture object
@section Methods
@ -242,6 +271,7 @@ static const struct luaL_Reg texture_methods[] = {
// module
static const struct luaL_Reg texture_functions[] = {
{"load", texture_load},
{"new", texture_new },
{NULL, NULL}
};