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

Updated font and fs lib; updated editor; updated sf2dlib

Libs additions: font.load, font:unload, font:getWidth, fs.getDirectory, fs.setDirectory, fs.exists

Editor additions: syntaxic coloring and mono font

sf2dlib update: you will need the latest version of ctrulib.

Also, because of the lib font needs, the sftdlib was modified.
This commit is contained in:
Reuh 2015-09-05 19:00:36 +02:00
parent 3f995629c0
commit 45f3216ed8
14 changed files with 382 additions and 28 deletions

View file

@ -151,7 +151,7 @@ void sf2d_start_frame(gfxScreen_t screen, gfx3dSide_t side)
GPU_DepthMap(-1.0f, 0.0f);
GPU_SetFaceCulling(GPU_CULL_NONE);
GPU_SetStencilTest(false, GPU_ALWAYS, 0x00, 0xFF, 0x00);
GPU_SetStencilOp(GPU_KEEP, GPU_KEEP, GPU_KEEP);
GPU_SetStencilOp(GPU_STENCIL_KEEP, GPU_STENCIL_KEEP, GPU_STENCIL_KEEP);
GPU_SetBlendingColor(0,0,0,0);
GPU_SetDepthTestAndWriteMask(true, GPU_GEQUAL, GPU_WRITE_ALL);
GPUCMD_AddMaskedWrite(GPUREG_0062, 0x1, 0);

View file

@ -78,7 +78,13 @@ sf2d_texture *sf2d_create_texture(int width, int height, sf2d_texfmt pixel_forma
texture->data_size = data_size;
texture->data = data;
memset(texture->data, 0, texture->data_size);
if (place == SF2D_PLACE_VRAM) {
GX_SetMemoryFill(NULL, texture->data, 0x00000000, (u32*)&((u8*)texture->data)[texture->data_size], GX_FILL_TRIGGER | GX_FILL_32BIT_DEPTH,
NULL, 0x00000000, NULL, 0);
gspWaitForPSC0();
} else {
memset(texture->data, 0, texture->data_size);
}
return texture;
}

View file

@ -105,6 +105,8 @@ 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, ...);
// (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);
#ifdef __cplusplus
}

View file

@ -228,7 +228,7 @@ void sftd_draw_text(sftd_font *font, int x, int y, unsigned int color, unsigned
&rect, &bitmap_left, &bitmap_top,
&advance_x, &advance_y, &glyph_size);
const float draw_scale = glyph_size/(float)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,
@ -304,7 +304,7 @@ void sftd_draw_wtext(sftd_font *font, int x, int y, unsigned int color, unsigned
&rect, &bitmap_left, &bitmap_top,
&advance_x, &advance_y, &glyph_size);
const float draw_scale = (float)size/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,
@ -332,3 +332,62 @@ void sftd_draw_wtextf(sftd_font *font, int x, int y, unsigned int color, unsigne
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)
{
FTC_FaceID face_id = (FTC_FaceID)font;
FT_Face face;
FTC_Manager_LookupFace(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;
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;
previous = glyph_index;
text++;
}
return pen_x;
}

Binary file not shown.

View file

@ -1,6 +1,16 @@
-- Colors based on the Monokai theme
return {
background = 0x272822FF,
default = 0xF8F8F2FF,
cursor = 0xFF0000FF
-- General
["background"] = 0x272822FF,
["cursor"] = 0xF8F8F0FF,
["default"] = 0xF8F8F2FF,
-- Syntax
["comment"] = 0x75715EFF,
["string"] = 0xE6DB74FF,
["constant.numeric"] = 0xAE81FFFF,
["constant.language"] = 0xAE81FFFF,
["keyword.control"] = 0xF92672FF,
["keyword.operator"] = 0xF92672FF,
["support.function"] = 0x66D9EFFF
}

View file

