If initsram/initstate points to LSS file, pull the matching member
[lsnes.git] / src / platform / wxwidgets / textrender.cpp
blobfc13e1bbc1f7bab285a540c6dc8f68c2ce01dee5
1 #include "platform/wxwidgets/textrender.hpp"
2 #include "platform/wxwidgets/platform.hpp"
3 #include "fonts/wrapper.hpp"
4 #include "library/utf8.hpp"
5 #include "library/string.hpp"
6 #include <wx/dc.h>
7 #include <wx/dcclient.h>
8 #include <wx/image.h>
10 extern const uint32_t text_framebuffer::element::white = 0xFFFFFF;
11 extern const uint32_t text_framebuffer::element::black = 0x000000;
13 text_framebuffer::text_framebuffer()
15 width = 0;
16 height = 0;
19 text_framebuffer::text_framebuffer(size_t w, size_t h)
21 width = 0;
22 height = 0;
23 set_size(w, h);
26 void text_framebuffer::set_size(size_t w, size_t h)
28 if(w == width && h == height)
29 return;
30 std::vector<element> newfb;
31 newfb.resize(w * h);
32 for(size_t i = 0; i < h && i < height; i++)
33 for(size_t j = 0; j < w && j < width; j++)
34 newfb[i * w + j] = buffer[i * width + j];
35 buffer.swap(newfb);
36 width = w;
37 height = h;
40 std::pair<size_t, size_t> text_framebuffer::get_cell()
42 return std::make_pair(8, 16);
45 std::pair<size_t, size_t> text_framebuffer::get_pixels()
47 auto x = get_cell();
48 return std::make_pair(x.first * width, x.second * height);
51 void text_framebuffer::render(char* tbuffer)
53 uint32_t dummy[8] = {0};
54 size_t stride = 24 * width;
55 size_t cellstride = 24;
56 for(size_t y = 0; y < height; y++) {
57 size_t xp = 0;
58 for(size_t x = 0; x < width; x++) {
59 if(xp >= width)
60 break; //No more space in row.
61 char* cellbase = tbuffer + y * (16 * stride) + xp * cellstride;
62 const element& e = buffer[y * width + x];
63 const framebuffer::font::glyph& g = main_font.get_glyph(e.ch);
64 char bgb = (e.bg >> 16);
65 char bgg = (e.bg >> 8);
66 char bgr = (e.bg >> 0);
67 char fgb = (e.fg >> 16);
68 char fgg = (e.fg >> 8);
69 char fgr = (e.fg >> 0);
70 const uint32_t* data = (g.data ? g.data : dummy);
71 if(g.wide && xp < width - 1) {
72 //Wide character, can draw full width.
73 for(size_t y2 = 0; y2 < 16; y2++) {
74 uint32_t d = data[y2 >> 1];
75 d >>= 16 - ((y2 & 1) << 4);
76 for(size_t j = 0; j < 16; j++) {
77 uint32_t b = 15 - j;
78 if(((d >> b) & 1) != 0) {
79 cellbase[3 * j + 0] = fgr;
80 cellbase[3 * j + 1] = fgg;
81 cellbase[3 * j + 2] = fgb;
82 } else {
83 cellbase[3 * j + 0] = bgr;
84 cellbase[3 * j + 1] = bgg;
85 cellbase[3 * j + 2] = bgb;
88 cellbase += stride;
90 xp += 2;
91 } else if(g.wide) {
92 //Wide character, can only draw half.
93 for(size_t y2 = 0; y2 < 16; y2++) {
94 uint32_t d = data[y2 >> 1];
95 d >>= 16 - ((y2 & 1) << 4);
96 for(size_t j = 0; j < 8; j++) {
97 uint32_t b = 15 - j;
98 if(((d >> b) & 1) != 0) {
99 cellbase[3 * j + 0] = fgr;
100 cellbase[3 * j + 1] = fgg;
101 cellbase[3 * j + 2] = fgb;
102 } else {
103 cellbase[3 * j + 0] = bgr;
104 cellbase[3 * j + 1] = bgg;
105 cellbase[3 * j + 2] = bgb;
108 cellbase += stride;
110 xp += 2;
111 } else {
112 //Narrow character.
113 for(size_t y2 = 0; y2 < 16; y2++) {
114 uint32_t d = data[y2 >> 2];
115 d >>= 24 - ((y2 & 3) << 3);
116 for(size_t j = 0; j < 8; j++) {
117 uint32_t b = 7 - j;
118 if(((d >> b) & 1) != 0) {
119 cellbase[3 * j + 0] = fgr;
120 cellbase[3 * j + 1] = fgg;
121 cellbase[3 * j + 2] = fgb;
122 } else {
123 cellbase[3 * j + 0] = bgr;
124 cellbase[3 * j + 1] = bgg;
125 cellbase[3 * j + 2] = bgb;
128 cellbase += stride;
130 xp += 1;
136 size_t text_framebuffer::text_width(const std::string& text)
138 auto x = main_font.get_metrics(text);
139 return x.first / 8;
142 size_t text_framebuffer::write(const std::string& str, size_t w, size_t x, size_t y, uint32_t fg, uint32_t bg)
144 return write(utf8::to32(str), w, x, y, fg, bg);
147 size_t text_framebuffer::write(const std::u32string& str, size_t w, size_t x, size_t y, uint32_t fg, uint32_t bg)
149 if(y >= height)
150 return 0;
151 size_t pused = 0;
152 for(auto u : str) {
153 if(u == 9) {
154 //TAB.
155 do {
156 if(x + pused < width) {
157 element& e = buffer[y * width + x + pused];
158 e.ch = 32; //Space.
159 e.fg = fg;
160 e.bg = bg;
162 pused++;
163 } while(pused % 8);
164 continue;
166 const framebuffer::font::glyph& g = main_font.get_glyph(u);
167 if(x + pused < width) {
168 element& e = buffer[y * width + x + pused];
169 e.ch = u;
170 e.fg = fg;
171 e.bg = bg;
173 pused += (g.wide ? 2 : 1);
175 while(pused < w) {
176 //Pad with spaces.
177 if(x + pused < width) {
178 element& e = buffer[y * width + x + pused];
179 e.ch = 32;
180 e.fg = fg;
181 e.bg = bg;
183 pused++;
185 return x + pused;
188 text_framebuffer_panel::text_framebuffer_panel(wxWindow* parent, size_t w, size_t h, wxWindowID id,
189 wxWindow* _redirect)
190 : wxPanel(parent, id), text_framebuffer(w, h)
192 CHECK_UI_THREAD;
193 redirect = _redirect;
194 auto psize = get_pixels();
195 size_changed = false;
196 locked = false;
197 paint_requested = false;
198 SetMinSize(wxSize(psize.first, psize.second));
199 this->Connect(wxEVT_PAINT, wxPaintEventHandler(text_framebuffer_panel::on_paint), NULL, this);
200 this->Connect(wxEVT_ERASE_BACKGROUND, wxEraseEventHandler(text_framebuffer_panel::on_erase), NULL, this);
201 this->Connect(wxEVT_SET_FOCUS, wxFocusEventHandler(text_framebuffer_panel::on_focus), NULL, this);
204 text_framebuffer_panel::~text_framebuffer_panel()
208 void text_framebuffer_panel::set_size(size_t _width, size_t _height)
210 CHECK_UI_THREAD;
211 text_framebuffer::set_size(_width, _height);
212 auto psize = get_pixels();
213 buffer.resize(psize.first * psize.second * 3);
214 if(!locked) {
215 SetMinSize(wxSize(psize.first, psize.second));
216 } else
217 size_changed = true;
218 request_paint();
221 void text_framebuffer_panel::request_paint()
223 CHECK_UI_THREAD;
224 if(size_changed) {
225 auto psize = get_pixels();
226 SetMinSize(wxSize(psize.first, psize.second));
227 size_changed = false;
228 paint_requested = true;
229 Refresh();
230 } else if(!paint_requested) {
231 paint_requested = true;
232 Refresh();
236 void text_framebuffer_panel::on_erase(wxEraseEvent& e)
240 void text_framebuffer_panel::on_paint(wxPaintEvent& e)
242 CHECK_UI_THREAD;
243 locked = true;
244 auto size = GetSize();
245 text_framebuffer::set_size((size.x + 7) / 8, (size.y + 15) / 16);
246 auto psize = get_pixels();
247 buffer.resize(psize.first * psize.second * 3);
248 prepare_paint();
249 locked = false;
250 psize = get_pixels();
251 wxPaintDC dc(this);
252 render(&buffer[0]);
253 wxBitmap bmp1(wxImage(psize.first, psize.second, reinterpret_cast<unsigned char*>(&buffer[0]),
254 true));
255 dc.DrawBitmap(bmp1, 0, 0, false);
256 paint_requested = false;
259 void text_framebuffer_panel::on_focus(wxFocusEvent& e)
261 CHECK_UI_THREAD;
262 if(redirect)
263 redirect->SetFocus();