Lua: Don't lua_error() out of context with pending dtors
[lsnes.git] / src / library / memorywatch-fb.cpp
blobf6b92ca00ae6f9017497fc4e059609866c3ccb19
1 #include "framebuffer-font2.hpp"
2 #include "memorywatch-fb.hpp"
3 #include "utf8.hpp"
4 #include "minmax.hpp"
6 namespace memorywatch
8 namespace
10 struct fb_object : public framebuffer::object
12 struct params
14 int64_t x;
15 int64_t y;
16 bool cliprange_x;
17 bool cliprange_y;
18 bool alt_origin_x;
19 bool alt_origin_y;
20 framebuffer::font2* font;
21 framebuffer::color fg;
22 framebuffer::color bg;
23 framebuffer::color halo;
25 fb_object(const params& _p, const std::string& _msg);
26 ~fb_object() throw();
27 void operator()(struct framebuffer::fb<false>& scr) throw();
28 void operator()(struct framebuffer::fb<true>& scr) throw();
29 void clone(framebuffer::queue& q) const throw(std::bad_alloc);
30 private:
31 template<bool ext> void draw(struct framebuffer::fb<ext>& scr) throw();
32 params p;
33 std::u32string msg;
36 fb_object::fb_object(const fb_object::params& _p, const std::string& _msg)
37 : p(_p)
39 msg = utf8::to32(_msg);
42 fb_object::~fb_object() throw() {}
43 void fb_object::operator()(struct framebuffer::fb<false>& scr) throw() { draw(scr); }
44 void fb_object::operator()(struct framebuffer::fb<true>& scr) throw() { draw(scr); }
46 void fb_object::clone(framebuffer::queue& q) const throw(std::bad_alloc) { q.clone_helper(this); }
48 template<bool ext> void fb_object::draw(struct framebuffer::fb<ext>& scr) throw()
50 p.x += scr.get_origin_x();
51 p.y += scr.get_origin_y();
52 if(p.alt_origin_x)
53 p.x += scr.get_last_blit_width();
54 if(p.alt_origin_y)
55 p.y += scr.get_last_blit_height();
56 p.fg.set_palette(scr);
57 p.bg.set_palette(scr);
58 p.halo.set_palette(scr);
60 bool has_halo = p.halo;
61 //Layout the text.
62 int64_t orig_x = p.x;
63 int64_t drawx = p.x;
64 int64_t drawy = p.y;
65 int64_t max_drawx = p.x;
66 for(size_t i = 0; i < msg.size();) {
67 uint32_t cp = msg[i];
68 std::u32string k = p.font->best_ligature_match(msg, i);
69 const framebuffer::font2::glyph& glyph = p.font->lookup_glyph(k);
70 if(k.length())
71 i += k.length();
72 else
73 i++;
74 if(cp == 9) {
75 drawx = (drawx + 64) >> 6 << 6;
76 } else if(cp == 10) {
77 drawx = orig_x;
78 drawy += p.font->get_rowadvance();
79 } else {
80 drawx += glyph.width;
81 max_drawx = max(max_drawx, drawx);
84 uint64_t width = max_drawx - p.x;
85 uint64_t height = drawy - p.y;
86 if(has_halo) {
87 width += 2;
88 height += 2;
90 drawx = p.x;
91 drawy = p.y;
92 orig_x = p.x;
93 if(p.cliprange_x) {
94 if(drawx < 0)
95 drawx = 0;
96 else if(drawx + width > scr.get_width())
97 drawx = scr.get_width() - width;
99 if(p.cliprange_y) {
100 if(drawy < 0)
101 drawy = 0;
102 else if(drawy + height > scr.get_height())
103 drawy = scr.get_height() - height;
105 if(has_halo) {
106 orig_x++;
107 drawx++;
108 drawy++;
110 for(size_t i = 0; i < msg.size();) {
111 uint32_t cp = msg[i];
112 std::u32string k = p.font->best_ligature_match(msg, i);
113 const framebuffer::font2::glyph& glyph = p.font->lookup_glyph(k);
114 if(k.length())
115 i += k.length();
116 else
117 i++;
118 if(cp == 9) {
119 drawx = (drawx + 64) >> 6 << 6;
120 } else if(cp == 10) {
121 drawx = orig_x;
122 drawy += p.font->get_rowadvance();
123 } else {
124 glyph.render(scr, drawx, drawy, p.fg, p.bg, p.halo);
125 drawx += glyph.width;
131 output_fb::output_fb()
133 font = NULL;
136 output_fb::~output_fb()
138 if(dtor_cb)
139 dtor_cb(*this);
142 void output_fb::set_rqueue(framebuffer::queue& rqueue)
144 queue = &rqueue;
147 void output_fb::set_dtor_cb(std::function<void(output_fb&)> cb)
149 dtor_cb = cb;
152 void output_fb::show(const std::string& iname, const std::string& val)
154 fb_object::params p;
155 try {
156 if(cond_enable) {
157 enabled->reset();
158 auto e = enabled->evaluate();
159 if(!e.type->toboolean(e._value))
160 return;
162 pos_x->reset();
163 pos_y->reset();
164 auto x = pos_x->evaluate();
165 auto y = pos_y->evaluate();
166 p.x = x.type->tosigned(x._value);
167 p.y = y.type->tosigned(y._value);
168 p.alt_origin_x = alt_origin_x;
169 p.alt_origin_y = alt_origin_y;
170 p.cliprange_x = cliprange_x;
171 p.cliprange_y = cliprange_y;
172 p.font = font;
173 p.fg = fg;
174 p.bg = bg;
175 p.halo = halo;
176 queue->create_add<fb_object>(p, val);
177 } catch(...) {
181 void output_fb::reset()
183 enabled->reset();
184 pos_x->reset();
185 pos_y->reset();