Redo text rendering (adds halo support to gui.text())
[lsnes.git] / src / lua / gui-text-cf.cpp
blobda056e2c00f72455ef1244aa09b3602f0fa0c985
1 #include "core/instance.hpp"
2 #include "lua/internal.hpp"
3 #include "lua/halo.hpp"
4 #include "lua/bitmap.hpp"
5 #include "fonts/wrapper.hpp"
6 #include "core/framebuffer.hpp"
7 #include "core/instance.hpp"
8 #include "library/framebuffer-font2.hpp"
9 #include "library/utf8.hpp"
10 #include "library/lua-framebuffer.hpp"
11 #include "library/zip.hpp"
12 #include <algorithm>
15 namespace
17 struct lua_customfont
19 public:
20 struct empty_font_tag {};
21 lua_customfont(lua::state& L, const std::string& filename, const std::string& filename2);
22 lua_customfont(lua::state& L);
23 lua_customfont(lua::state& L, empty_font_tag tag);
24 static size_t overcommit() { return 0; }
25 static size_t overcommit(const std::string& filename, const std::string& filename2) { return 0; }
26 static size_t overcommit(empty_font_tag tag) { return 0; }
27 ~lua_customfont() throw();
28 static int create(lua::state& L, lua::parameters& P);
29 static int load(lua::state& L, lua::parameters& P);
30 int draw(lua::state& L, lua::parameters& P);
31 int edit(lua::state& L, lua::parameters& P);
32 const framebuffer::font2& get_font() { return font; }
33 std::string print()
35 return orig_filename;
37 private:
38 std::string orig_filename;
39 framebuffer::font2 font;
42 lua::_class<lua_customfont> LUA_class_customfont(lua_class_gui, "CUSTOMFONT", {
43 {"new", lua_customfont::create},
44 {"load", lua_customfont::load},
45 }, {
46 {"__call", &lua_customfont::draw},
47 {"edit", &lua_customfont::edit},
48 }, &lua_customfont::print);
50 struct render_object_text_cf : public framebuffer::object
52 render_object_text_cf(int32_t _x, int32_t _y, const std::string& _text, framebuffer::color _fg,
53 framebuffer::color _bg, framebuffer::color _hl, lua::objpin<lua_customfont>& _font) throw()
54 : x(_x), y(_y), text(_text), fg(_fg), bg(_bg), hl(_hl), font(_font) {}
55 ~render_object_text_cf() throw()
58 template<bool X> void op(struct framebuffer::fb<X>& scr) throw()
60 const framebuffer::font2& fdata = font->get_font();
61 std::u32string _text = utf8::to32(text);
63 auto size = fdata.get_metrics(_text, x);
64 //Enlarge size by 2 in each dimension, in order to accomodiate halo, if any.
65 //Round up width to multiple of 32.
66 size.first = (size.first + 33) >> 5 << 5;
67 size.second += 2;
68 size_t allocsize = size.first * size.second + 32;
70 if(allocsize > 32768) {
71 std::vector<uint8_t> memory;
72 memory.resize(allocsize);
73 op_with(scr, &memory[0], size, _text, fdata);
74 } else {
75 uint8_t memory[allocsize];
76 op_with(scr, memory, size, _text, fdata);
79 template<bool X> void op_with(struct framebuffer::fb<X>& scr, unsigned char* mem,
80 std::pair<size_t, size_t> size, const std::u32string& _text, const framebuffer::font2& fdata)
81 throw()
83 memset(mem, 0, size.first * size.second);
84 int32_t rx = x + scr.get_origin_x();
85 int32_t ry = y + scr.get_origin_y();
86 fdata.for_each_glyph(_text, x, [mem, size](uint32_t x, uint32_t y,
87 const framebuffer::font2::glyph& glyph) {
88 x++;
89 y++;
90 glyph.render(mem + (y * size.first + x), size.first, 0, 0, glyph.width, glyph.height);
91 });
92 halo_blit(scr, mem, size.first, size.second, rx, ry, bg, fg, hl);
94 bool kill_request(void* obj) throw()
96 return kill_request_ifeq(font.object(), obj);
98 void operator()(struct framebuffer::fb<true>& scr) throw() { op(scr); }
99 void operator()(struct framebuffer::fb<false>& scr) throw() { op(scr); }
100 void clone(framebuffer::queue& q) const throw(std::bad_alloc) { q.clone_helper(this); }
101 private:
102 int32_t x;
103 int32_t y;
104 std::string text;
105 framebuffer::color fg;
106 framebuffer::color bg;
107 framebuffer::color hl;
108 lua::objpin<lua_customfont> font;
111 lua_customfont::lua_customfont(lua::state& L, const std::string& filename, const std::string& filename2)
112 : orig_filename(zip::resolverel(filename, filename2)), font(orig_filename)
116 lua_customfont::lua_customfont(lua::state& L)
117 : font(main_font)
119 orig_filename = "<builtin>";
122 lua_customfont::~lua_customfont() throw()
124 CORE().fbuf->render_kill_request(this);
127 int lua_customfont::draw(lua::state& L, lua::parameters& P)
129 auto& core = CORE();
130 int32_t _x, _y;
131 framebuffer::color fg, bg, hl;
132 std::string text;
133 lua::objpin<lua_customfont> f;
135 if(!core.lua2->render_ctx)
136 return 0;
138 P(f, _x, _y, text, P.optional(fg, 0xFFFFFFU), P.optional(bg, -1), P.optional(hl, -1));
140 core.lua2->render_ctx->queue->create_add<render_object_text_cf>(_x, _y, text, fg, bg, hl, f);
141 return 0;
144 lua_customfont::lua_customfont(lua::state& L, lua_customfont::empty_font_tag tag)
146 orig_filename = "<empty>";
149 int lua_customfont::edit(lua::state& L, lua::parameters& P)
151 std::string text;
152 lua_bitmap* _glyph;
154 P(P.skipped(), text, _glyph);
156 framebuffer::font2::glyph glyph;
157 glyph.width = _glyph->width;
158 glyph.height = _glyph->height;
159 glyph.stride = (glyph.width + 31) / 32;
160 glyph.fglyph.resize(glyph.stride * glyph.height);
161 memset(&glyph.fglyph[0], 0, sizeof(uint32_t) * glyph.fglyph.size());
162 for(size_t y = 0; y < glyph.height; y++) {
163 size_t bpos = y * glyph.stride * 32;
164 for(size_t x = 0; x < glyph.width; x++) {
165 size_t e = (bpos + x) / 32;
166 size_t b = 31 - (bpos + x) % 32;
167 if(_glyph->pixels[y * _glyph->width + x])
168 glyph.fglyph[e] |= (1UL << b);
171 font.add(utf8::to32(text), glyph);
172 return 0;
175 int lua_customfont::create(lua::state& L, lua::parameters& P)
177 lua::_class<lua_customfont>::create(L, lua_customfont::empty_font_tag());
178 return 1;
181 int lua_customfont::load(lua::state& L, lua::parameters& P)
183 std::string filename, filename2;
184 if(P.is_novalue()) {
185 lua::_class<lua_customfont>::create(L);
186 return 1;
189 P(filename, P.optional(filename2, ""));
191 lua::_class<lua_customfont>::create(L, filename, filename2);
192 return 1;