@ -5,27 +5,45 @@ local gfx = require("ctr.gfx")
-- Open libs
local keyboard = dofile("sdmc:/3ds/ctruLua/keyboard.lua")
local openfile = dofile("sdmc:/3ds/ctruLua/openfile.lua")
local color = dofile("sdmc:/3ds/ctruLua/editor/color.lua")
local color = dofile("color.lua")
local syntax = dofile("syntax.lua")
-- Load data
local font = gfx.font.load("VeraMono.ttf")
-- Open file
local path, status = openfile("Choose a file to edit", "/3ds/ctruLua/", nil, "any")
if not path then return end
local lineEnding
local lines = {}
if status == "exist" then
for line in io.lines(path) do table.insert(lines, line) end
for line in io.lines(path, "L") do
if not lineEnding then lineEnding = line:match("([\n\r]+)$") end
table.insert(lines, line:match("^(.-)[\n\r]*$"))
end
else
lineEnding = "\n"
lines = { "" }
end
-- Syntax coloring
local coloredLines = syntax(lines, color)
-- Variables
local lineHeight = 10
local cursorX, cursorY = 1, 1
local scrollX, scrollY = 0, 0
-- Helper functions
local function displayedText(text)
return text:gsub("\t", " ")
end
-- Set defaults
gfx.set3D(false)
gfx.color.setDefault(color.default)
gfx.color.setBackground(color.background)
gfx.font.setDefault(font)
while ctr.run() do
hid.read()
@ -75,10 +93,10 @@ while ctr.run() do
until t + 5 < os.time()
else
for i = 1, #lines, 1 do
file:write(lines[i].."\n")
file:write(lines[i]..lineEnding)
gfx.startFrame(gfx.GFX_TOP)
gfx.rectangle(0, 0, math.ceil(i/#lines*gfx.TOP_WIDTH), gfx.TOP_HEIGHT, 0, 0xFFFFFFFF)
gfx.color.setDefault(0x000000FF)
gfx.color.setDefault(color.background)
gfx.text(gfx.TOP_WIDTH/2, gfx.TOP_HEIGHT/2, math.ceil(i/#lines*100).."%")
gfx.color.setDefault(color.default)
gfx.endFrame()
@ -122,6 +140,7 @@ while ctr.run() do
-- Draw
gfx.startFrame(gfx.GFX_TOP)
-- Lines
local sI = math.floor(scrollY / lineHeight)
if sI < 1 then sI = 1 end
@ -129,21 +148,30 @@ while ctr.run() do
if eI > #lines then eI = #lines end
for i = sI, eI, 1 do
local line = lines[i]
local x = -scrollX
local y = -scrollY+ (i-1)*lineHeight
if cursorY == i then
gfx.color.setDefault(color.cursor)
gfx.text(-scrollX, y, line:sub(1, (utf8.offset(line, cursorX) or 0)-1):gsub("\t", " ").."|", nil) -- TODO: color doesn't work
for _,colored in ipairs(coloredLines[i]) do
local str = displayedText(colored[1])
gfx.color.setDefault(colored[2])
gfx.text(x, y, str)
gfx.color.setDefault(color.default)
x = x + font:width(str)
end
gfx.text(-scrollX, y, line:gsub("\t", " "), nil)
end
-- Cursor
local curline = lines[cursorY]
gfx.rectangle(-scrollX+ font:width(displayedText(curline:sub(1, (utf8.offset(curline, cursorX) or 0)-1))),
-scrollY+ (cursorY-1)*lineHeight, 1, lineHeight, 0, color.cursor)
gfx.endFrame()
gfx.startFrame(gfx.GFX_BOTTOM)
gfx.text(3, 3, "FPS: "..math.ceil(gfx.getFPS()))
keyboard.draw(5, 115)
@ -151,3 +179,5 @@ while ctr.run() do
gfx.render()
end
font:unload()

View file

@ -0,0 +1,90 @@
-- Each pattern should return 3 captures : start position, the string to colorize, and the end position.
local syntax = {
{ "comment", { "()(%-%-.*)()$" } },
--["string"] = { "()(%'.*%f[%\\]%')()", "()(%\".*%f[%\\]%\")()" },
{ "string", { "()(%'[^%']*%')()", "()(%\"[^%\"]*%\")()" } },
{ "constant.numeric", {
"%f[%d%w%.]()(0x[a-fA-F%d]+)()%f[^%d%w%.]",
"%f[%d%w%.]()([%d% ]+%.[%d% ]+)()%f[^%d%w%.]",
"%f[%d%w%.]()([%d% ]+)()%f[^%d%w%.]"
}
},
{ "constant.language", {
"%f[%w]()(false)()%f[%W]", "%f[%w]()(nil)()%f[%W]", "%f[%w]()(true)()%f[%W]", "%f[%w]()(_G)()%f[%W]",
"%f[%w]()(_VERSION)()%f[%W]", "%f[%w]()(math.pi)()%f[%W]", "%f[%w]()(math.huge)()%f[%W]", "%f[%w]()(%.%.%.)()%f[%W]"
}
},
{ "keyword.control", {
"%f[%w]()(break)()%f[%W]", "%f[%w]()(goto)()%f[%W]", "%f[%w]()(do)()%f[%W]", "%f[%w]()(else)()%f[%W]",
"%f[%w]()(for)()%f[%W]", "%f[%w]()(if)()%f[%W]", "%f[%w]()(elseif)()%f[%W]", "%f[%w]()(return)()%f[%W]",
"%f[%w]()(then)()%f[%W]", "%f[%w]()(repeat)()%f[%W]", "%f[%w]()(while)()%f[%W]", "%f[%w]()(until)()%f[%W]",
"%f[%w]()(end)()%f[%W]", "%f[%w]()(function)()%f[%W]", "%f[%w]()(local)()%f[%W]", "%f[%w]()(in)()%f[%W]"
}
},
{ "keyword.operator", {
"%f[%w]()(and)()%f[%W]", "%f[%w]()(or)()%f[%W]", "%f[%w]()(not)()%f[%W]",
"()(%+)()", "()(%-)()", "()(%%)()", "()(%#)()", "()(%*)()", "()(%/%/?)()", "()(%^)()", "()(%=%=?)()", "()(%~%=?)()",
"()(%.%.)()", "()(%<%=?)()", "()(%>%=?)()", "()(%&)()", "()(%|)()", "()(%<%<)()", "()(%>%>)()",
}
},
{ "support.function", {
"[^%.%:]()(assert)()[%( %{]", "[^%.%:]()(collectgarbage)()[%( %{]", "[^%.%:]()(dofile)()[%( %{]",
"[^%.%:]()(error)()[%( %{]", "[^%.%:]()(getfenv)()[%( %{]", "[^%.%:]()(getmetatable)()[%( %{]",
"[^%.%:]()(ipairs)()[%( %{]", "[^%.%:]()loadfile)()[%( %{]", "[^%.%:]()(loadstring)()[%( %{]",
"[^%.%:]()(module)()[%( %{]", "[^%.%:]()(next)()[%( %{]", "[^%.%:]()(pairs)()[%( %{]",
"[^%.%:]()(pcall)()[%( %{]", "[^%.%:]()(print)()[%( %{]", "[^%.%:]()(rawequal)()[%( %{]",
"[^%.%:]()(rawget)()[%( %{]", "[^%.%:]()(rawset)()[%( %{]", "[^%.%:]()(require)()[%( %{]",
"[^%.%:]()(select)()[%( %{]", "[^%.%:]()(setfenv)()[%( %{]", "[^%.%:]()(setmetatable)()[%( %{]",
"[^%.%:]()(tonumber)()[%( %{]", "[^%.%:]()(tostring)()[%( %{]", "[^%.%:]()(type)()[%( %{]",
"[^%.%:]()(unpack)()[%( %{]", "[^%.%:]()(xpcall)()[%( %{]"
}
}
}
return function(lines, color)
local ret = {}
for _,line in ipairs(lines) do
local colored = { { line, color.default } }
for _, patterns in ipairs(syntax) do
local name = patterns[1]
for _, pattern in ipairs(patterns[2]) do
local i = 1
while i <= #colored do
local oldcolor = colored[i][2]
if oldcolor == color.default then
local part = colored[i][1]
local starti, match, endi = part:match(pattern)
if starti then
table.remove(colored, i)
if starti > 1 then
table.insert(colored, i, { part:sub(1, starti-1), oldcolor })
i = i + 1
end
table.insert(colored, i, { match, color[name] or color.default })
if endi <= #part then
table.insert(colored, i+1, { part:sub(endi, -1), oldcolor })
end
end
end
i = i + 1
end
end
end
table.insert(ret, colored)
end
return ret
end

View file

@ -1,4 +1,10 @@
local fs = require("ctr.fs")
repeat
local file = dofile("sdmc:/3ds/ctruLua/openfile.lua")("Choose a Lua file to execute", "/3ds/ctruLua/", ".lua", "exist")
if file then dofile(file) end
fs.setDirectory("sdmc:/3ds/ctruLua")
local file = dofile("openfile.lua")("Choose a Lua file to execute", "/3ds/ctruLua/", ".lua", "exist")
if file then
fs.setDirectory(file:match("^(.-)[^/]*$"))
dofile(file)
end
until not file

View file

@ -29,9 +29,11 @@ return function(title, curdir, exts, type)
--local was3D = gfx.get3D() TODO: implement this thing in ctruLua
local wasDefault = gfx.color.getDefault()
local wasBackground = gfx.color.getBackground()
local wasFont = gfx.font.getDefault()
gfx.set3D(false)
gfx.color.setDefault(0xFFFFFFFF)
gfx.color.setBackground(0x000000FF)
gfx.font.setDefault()
while ctr.run() do
ctr.hid.read()
@ -130,6 +132,7 @@ return function(title, curdir, exts, type)
--gfx.set3D(was3D)
gfx.color.setDefault(wasDefault)
gfx.color.setBackground(wasBackground)
gfx.font.setDefault(wasFont)
if ret then
return table.unpack(ret)

View file

@ -1,27 +1,126 @@
#include <unistd.h>
#include <stdlib.h>
#include <sftd.h>
#include "vera_ttf.h"
#include <lua.h>
#include <lauxlib.h>
sftd_font *font_default;
#include "font.h"
static int font_load(lua_State *L) {
const char *path = luaL_checkstring(L, 1);
font_userdata *font = lua_newuserdata(L, sizeof(*font));
luaL_getmetatable(L, "LFont");
lua_setmetatable(L, -2);
font->font = sftd_load_font_file(path);
// SFTD doesn't actually check if the file exist, so we have to do this ourselves.
if (font->font == NULL || access(path, F_OK) != 0) {
lua_pushnil(L);
lua_pushfstring(L, "No valid font file at %s", path);
return 2;
}
return 1;
}
static int font_setDefault(lua_State *L) {
if (luaL_testudata(L, 1, "LFont") == NULL) {
font_userdata *font = lua_newuserdata(L, sizeof(*font));
luaL_getmetatable(L, "LFont");
lua_setmetatable(L, -2);
font->font = sftd_load_font_mem(vera_ttf, vera_ttf_size);
}
lua_setfield(L, LUA_REGISTRYINDEX, "LFontDefault");
return 0;
}
static int font_getDefault(lua_State *L) {
lua_getfield(L, LUA_REGISTRYINDEX, "LFontDefault");
return 1;
}
static int font_object_width(lua_State *L) {
font_userdata *font = luaL_checkudata(L, 1, "LFont");
if (font->font == NULL) luaL_error(L, "The font object was unloaded");
size_t len;
const char *text = luaL_checklstring(L, 2, &len);
int size = luaL_optinteger(L, 3, 9);
// Wide caracters support. (wchar = UTF32 on 3DS.)
wchar_t wtext[len];
len = mbstowcs(wtext, text, len);
*(wtext+len) = 0x0; // text end
lua_pushinteger(L, sftd_width_wtext(font->font, size, wtext));
return 1;
}
static int font_object_unload(lua_State *L) {
font_userdata *font = luaL_checkudata(L, 1, "LFont");
if (font->font == NULL) return 0;
sftd_free_font(font->font);
font->font = NULL;
return 0;
}
// Font object methods
static const struct luaL_Reg font_object_methods[] = {
{ "width", font_object_width },
{ "unload", font_object_unload },
{ "__gc", font_object_unload },
{ NULL, NULL }
};
// Library functions
static const struct luaL_Reg font_lib[] = {
{ "load", font_load },
{ "setDefault", font_setDefault },
{ "getDefault", font_getDefault },
{ NULL, NULL }
};
int luaopen_font_lib(lua_State *L) {
luaL_newmetatable(L, "LFont");
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
luaL_setfuncs(L, font_object_methods, 0);
luaL_newlib(L, font_lib);
return 1;
}
void load_font_lib(lua_State *L) {
font_default = sftd_load_font_mem(vera_ttf, vera_ttf_size); // Load default font
// Load default font
font_userdata *font = lua_newuserdata(L, sizeof(*font));
luaL_getmetatable(L, "LFont");
lua_setmetatable(L, -2);
font->font = sftd_load_font_mem(vera_ttf, vera_ttf_size);
lua_setfield(L, LUA_REGISTRYINDEX, "LFontDefault");
// Load lib
luaL_requiref(L, "ctr.gfx.font", luaopen_font_lib, false);
}
void unload_font_lib(lua_State *L) {
sftd_free_font(font_default); // Unload current font
lua_getfield(L, LUA_REGISTRYINDEX, "LFontDefault");
if (luaL_testudata(L, -1, "LFont") != NULL)
sftd_free_font(((font_userdata *)lua_touserdata(L, -1))->font); // Unload current font
}

8
source/font.h Normal file
View file

@ -0,0 +1,8 @@
#ifndef FONT_H
#define FONT_H
typedef struct {
sftd_font *font;
} font_userdata;
#endif

View file

@ -1,3 +1,5 @@
#include <unistd.h>
#include <3ds/types.h>
#include <3ds/util/utf.h>
#include <3ds/services/fs.h>
@ -8,7 +10,7 @@
Handle *fsuHandle;
FS_archive sdmcArchive;
int fs_list(lua_State *L) {
static int fs_list(lua_State *L) {
const char *path = luaL_checkstring(L, 1);
lua_newtable(L);
@ -60,8 +62,40 @@ int fs_list(lua_State *L) {
return 1;
}
static int fs_exists(lua_State *L) {
const char *path = luaL_checkstring(L, 1);
lua_pushboolean(L, access(path, F_OK) == 0);
return 1;
}
static int fs_getDirectory(lua_State *L) {
char cwd[256];
lua_pushstring(L, getcwd(cwd, 256));
return 1;
}
static int fs_setDirectory(lua_State *L) {
const char *path = luaL_checkstring(L, 1);
int result = chdir(path);
if (result == 0)
lua_pushboolean(L, true);
else
lua_pushboolean(L, false);
return 1;
}
static const struct luaL_Reg fs_lib[] = {
{ "list", fs_list },
{ "list", fs_list },
{ "exists", fs_exists },
{ "getDirectory", fs_getDirectory },
{ "setDirectory", fs_setDirectory },
{ NULL, NULL }
};

View file

@ -8,6 +8,8 @@
#include <lua.h>
#include <lauxlib.h>
#include "font.h"
bool isGfxInitialised = false;
void load_color_lib(lua_State *L);
@ -18,7 +20,6 @@ void load_map_lib(lua_State *L);
void unload_font_lib(lua_State *L);
u32 color_default;
sftd_font *font_default;
static int gfx_startFrame(lua_State *L) {
u8 screen = luaL_checkinteger(L, 1);
@ -124,14 +125,20 @@ static int gfx_text(lua_State *L) {
int size = luaL_optinteger(L, 4, 9);
u32 color = luaL_optinteger(L, 5, color_default);
// todo : font selection
font_userdata *font = luaL_testudata(L, 6, "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.)
wchar_t wtext[len];
len = mbstowcs(wtext, text, len);
*(wtext+len) = 0x0; // text end
sftd_draw_wtext(font_default, x, y, color, size, wtext);
sftd_draw_wtext(font->font, x, y, color, size, wtext);
return 0;
}