Direct framebuffer
[lsnes.git] / src / plat-sdl / paint.cpp
blobca6a0471b241a5b44fafba6800a32bb06fa360a5
1 #include "core/dispatch.hpp"
2 #include "core/framebuffer.hpp"
3 #include "core/framerate.hpp"
4 #include "core/window.hpp"
6 #include "plat-sdl/paint.hpp"
8 #define MAXMESSAGES 6
10 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
11 #define WRITE3(ptr, idx, c) do {\
12 (ptr)[(idx) + 0] = (c) >> 16; \
13 (ptr)[(idx) + 1] = (c) >> 8; \
14 (ptr)[(idx) + 2] = (c); \
15 } while(0)
16 #else
17 #define WRITE3(ptr, idx, c) do {\
18 (ptr)[(idx) + 0] = (c); \
19 (ptr)[(idx) + 1] = (c) >> 8; \
20 (ptr)[(idx) + 2] = (c) >> 16; \
21 } while(0)
22 #endif
24 namespace
26 SDL_Surface* hwsurf;
27 screen* our_screen;
28 sdlw_display_parameters dp;
29 bool fullscreen_console_active;
30 bool video_locked;
31 bool screen_paintable;
32 bool screen_dirty;
33 bool modal_dialog_shown;
34 std::string modal_dialog_text;
35 bool modal_dialog_confirm;
36 bool have_received_frames;
38 void paint_line(uint8_t* ptr, uint32_t length, uint32_t step, uint32_t pbytes, uint32_t color)
40 switch(pbytes) {
41 case 1:
42 for(uint32_t i = 0; i < length; i++) {
43 *ptr = color;
44 ptr += step;
46 break;
47 case 2:
48 for(uint32_t i = 0; i < length; i++) {
49 *reinterpret_cast<uint16_t*>(ptr) = color;
50 ptr += step;
52 break;
53 case 3:
54 for(uint32_t i = 0; i < length; i++) {
55 WRITE3(ptr, 0, color);
56 ptr += step;
58 break;
59 case 4:
60 for(uint32_t i = 0; i < length; i++) {
61 *reinterpret_cast<uint32_t*>(ptr) = color;
62 ptr += step;
64 break;
68 std::vector<uint32_t> decode_utf8(std::string s)
70 std::vector<uint32_t> ret;
71 for(auto i = s.begin(); i != s.end(); i++) {
72 uint32_t j = static_cast<uint8_t>(*i);
73 if(j < 128)
74 ret.push_back(j);
75 else if(j < 192)
76 continue;
77 else if(j < 224) {
78 uint32_t j2 = static_cast<uint8_t>(*(++i));
79 ret.push_back((j - 192) * 64 + (j2 - 128));
80 } else if(j < 240) {
81 uint32_t j2 = static_cast<uint8_t>(*(++i));
82 uint32_t j3 = static_cast<uint8_t>(*(++i));
83 ret.push_back((j - 224) * 4096 + (j2 - 128) * 64 + (j3 - 128));
84 } else {
85 uint32_t j2 = static_cast<uint8_t>(*(++i));
86 uint32_t j3 = static_cast<uint8_t>(*(++i));
87 uint32_t j4 = static_cast<uint8_t>(*(++i));
88 ret.push_back((j - 240) * 262144 + (j2 - 128) * 4096 + (j3 - 128) * 64 + (j4 - 128));
91 return ret;
94 inline void draw_blank_glyph_3(uint8_t* base, uint32_t pitch, uint32_t w, uint32_t color, uint32_t curstart)
96 for(uint32_t j = 0; j < 16; j++) {
97 uint8_t* ptr = base + j * pitch;
98 uint32_t c = (j >= curstart) ? color : 0;
99 for(uint32_t i = 0; i < w; i++)
100 WRITE3(ptr, 3 * i, c);
104 template<typename T>
105 inline void draw_blank_glyph_T(uint8_t* base, uint32_t pitch, uint32_t w, uint32_t color, uint32_t curstart)
107 for(uint32_t j = 0; j < 16; j++) {
108 T* ptr = reinterpret_cast<T*>(base + j * pitch);
109 T c = (j >= curstart) ? color : 0;
110 for(uint32_t i = 0; i < w; i++)
111 ptr[i] = c;
115 template<bool wide>
116 inline void draw_glyph_3(uint8_t* base, uint32_t pitch, uint32_t w, const uint32_t* gdata, uint32_t color,
117 uint32_t curstart)
119 for(uint32_t j = 0; j < 16; j++) {
120 uint8_t* ptr = base + j * pitch;
121 uint32_t bgc = (j >= curstart) ? color : 0;
122 uint32_t fgc = (j >= curstart) ? 0 : color;
123 uint32_t dataword = gdata[j >> (wide ? 1 : 2)];
124 unsigned rbit = (~(j << (wide ? 4 : 3))) & 0x1F;
125 for(uint32_t i = 0; i < w; i++) {
126 bool b = (((dataword >> (rbit - i)) & 1));
127 WRITE3(ptr, 3 * i, b ? fgc : bgc);
132 template<typename T, bool wide>
133 inline void draw_glyph_T(uint8_t* base, uint32_t pitch, uint32_t w, const uint32_t* gdata, uint32_t color,
134 uint32_t curstart)
136 for(uint32_t j = 0; j < 16; j++) {
137 T* ptr = reinterpret_cast<T*>(base + j * pitch);
138 T bgc = (j >= curstart) ? color : 0;
139 T fgc = (j >= curstart) ? 0 : color;
140 uint32_t dataword = gdata[j >> (wide ? 1 : 2)];
141 unsigned rbit = (~(j << (wide ? 4 : 3))) & 0x1F;
142 for(uint32_t i = 0; i < w; i++) {
143 bool b = (((dataword >> (rbit - i)) & 1));
144 ptr[i] = b ? fgc : bgc;
150 void draw_blank_glyph(uint8_t* base, uint32_t pitch, uint32_t pbytes, uint32_t w, uint32_t wleft,
151 uint32_t color, uint32_t hilite_mode)
153 if(w > wleft)
154 w = wleft;
155 if(!w)
156 return;
157 uint32_t curstart = 16;
158 if(hilite_mode == 1)
159 curstart = 14;
160 if(hilite_mode == 2)
161 curstart = 0;
162 switch(pbytes) {
163 case 1:
164 draw_blank_glyph_T<uint8_t>(base, pitch, w, color, curstart);
165 break;
166 case 2:
167 draw_blank_glyph_T<uint16_t>(base, pitch, w, color, curstart);
168 break;
169 case 3:
170 draw_blank_glyph_3(base, pitch, w, color, curstart);
171 break;
172 case 4:
173 draw_blank_glyph_T<uint32_t>(base, pitch, w, color, curstart);
174 break;
178 void draw_glyph(uint8_t* base, uint32_t pitch, uint32_t pbytes, const uint32_t* gdata, uint32_t w,
179 uint32_t wleft, uint32_t color, uint32_t hilite_mode)
181 bool wide = (w > 8);
182 if(w > wleft)
183 w = wleft;
184 if(!w)
185 return;
186 uint32_t curstart = 16;
187 if(hilite_mode == 1)
188 curstart = 14;
189 if(hilite_mode == 2)
190 curstart = 0;
191 switch(pbytes) {
192 case 1:
193 if(wide)
194 draw_glyph_T<uint8_t, true>(base, pitch, w, gdata, color, curstart);
195 else
196 draw_glyph_T<uint8_t, false>(base, pitch, w, gdata, color, curstart);
197 break;
198 case 2:
199 if(wide)
200 draw_glyph_T<uint16_t, true>(base, pitch, w, gdata, color, curstart);
201 else
202 draw_glyph_T<uint16_t, false>(base, pitch, w, gdata, color, curstart);
203 break;
204 case 3:
205 if(wide)
206 draw_glyph_3<true>(base, pitch, w, gdata, color, curstart);
207 else
208 draw_glyph_3<false>(base, pitch, w, gdata, color, curstart);
209 break;
210 case 4:
211 if(wide)
212 draw_glyph_T<uint32_t, true>(base, pitch, w, gdata, color, curstart);
213 else
214 draw_glyph_T<uint32_t, false>(base, pitch, w, gdata, color, curstart);
215 break;
219 void draw_string(uint8_t* base, uint32_t pitch, uint32_t pbytes, std::vector<uint32_t> s, uint32_t x,
220 uint32_t y, uint32_t maxwidth, uint32_t color, uint32_t hilite_mode = 0, uint32_t hilite_pos = 0)
222 int32_t pos_x = 0;
223 int32_t pos_y = 0;
224 size_t xo = pbytes;
225 size_t yo = pitch;
226 unsigned c = 0;
227 for(auto si : s) {
228 uint32_t old_x = pos_x;
229 uint32_t old_y = pos_y;
230 auto g = find_glyph(si, pos_x, pos_y, 0, pos_x, pos_y);
231 uint32_t mw = maxwidth - old_x;
232 if(maxwidth < old_x)
233 mw = 0;
234 if(mw > g.first)
235 mw = g.first;
236 uint8_t* cbase = base + (y + old_y) * yo + (x + old_x) * xo;
237 if(g.second == NULL)
238 draw_blank_glyph(cbase, pitch, pbytes, g.first, mw, color,
239 (c == hilite_pos) ? hilite_mode : 0);
240 else
241 draw_glyph(cbase, pitch, pbytes, g.second, g.first, mw, color,
242 (c == hilite_pos) ? hilite_mode : 0);
243 c++;
245 if(c == hilite_pos) {
246 uint32_t old_x = pos_x;
247 uint32_t mw = maxwidth - old_x;
248 if(maxwidth < old_x)
249 mw = 0;
250 draw_blank_glyph(base + y * yo + (x + old_x) * xo, pitch, pbytes, 8, mw, 0xFFFFFFFFU,
251 hilite_mode);
252 pos_x += 8;
254 if(pos_x < maxwidth)
255 draw_blank_glyph(base + y * yo + (x + pos_x) * xo, pitch, pbytes, maxwidth - pos_x,
256 maxwidth - pos_x, 0, 0);
259 void draw_string(uint8_t* base, uint32_t pitch, uint32_t pbytes, std::string s, uint32_t x, uint32_t y,
260 uint32_t maxwidth, uint32_t color, uint32_t hilite_mode = 0, uint32_t hilite_pos = 0)
262 draw_string(base, pitch, pbytes, decode_utf8(s), x, y, maxwidth, color, hilite_mode, hilite_pos);
266 void draw_box(SDL_Surface* surf, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t color)
268 if(!w || !h)
269 return;
270 uint32_t sx, sy, ex, ey;
271 uint32_t bsx, bsy, bex, bey;
272 uint32_t pbytes = surf->format->BytesPerPixel;
273 uint32_t lstride = surf->pitch;
274 uint8_t* p = reinterpret_cast<uint8_t*>(surf->pixels);
275 size_t xo = surf->format->BytesPerPixel;
276 size_t yo = surf->pitch;
277 sx = (x < 6) ? 0 : (x - 6);
278 sy = (y < 6) ? 0 : (y - 6);
279 ex = (x + w + 6 > surf->w) ? surf->w : (x + w + 6);
280 ey = (y + h + 6 > surf->h) ? surf->h : (y + h + 6);
281 bsx = (x < 4) ? 0 : (x - 4);
282 bsy = (y < 4) ? 0 : (y - 4);
283 bex = (x + w + 4 > surf->w) ? surf->w : (x + w + 4);
284 bey = (y + h + 4 > surf->h) ? surf->h : (y + h + 4);
285 //First, blank the area.
286 for(uint32_t j = sy; j < ey; j++)
287 memset(p + j * yo + sx * xo, 0, (ex - sx) * xo);
288 //Paint the borders.
289 if(x >= 4)
290 paint_line(p + bsy * yo + (x - 4) * xo, bey - bsy, yo, xo, color);
291 if(x >= 3)
292 paint_line(p + bsy * yo + (x - 3) * xo, bey - bsy, yo, xo, color);
293 if(y >= 4)
294 paint_line(p + (y - 4) * yo + bsx * xo, bex - bsx, xo, xo, color);
295 if(y >= 3)
296 paint_line(p + (y - 3) * yo + bsx * xo, bex - bsx, xo, xo, color);
297 if(x + w + 3 < surf->w)
298 paint_line(p + bsy * yo + (x + w + 2) * xo, bey - bsy, yo, xo, color);
299 if(x + w + 4 < surf->w)
300 paint_line(p + bsy * yo + (x + w + 3) * xo, bey - bsy, yo, xo, color);
301 if(y + h + 3 < surf->h)
302 paint_line(p + (y + h + 2) * yo + bsx * xo, bex - bsx, xo, xo, color);
303 if(y + h + 4 < surf->h)
304 paint_line(p + (y + h + 3) * yo + bsx * xo, bex - bsx, xo, xo, color);
307 sdlw_display_parameters::sdlw_display_parameters()
309 real_screen_w = 0;
310 real_screen_h = 0;
311 fullscreen_console = false;
312 virtual_screen_w = 512;
313 virtual_screen_h = 448;
314 display_w = virtual_screen_w + 278;
315 display_h = virtual_screen_h + 16 * MAXMESSAGES + 48;
316 screenarea_x = 6;
317 screenarea_y = 6;
318 statusarea_x = virtual_screen_w + 16;
319 statusarea_y = 6;
320 messagearea_x = 6;
321 cmdline_x = 6;
322 cmdline_y = display_h - 22;
323 cmdline_w = display_w - 12;
324 messagearea_w = display_w - 12;
325 screenarea_w = virtual_screen_w;
326 screenarea_h = virtual_screen_h;
327 statusarea_w = 256;
328 statusarea_lines = virtual_screen_h / 16;
329 messagearea_y = virtual_screen_h + 16;
330 messagearea_lines = MAXMESSAGES;
331 messagearea_trailing_y = messagearea_y + MAXMESSAGES;
332 messagearea_trailing_h = 0;
333 statusarea_h = statusarea_lines * 16;
334 messagearea_h = messagearea_lines * 16 + messagearea_trailing_h;
337 sdlw_display_parameters::sdlw_display_parameters(uint32_t rscrw, uint32_t rscrh, bool cactive)
339 real_screen_w = rscrw;
340 real_screen_h = rscrh;
341 fullscreen_console = cactive;
342 virtual_screen_w = (((real_screen_w < 512) ? 512 : real_screen_w) + 15) >> 4 << 4;
343 virtual_screen_h = (((real_screen_w < 448) ? 448 : real_screen_h) + 15) >> 4 << 4;
344 display_w = virtual_screen_w + 278;
345 display_h = virtual_screen_h + 16 * MAXMESSAGES + 48;
346 screenarea_x = 6;
347 screenarea_y = 6;
348 statusarea_x = virtual_screen_w + 16;
349 statusarea_y = 6;
350 messagearea_x = 6;
351 cmdline_x = 6;
352 cmdline_y = display_h - 22;
353 cmdline_w = display_w - 12;
354 messagearea_w = display_w - 12;
355 if(fullscreen_console) {
356 screenarea_w = 0;
357 screenarea_h = 0;
358 statusarea_w = 0;
359 statusarea_lines = 0;
360 messagearea_y = 6;
361 messagearea_lines = (display_h - 38) / 16;
362 messagearea_trailing_y = messagearea_y + 16 * messagearea_lines;
363 messagearea_trailing_h = (display_h - 38) % 16;
364 } else {
365 screenarea_w = virtual_screen_w;
366 screenarea_h = virtual_screen_h;
367 statusarea_w = 256;
368 statusarea_lines = virtual_screen_h / 16;
369 messagearea_y = virtual_screen_h + 16;
370 messagearea_lines = MAXMESSAGES;
371 messagearea_trailing_y = messagearea_y + MAXMESSAGES;
372 messagearea_trailing_h = 0;
374 statusarea_h = statusarea_lines * 16;
375 messagearea_h = messagearea_lines * 16 + messagearea_trailing_h;
378 bool paint_command(SDL_Surface* surf, const sdlw_display_parameters& p, bool full)
380 static bool cached_command_active = false;
381 static bool cached_overwrite = false;
382 static uint32_t cached_rawcursor = 0;
383 static std::string cached_command;
385 //Query status of command line.
386 auto cmd = get_current_command();
388 if(full) {
389 draw_box(surf, p.cmdline_x, p.cmdline_y, p.cmdline_w, 16, surf->format->Gmask);
390 cached_command_active = false;
391 cached_overwrite = false;
392 cached_rawcursor = 0;
393 cached_command = "";
395 if(cached_command_active == cmd.active && cached_overwrite == cmd.overwrite &&
396 cached_rawcursor == cmd.rawpos && cached_command == cmd.encoded)
397 return full;
398 try {
399 if(cmd.active) {
400 //FIXME, scroll text if too long.
401 uint32_t hilite_mode = cmd.overwrite ? 2 : 1;
402 auto s2 = decode_utf8(sdlw_decode_string(cmd.encoded));
403 draw_string(reinterpret_cast<uint8_t*>(surf->pixels), surf->pitch, surf->format->BytesPerPixel,
404 s2, p.cmdline_x, p.cmdline_y, p.cmdline_w, 0xFFFFFFFFU, hilite_mode, cmd.rawpos / 4);
405 } else
406 draw_string(reinterpret_cast<uint8_t*>(surf->pixels), surf->pitch, surf->format->BytesPerPixel,
407 "", p.cmdline_x, p.cmdline_y, p.cmdline_w, 0xFFFFFFFFU);
408 cached_command_active = cmd.active;
409 cached_overwrite = cmd.overwrite;
410 cached_rawcursor = cmd.rawpos;
411 cached_command = cmd.encoded;
412 } catch(...) {
414 return true;
417 bool paint_messages(SDL_Surface* surf, const sdlw_display_parameters& p, bool full)
419 static uint64_t cached_first = 0;
420 static uint64_t cached_messages = 0;
421 if(full) {
422 draw_box(surf, p.messagearea_x, p.messagearea_y, p.messagearea_w, p.messagearea_h,
423 surf->format->Gmask);
424 cached_first = 0;
425 cached_messages = 0;
427 uint32_t message_y = p.messagearea_y;
428 size_t maxmessages = window::msgbuf.get_max_window_size();
429 size_t msgnum = window::msgbuf.get_visible_first();
430 size_t visible = window::msgbuf.get_visible_count();
431 if((!visible && cached_messages == 0) || (msgnum == cached_first && visible == cached_messages))
432 return full;
433 if(cached_messages == 0)
434 cached_first = msgnum; //Little trick.
435 for(size_t j = 0; j < maxmessages; j++)
436 try {
437 if(msgnum == cached_first && j < cached_messages)
438 continue; //Don't draw lines that stayed the same.
439 if(j >= visible && j >= cached_messages)
440 continue; //Don't draw blank lines.
441 std::ostringstream o;
442 if(j < visible)
443 o << (msgnum + j + 1) << ": " << window::msgbuf.get_message(msgnum + j);
444 draw_string(reinterpret_cast<uint8_t*>(surf->pixels), surf->pitch,
445 surf->format->BytesPerPixel, o.str(), p.messagearea_x,
446 message_y + 16 * j, p.messagearea_w, 0xFFFFFFFFU);
447 } catch(...) {
449 if(window::msgbuf.is_more_messages())
450 try {
451 draw_string(reinterpret_cast<uint8_t*>(surf->pixels), surf->pitch,
452 surf->format->BytesPerPixel, "--More--",
453 p.messagearea_x + p.messagearea_w - 64, message_y + 16 * maxmessages - 16, 64,
454 0xFFFFFFFFU);
455 } catch(...) {
457 cached_first = msgnum;
458 cached_messages = visible;
459 return true;
462 bool paint_status(SDL_Surface* surf, const sdlw_display_parameters& p, bool full)
464 auto& status = window::get_emustatus();
465 try {
466 std::ostringstream y;
467 y << get_framerate();
468 status["FPS"] = y.str();
469 } catch(...) {
471 if(!p.statusarea_w || !p.statusarea_h)
472 return full;
473 uint32_t y = p.statusarea_y;
474 uint32_t lines = 0;
475 static std::map<std::string, std::string> old_status;
476 size_t old_lines = old_status.size();
477 if(full) {
478 old_status.clear();
479 draw_box(surf, p.statusarea_x, p.statusarea_y, p.statusarea_w, p.statusarea_h,
480 surf->format->Gmask);
482 bool paint_any = false;
483 bool desynced = false;
484 for(auto i : status) {
485 if(!old_status.count(i.first))
486 desynced = true;
487 if(!desynced && old_status[i.first] == i.second) {
488 y += 16;
489 lines++;
490 continue;
492 //Paint in full.
493 paint_any = true;
494 try {
495 std::string str = i.first + " " + i.second;
496 draw_string(reinterpret_cast<uint8_t*>(surf->pixels), surf->pitch,
497 surf->format->BytesPerPixel, str, p.statusarea_x, y, p.statusarea_w,
498 0xFFFFFFFFU);
499 old_status[i.first] = i.second;
500 } catch(...) {
502 y += 16;
503 lines++;
505 for(size_t i = lines; i < old_lines; i++) {
506 draw_string(reinterpret_cast<uint8_t*>(surf->pixels), surf->pitch,
507 surf->format->BytesPerPixel, "", p.statusarea_x, y, p.statusarea_w, 0);
508 y += 16;
510 return paint_any || full;
513 bool paint_screen(SDL_Surface* surf, const sdlw_display_parameters& p, bool full)
515 if(full) {
516 draw_box(surf, p.screenarea_x, p.screenarea_y, p.screenarea_w, p.screenarea_h,
517 surf->format->Gmask);
521 void paint_modal_dialog(SDL_Surface* surf, const std::string& text, bool confirm)
523 std::string realtext;
524 if(confirm)
525 realtext = text + "\n\nHit Enter to confirm, Esc to cancel";
526 else
527 realtext = text + "\n\nHit Enter or Esc to dismiss";
528 unsigned extent_w = 0;
529 unsigned extent_h = 0;
530 int32_t pos_x = 0;
531 int32_t pos_y = 0;
532 auto s2 = decode_utf8(realtext);
533 for(auto i : s2) {
534 auto g = find_glyph(i, pos_x, pos_y, 0, pos_x, pos_y);
535 if(pos_x + g.first > extent_w)
536 extent_w = static_cast<uint32_t>(pos_x + g.first);
537 if(pos_y + 16 > static_cast<int32_t>(extent_h))
538 extent_h = static_cast<uint32_t>(pos_y + 16);
540 uint32_t x1;
541 uint32_t x2;
542 uint32_t y1;
543 uint32_t y2;
544 if(extent_w + 12 >= static_cast<uint32_t>(surf->w)) {
545 x1 = 6;
546 x2 = surf->w - 6;
547 extent_w = x2 - x1;
548 } else {
549 x1 = (surf->w - extent_w) / 2;
550 x2 = x1 + extent_w;
552 if(extent_h + 12 >= static_cast<uint32_t>(surf->h)) {
553 y1 = 6;
554 y2 = surf->h - 6;
555 extent_h = y2 - y1;
556 } else {
557 y1 = (surf->h - extent_h) / 2;
558 y2 = y1 + extent_h;
560 uint32_t color = surf->format->Rmask | ((surf->format->Gmask >> 1) & surf->format->Gmask);
561 draw_box(surf, x1, y1, extent_w, extent_h, color);
562 draw_string(reinterpret_cast<uint8_t*>(surf->pixels), surf->pitch, surf->format->BytesPerPixel, s2,
563 x1, y1, extent_w, color);
566 void sdlw_paint_modal_dialog(const std::string& text, bool confirm)
568 modal_dialog_shown = true;
569 modal_dialog_text = text;
570 modal_dialog_confirm = confirm;
571 SDL_LockSurface(hwsurf);
572 paint_modal_dialog(hwsurf, text, confirm);
573 SDL_UnlockSurface(hwsurf);
574 SDL_UpdateRect(hwsurf, 0, 0, 0, 0);
577 void sdlw_clear_modal_dialog()
579 modal_dialog_shown = false;
583 namespace
585 class painter_listener : public information_dispatch
587 public:
588 painter_listener();
589 void on_screen_resize(screen& scr, uint32_t w, uint32_t h);
590 void on_render_update_start();
591 void on_render_update_end();
592 void on_status_update();
593 } plistener;
595 painter_listener::painter_listener() : information_dispatch("SDL-painter-listener") {}
597 void painter_listener::on_screen_resize(screen& scr, uint32_t w, uint32_t h)
599 if(w != dp.real_screen_w || h != dp.real_screen_h || !hwsurf ||
600 fullscreen_console_active != dp.fullscreen_console) {
601 dp = sdlw_display_parameters(w, h, fullscreen_console_active);
602 SDL_Surface* hwsurf2 = SDL_SetVideoMode(dp.display_w, dp.display_h, 32, SDL_SWSURFACE);
603 if(!hwsurf2) {
604 //We are in too fucked up state to even print error as message.
605 std::cout << "PANIC: Can't create/resize window: " << SDL_GetError() << std::endl;
606 exit(1);
608 hwsurf = hwsurf2;
610 scr.set_palette(hwsurf->format->Rshift, hwsurf->format->Gshift, hwsurf->format->Bshift);
611 if(fullscreen_console_active)
612 //We have to render to memory buffer.
613 scr.reallocate(w, h, false);
614 else {
615 //Render direct to screen. But delay setting the buffer.
617 our_screen = &scr;
620 void painter_listener::on_render_update_start()
622 if(fullscreen_console_active)
623 return;
624 SDL_LockSurface(hwsurf);
625 video_locked = true;
626 our_screen->set(reinterpret_cast<uint32_t*>(reinterpret_cast<uint8_t*>(hwsurf->pixels) +
627 dp.screenarea_y * hwsurf->pitch + dp.screenarea_y * hwsurf->format->BytesPerPixel),
628 dp.real_screen_w, dp.real_screen_h, hwsurf->pitch);
629 our_screen->set_palette(hwsurf->format->Rshift, hwsurf->format->Gshift, hwsurf->format->Bshift);
632 void painter_listener::on_render_update_end()
634 if(!video_locked)
635 return;
636 SDL_UnlockSurface(hwsurf);
637 video_locked = false;
638 if(screen_paintable) {
639 SDL_UpdateRect(hwsurf, 6, 6, dp.real_screen_w, dp.real_screen_h);
640 screen_paintable = false;
641 } else
642 screen_dirty = true;
643 have_received_frames = true;
646 void painter_listener::on_status_update()
648 SDL_LockSurface(hwsurf);
649 bool update = paint_status(hwsurf, dp, false);
650 SDL_UnlockSurface(hwsurf);
651 if(update)
652 SDL_UpdateRect(hwsurf, dp.statusarea_x, dp.statusarea_y, dp.statusarea_w, dp.statusarea_h);
656 void sdlw_command_updated()
658 SDL_LockSurface(hwsurf);
659 bool update = paint_command(hwsurf, dp, false);
660 SDL_UnlockSurface(hwsurf);
661 if(update)
662 SDL_UpdateRect(hwsurf, dp.cmdline_x, dp.cmdline_y, dp.cmdline_w, 16);
665 void sdlw_screen_paintable()
667 if(screen_dirty) {
668 SDL_UpdateRect(hwsurf, 6, 6, dp.real_screen_w, dp.real_screen_h);
669 screen_dirty = false;
670 } else
671 screen_paintable = true;
674 void window::notify_message() throw(std::bad_alloc, std::runtime_error)
676 SDL_LockSurface(hwsurf);
677 bool update = paint_messages(hwsurf, dp, false);
678 SDL_UnlockSurface(hwsurf);
679 if(update)
680 SDL_UpdateRect(hwsurf, dp.messagearea_x, dp.messagearea_y, dp.messagearea_w, dp.messagearea_h);
683 void sdlw_fullscreen_console(bool enable)
685 fullscreen_console_active = enable;
686 window::msgbuf.set_max_window_size(dp.messagearea_lines);
687 sdlw_force_paint();
690 void sdlw_force_paint()
692 if(!hwsurf) {
693 //Initialize video.
694 dp = sdlw_display_parameters(0, 0, fullscreen_console_active);
695 SDL_Surface* hwsurf2 = SDL_SetVideoMode(dp.display_w, dp.display_h, 32, SDL_SWSURFACE);
696 if(!hwsurf2) {
697 //We are in too fucked up state to even print error as message.
698 std::cout << "PANIC: Can't create/resize window: " << SDL_GetError() << std::endl;
699 exit(1);
701 hwsurf = hwsurf2;
703 SDL_LockSurface(hwsurf);
704 paint_screen(hwsurf, dp, true);
705 paint_status(hwsurf, dp, true);
706 paint_messages(hwsurf, dp, true);
707 paint_command(hwsurf, dp, true);
708 SDL_UnlockSurface(hwsurf);
709 SDL_UpdateRect(hwsurf, 0, 0, 0, 0);
710 if(have_received_frames)
711 redraw_framebuffer();
712 if(modal_dialog_shown) {
713 SDL_LockSurface(hwsurf);
714 paint_modal_dialog(hwsurf, modal_dialog_text, modal_dialog_confirm);
715 SDL_UnlockSurface(hwsurf);
716 SDL_UpdateRect(hwsurf, 0, 0, 0, 0);
720 std::string sdlw_decode_string(std::string e)
722 std::string x;
723 for(size_t i = 0; i < e.length(); i += 4) {
724 char tmp[5] = {0};
725 uint32_t c1 = e[i] - 33;
726 uint32_t c2 = e[i + 1] - 33;
727 uint32_t c3 = e[i + 2] - 33;
728 uint32_t c4 = e[i + 3] - 33;
729 uint32_t c = (c1 << 18) | (c2 << 12) | (c3 << 6) | c4;
730 if(c < 0x80) {
731 tmp[0] = c;
732 } else if(c < 0x800) {
733 tmp[0] = 0xC0 | (c >> 6);
734 tmp[1] = 0x80 | (c & 0x3F);
735 } else if(c < 0x10000) {
736 tmp[0] = 0xE0 | (c >> 12);
737 tmp[1] = 0x80 | ((c >> 6) & 0x3F);
738 tmp[2] = 0x80 | (c & 0x3F);
739 } else {
740 tmp[0] = 0xF0 | (c >> 18);
741 tmp[1] = 0x80 | ((c >> 12) & 0x3F);
742 tmp[2] = 0x80 | ((c >> 6) & 0x3F);
743 tmp[3] = 0x80 | (c & 0x3F);
745 x = x + tmp;
747 return x;