diff --git a/SDL/window-sdl.cpp b/SDL/window-sdl.cpp index 7d6a1335..0c9416e7 100644 --- a/SDL/window-sdl.cpp +++ b/SDL/window-sdl.cpp @@ -488,6 +488,8 @@ namespace std::list::iterator commandhistory_itr; screen* current_screen; SDL_Surface* hwsurf; + SDL_Surface* swsurf; + std::pair current_windowsize; bool pause_active; uint64_t last_ui_update; bool screen_is_dirty; @@ -615,17 +617,17 @@ namespace } void draw_rectangle(uint8_t* data, uint32_t pitch, uint32_t x1, uint32_t y1, uint32_t x2, uint32_t y2, - uint32_t color, uint32_t thickness) + uint16_t color, uint32_t thickness) { for(uint32_t i = x1; i < x2; i++) for(uint32_t j = 0; j < thickness; j++) { - reinterpret_cast(data + pitch * (y1 + j))[i] = color; - reinterpret_cast(data + pitch * (y2 - 1 - j))[i] = color; + reinterpret_cast(data + pitch * (y1 + j))[i] = color; + reinterpret_cast(data + pitch * (y2 - 1 - j))[i] = color; } for(uint32_t i = y1; i < y2; i++) for(uint32_t j = 0; j < thickness; j++) { - reinterpret_cast(data + pitch * i)[x1 + j] = color; - reinterpret_cast(data + pitch * i)[x2 - 1 - j] = color; + reinterpret_cast(data + pitch * i)[x1 + j] = color; + reinterpret_cast(data + pitch * i)[x2 - 1 - j] = color; } } @@ -658,7 +660,7 @@ namespace void draw_string(uint8_t* base, uint32_t pitch, std::vector s, uint32_t x, uint32_t y, uint32_t maxwidth, uint32_t hilite_mode = 0, uint32_t hilite_pos = 0) { - base += y * static_cast(pitch) + 4 * x; + base += y * static_cast(pitch) + 2 * x; int32_t pos_x = 0; int32_t pos_y = 0; unsigned c = 0; @@ -675,35 +677,34 @@ namespace if(g.second == 0) { //Empty glyph. for(unsigned j = 0; j < 16; j++) { - uint32_t* ptr = reinterpret_cast(base + pitch * j); + uint16_t* ptr = reinterpret_cast(base + pitch * j); for(unsigned i = 0; i < g.first && old_x + i < maxwidth; i++) - ptr[old_x + i] = (j >= curstart) ? 0xFFFFFFFFU : 0; + ptr[old_x + i] = (j >= curstart) ? 0x7FFFU : 0; } } else { //Narrow/Wide glyph. for(unsigned j = 0; j < 16; j++) { - uint32_t* ptr = reinterpret_cast(base + pitch * j); + uint16_t* ptr = reinterpret_cast(base + pitch * j); uint32_t dataword = fontdata[g.second + j / 4]; for(uint32_t i = 0; i < g.first && old_x + i < maxwidth; i++) { bool b = (((dataword >> (31 - (j % (32 / g.first)) * g.first - i)) & 1)); b ^= (j >= curstart); - ptr[old_x + i] = b ? 0xFFFFFFFFU : 0; + ptr[old_x + i] = b ? 0x7FFFU : 0; } } } c++; } for(unsigned j = 0; j < 16; j++) { - uint32_t* ptr = reinterpret_cast(base + pitch * j); + uint16_t* ptr = reinterpret_cast(base + pitch * j); uint32_t curstart = 16; if(c == hilite_pos && hilite_mode == 1) curstart = 14; if(c == hilite_pos && hilite_mode == 2) curstart = 0; - for(uint32_t i = pos_x; i < maxwidth; i++) { - ptr[i] = ((i - pos_x) < 8 && j >= curstart) ? 0xFFFFFFFFU : 0; - } + for(uint32_t i = pos_x; i < maxwidth; i++) + ptr[i] = ((i - pos_x) < 8 && j >= curstart) ? 0x7FFFU : 0; } } @@ -760,11 +761,10 @@ namespace y1 = (surf->h - height) / 2; y2 = y1 + height; } - SDL_LockSurface(surf); for(uint32_t j = y1 - 6; j < y2 + 6; j++) - memset(reinterpret_cast(surf->pixels) + j * surf->pitch + 4 * (x1 - 6), 0, - 4 * (x2 - x1 + 12)); - uint32_t bordercolor = (128 << surf->format->Gshift) | (255 << surf->format->Rshift); + memset(reinterpret_cast(surf->pixels) + j * surf->pitch + 2 * (x1 - 6), 0, + 2 * (x2 - x1 + 12)); + uint16_t bordercolor = 0x7E00; draw_rectangle(reinterpret_cast(surf->pixels), surf->pitch, x1 - 4, y1 - 4, x2 + 4, y2 + 4, bordercolor, 2); @@ -777,11 +777,11 @@ namespace if(static_cast(pos_y) > height) break; uint8_t* base = reinterpret_cast(surf->pixels) + (y1 + oy) * surf->pitch + - 4 * (x1 + ox); + 2 * (x1 + ox); if(g.second) { //Narrow/Wide glyph. for(unsigned j = 0; j < 16; j++) { - uint32_t* ptr = reinterpret_cast(base + surf->pitch * j); + uint16_t* ptr = reinterpret_cast(base + surf->pitch * j); uint32_t dataword = fontdata[g.second + j / 4]; for(uint32_t i = 0; i < g.first && (ox + i) < width; i++) { bool b = (((dataword >> (31 - (j % (32 / g.first)) * g.first - i)) & @@ -789,7 +789,6 @@ namespace ptr[i] = b ? bordercolor : 0; } } - } } } @@ -1087,6 +1086,7 @@ void window::init() current_screen = NULL; pause_active = false; hwsurf = NULL; + swsurf = NULL; command_overwrite = false; old_screen_h = 0; old_screen_w = 0; @@ -1205,146 +1205,211 @@ void window::set_main_surface(screen& scr) throw() notify_screen_update(true); } -void window::notify_screen_update(bool full) throw() +namespace { - uint64_t curtime = get_ticks_msec(); - if(!full && last_ui_update < curtime && last_ui_update + MIN_UPDATE_TIME > curtime) { - screen_is_dirty = true; - return; - } - last_ui_update = curtime; - screen_is_dirty = false; - - try { - std::ostringstream y; - y << get_framerate(); - emustatus["FPS"] = y.str(); - } catch(...) { - } - - std::string command_showas = decode_string(command_buf); - uint32_t screen_w = 512; - uint32_t screen_h = 448; - if(current_screen && current_screen->width >= 512 && current_screen->height >= 448) { - screen_w = current_screen->width; - screen_h = current_screen->height; - } - uint32_t win_w = ((screen_w < 512) ? 512 : ((screen_w + 15) / 16 * 16)) + 278; - uint32_t win_h = screen_h + MAXMESSAGES * 16 + 48; - if(!hwsurf || static_cast(hwsurf->w) != win_w || static_cast(hwsurf->h) != win_h || - old_screen_w != screen_w || old_screen_h != screen_h || full) { - //Create/Resize the window. - if(!hwsurf || static_cast(hwsurf->w) != win_w || static_cast(hwsurf->h) != win_h) { - SDL_Surface* hwsurf2 = SDL_SetVideoMode(win_w, win_h, 32, SDL_SWSURFACE | SDL_DOUBLEBUF); - if(!hwsurf2) { - //We are in too fucked up state to even print error as message. - std::cout << "PANIC: Can't create/resize window: " << SDL_GetError() << std::endl; - exit(1); - } - hwsurf = hwsurf2; + bool is_time_for_screen_update(bool full) + { + uint64_t curtime = get_ticks_msec(); + //Always do full updates. + if(!full && last_ui_update < curtime && last_ui_update + MIN_UPDATE_TIME > curtime) { + screen_is_dirty = true; + return false; } - if(current_screen) - current_screen->set_palette(hwsurf->format->Rshift, hwsurf->format->Gshift, - hwsurf->format->Bshift); + last_ui_update = curtime; + screen_is_dirty = false; + return true; + } + + std::pair compute_screen_size(uint32_t width, uint32_t height) + { + if(width < 512) + width = 512; + if(height < 448) + height = 448; + return std::make_pair(width, height); + } + + std::pair compute_window_size(uint32_t width, uint32_t height) + { + auto g = compute_screen_size(width, height); + uint32_t win_w = ((g.first + 15) >> 4 << 4) + 278; + uint32_t win_h = g.second + MAXMESSAGES * 16 + 48; + return std::make_pair(win_w, win_h); + } + + void show_fps() + { + try { + std::ostringstream y; + y << get_framerate(); + emustatus["FPS"] = y.str(); + } catch(...) { + } + } + + void redraw_borders(SDL_Surface* swsurf, std::pair screensize, + std::pair windowsize) + { //Blank the screen and draw borders. - SDL_LockSurface(hwsurf); - memset(hwsurf->pixels, 0, win_h * hwsurf->pitch); - uint32_t bordercolor = 255 << hwsurf->format->Gshift; - if(console_mode) { - draw_rectangle(reinterpret_cast(hwsurf->pixels), hwsurf->pitch, 2, 2, win_w - 2, - win_h - 28, bordercolor, 2); - draw_rectangle(reinterpret_cast(hwsurf->pixels), hwsurf->pitch, 2, win_h - 26, - win_w - 2, win_h - 2, bordercolor, 2); - } else { - draw_rectangle(reinterpret_cast(hwsurf->pixels), hwsurf->pitch, 2, 2, screen_w + 10, - screen_h + 10, bordercolor, 2); - draw_rectangle(reinterpret_cast(hwsurf->pixels), hwsurf->pitch, screen_w + 12, 2, - screen_w + 276, screen_h + 10, bordercolor, 2); - draw_rectangle(reinterpret_cast(hwsurf->pixels), hwsurf->pitch, 2, screen_h + 12, - win_w - 2, screen_h + MAXMESSAGES * 16 + 20, bordercolor, 2); - draw_rectangle(reinterpret_cast(hwsurf->pixels), hwsurf->pitch, 2, - screen_h + MAXMESSAGES * 16 + 22, win_w - 2, screen_h + MAXMESSAGES * 16 + 46, - bordercolor, 2); + memset(swsurf->pixels, 0, windowsize.second * swsurf->pitch); + uint32_t bordercolor = 0x03E0; + uint32_t msgbox_min_x = 2; + uint32_t msgbox_min_y = 2; + uint32_t msgbox_max_x = windowsize.first - 2; + uint32_t msgbox_max_y = windowsize.second - 28; + uint32_t cmdbox_min_x = 2; + uint32_t cmdbox_max_x = windowsize.first - 2; + uint32_t cmdbox_min_y = windowsize.second - 26; + uint32_t cmdbox_max_y = windowsize.second - 2; + if(!console_mode) { + uint32_t scrbox_min_x = 2; + uint32_t scrbox_max_x = screensize.first + 10; + uint32_t scrbox_min_y = 2; + uint32_t scrbox_max_y = screensize.second + 10; + uint32_t stsbox_min_x = screensize.first + 12; + uint32_t stsbox_max_x = windowsize.first - 2; + uint32_t stsbox_min_y = 2; + uint32_t stsbox_max_y = screensize.second + 10; + uint32_t msgbox_min_y = screensize.second + 12; + draw_rectangle(reinterpret_cast(swsurf->pixels), swsurf->pitch, scrbox_min_x, + scrbox_min_y, scrbox_max_x, scrbox_max_y, bordercolor, 2); + draw_rectangle(reinterpret_cast(swsurf->pixels), swsurf->pitch, stsbox_min_x, + stsbox_min_y, stsbox_max_x, stsbox_max_y, bordercolor, 2); } - SDL_UnlockSurface(hwsurf); - old_screen_w = screen_w; - old_screen_h = screen_h; + draw_rectangle(reinterpret_cast(swsurf->pixels), swsurf->pitch, msgbox_min_x, + msgbox_min_y, msgbox_max_x, msgbox_max_y, bordercolor, 2); + draw_rectangle(reinterpret_cast(swsurf->pixels), swsurf->pitch, cmdbox_min_x, + cmdbox_min_y, cmdbox_max_x, cmdbox_max_y, bordercolor, 2); } - SDL_LockSurface(hwsurf); - if(!console_mode) { + + void draw_main_screen(SDL_Surface* swsurf, std::pair screensize) + { + uint32_t cw = current_screen ? current_screen->width : 0; + uint32_t ch = current_screen ? current_screen->height : 0; + //Blank parts not drawn. + for(uint32_t i = 6; i < ch + 6; i++) + memset(reinterpret_cast(swsurf->pixels) + i * swsurf->pitch + 12 + 2 * cw, 0, + 2 * (screensize.first - cw)); + for(uint32_t i = ch + 6; i < screensize.second + 6; i++) + memset(reinterpret_cast(swsurf->pixels) + i * swsurf->pitch + 12, 0, + 2 * screensize.first); if(current_screen) { - //Draw main screen (blanking background if needed). - if(screen_w < current_screen->width || screen_h < current_screen->height) - for(uint32_t i = 6; i < screen_h + 6; i++) - memset(reinterpret_cast(hwsurf->pixels) + i * hwsurf->pitch + 24, 0, - 4 * screen_w); - for(uint32_t i = 0; i < current_screen->height; i++) - memcpy(reinterpret_cast(hwsurf->pixels) + (i + 6) * hwsurf->pitch + 24, + for(uint32_t i = 0; i < ch; i++) + memcpy(reinterpret_cast(swsurf->pixels) + (i + 6) * swsurf->pitch + 12, reinterpret_cast(current_screen->memory) + current_screen->pitch * i, - 4 * current_screen->width); - } else { - //Draw blank. - for(uint32_t i = 6; i < screen_h + 6; i++) - memset(reinterpret_cast(hwsurf->pixels) + i * hwsurf->pitch + 24, 0, - 4 * screen_w); + 2 * cw); } - //Draw status. - uint32_t status_x = screen_w + 16; + } + + void draw_status_area(SDL_Surface* swsurf, std::pair screensize) + { + uint32_t status_x = screensize.first + 16; uint32_t status_y = 6; for(auto i = emustatus.begin(); i != emustatus.end(); i++) { std::string msg = i->first + " " + i->second; - draw_string(reinterpret_cast(hwsurf->pixels), hwsurf->pitch, msg, status_x, status_y, + draw_string(reinterpret_cast(swsurf->pixels), swsurf->pitch, msg, status_x, status_y, 256); status_y += 16; } - while(status_y - 6 < screen_h / 16 * 16) { - draw_string(reinterpret_cast(hwsurf->pixels), hwsurf->pitch, "", status_x, status_y, + while(status_y - 6 < screensize.second / 16 * 16) { + draw_string(reinterpret_cast(swsurf->pixels), swsurf->pitch, "", status_x, status_y, 256); status_y += 16; } } - //Draw messages. - uint32_t message_y; - if(!console_mode) - message_y = screen_h + 16; - else - message_y = 6; - for(size_t j = 0; j < maxmessages; j++) - try { - std::ostringstream o; - if(messagebuffer_first_show + j < messagebuffer_next_seq) - o << (messagebuffer_first_show + j + 1) << ": " - << messagebuffer[messagebuffer_first_show + j]; - draw_string(reinterpret_cast(hwsurf->pixels), hwsurf->pitch, o.str(), 6, - message_y + 16 * j, win_w - 12); - } catch(...) { - } - if(messagebuffer_next_seq - messagebuffer_first_show > maxmessages) - try { - draw_string(reinterpret_cast(hwsurf->pixels), hwsurf->pitch, "--More--", win_w - 76, - message_y + 16 * maxmessages - 16, 64); - } catch(...) { - } - //Draw command_buf. - uint32_t command_y = win_h - 22; - try { - if(state == WINSTATE_COMMAND) - draw_command(reinterpret_cast(hwsurf->pixels), hwsurf->pitch, command_showas, - command_cursor / 4, 6, command_y, win_w - 12, command_overwrite); + void draw_messages(SDL_Surface* swsurf, std::pair screensize, + std::pair windowsize) + { + uint32_t message_y; + if(!console_mode) + message_y = screensize.second + 16; else - draw_string(reinterpret_cast(hwsurf->pixels), hwsurf->pitch, "", 6, command_y, - win_w - 12); - } catch(...) { + message_y = 6; + for(size_t j = 0; j < maxmessages; j++) + try { + std::ostringstream o; + if(messagebuffer_first_show + j < messagebuffer_next_seq) + o << (messagebuffer_first_show + j + 1) << ": " + << messagebuffer[messagebuffer_first_show + j]; + draw_string(reinterpret_cast(swsurf->pixels), swsurf->pitch, o.str(), 6, + message_y + 16 * j, windowsize.first - 12); + } catch(...) { + } + if(messagebuffer_next_seq - messagebuffer_first_show > maxmessages) + try { + draw_string(reinterpret_cast(swsurf->pixels), swsurf->pitch, "--More--", + windowsize.first - 76, message_y + 16 * maxmessages - 16, 64); + } catch(...) { + } } + + void draw_command(SDL_Surface* swsurf, std::pair windowsize) + { + uint32_t command_y = windowsize.second - 22; + try { + std::string command_showas = decode_string(command_buf); + if(state == WINSTATE_COMMAND) + draw_command(reinterpret_cast(swsurf->pixels), swsurf->pitch, command_showas, + command_cursor / 4, 6, command_y, windowsize.first - 12, command_overwrite); + else + draw_string(reinterpret_cast(swsurf->pixels), swsurf->pitch, "", 6, + command_y, windowsize.first - 12); + } catch(...) { + } + } +} + +void window::notify_screen_update(bool full) throw() +{ + bool resize_screen = false; + if(!is_time_for_screen_update(full)) + return; + auto windowsize = compute_window_size(current_screen ? current_screen->width : 0, current_screen ? + current_screen->height : 0); + auto screensize = compute_screen_size(current_screen ? current_screen->width : 0, current_screen ? + current_screen->height : 0); + show_fps(); + + + if(!hwsurf || windowsize != current_windowsize) { + //Create/Resize the window. + SDL_Surface* hwsurf2 = SDL_SetVideoMode(windowsize.first, windowsize.second, 0, SDL_SWSURFACE | + SDL_ANYFORMAT); + SDL_Surface* swsurf2 = SDL_CreateRGBSurface(SDL_SWSURFACE, windowsize.first, windowsize.second, 16, + 0x7E00, 0x03E0, 0x001F, 0); + if(!hwsurf2 || !swsurf2) { + //We are in too fucked up state to even print error as message. + std::cout << "PANIC: Can't create/resize window: " << SDL_GetError() << std::endl; + exit(1); + } + if(swsurf) + SDL_FreeSurface(swsurf); + hwsurf = hwsurf2; + swsurf = swsurf2; + full = true; + current_windowsize = windowsize; + } + + SDL_LockSurface(swsurf); + if(full) + redraw_borders(swsurf, screensize, windowsize); + if(!console_mode) { + draw_main_screen(swsurf, screensize); + draw_status_area(swsurf, screensize); + } + draw_messages(swsurf, screensize, windowsize); + draw_command(swsurf, windowsize); + //Draw modal dialog. if(state == WINSTATE_MODAL) try { - draw_modal_dialog(hwsurf, modmsg, modconfirm); + draw_modal_dialog(swsurf, modmsg, modconfirm); } catch(...) { } - SDL_UnlockSurface(hwsurf); - SDL_Flip(hwsurf); + SDL_UnlockSurface(swsurf); + SDL_BlitSurface(swsurf, NULL, hwsurf, NULL); + SDL_UpdateRect(hwsurf, 0, 0, 0, 0); } void poll_inputs_internal() throw(std::bad_alloc) @@ -1456,7 +1521,7 @@ namespace []() throw(std::bad_alloc, std::runtime_error) { console_mode = !console_mode; if(console_mode) - maxmessages = hwsurf ? (hwsurf->h - 38) / 16 : 36; + maxmessages = swsurf ? (swsurf->h - 38) / 16 : 36; else maxmessages = MAXMESSAGES; if(messagebuffer_next_seq < maxmessages) diff --git a/avidump/avidump-control.cpp b/avidump/avidump-control.cpp index d3d8c643..794c406e 100644 --- a/avidump/avidump-control.cpp +++ b/avidump/avidump-control.cpp @@ -47,9 +47,6 @@ namespace hscl = 2; if(dump_large && _frame.height < 400) vscl = 2; - uint32_t _magic = 403703808; - uint8_t* magic = reinterpret_cast(&_magic); - dscr.set_palette(magic[2], magic[1], magic[0]); struct lua_render_context lrc; render_queue rq; @@ -60,9 +57,6 @@ namespace lrc.queue = &rq; lrc.width = _frame.width * hscl; lrc.height = _frame.height * vscl; - lrc.rshift = magic[2]; - lrc.gshift = magic[1]; - lrc.bshift = magic[0]; lua_callback_do_video(&lrc); dscr.reallocate(lrc.left_gap + hscl * _frame.width + lrc.right_gap, lrc.top_gap + vscl * diff --git a/avidump/avidump.cpp b/avidump/avidump.cpp index bbce1cde..f0aa13e8 100644 --- a/avidump/avidump.cpp +++ b/avidump/avidump.cpp @@ -126,7 +126,7 @@ void avidumper::on_sample(short left, short right) throw(std::bad_alloc, std::ru audio_put_ptr = 0; } -void avidumper::on_frame(const uint32_t* data, uint16_t width, uint16_t height, uint32_t fps_n, uint32_t fps_d) +void avidumper::on_frame(const uint16_t* data, uint16_t width, uint16_t height, uint32_t fps_n, uint32_t fps_d) throw(std::bad_alloc, std::runtime_error) { if(capture_error) @@ -202,8 +202,8 @@ void avidumper::print_summary(std::ostream& str) str << s2.str(); } -void avidumper::on_frame_threaded(const uint32_t* data, uint16_t width, uint16_t height, uint32_t fps_n, uint32_t fps_d) - throw(std::bad_alloc, std::runtime_error) +void avidumper::on_frame_threaded(const uint16_t* data, uint16_t width, uint16_t height, uint32_t fps_n, + uint32_t fps_d) throw(std::bad_alloc, std::runtime_error) { //The AVI part of sound to write is [audio_get, audio_commit). We don't write part [audio_commit,audio_put) //yet, as it is being concurrently written. Also grab lock to read the commit value. Also, if global frame @@ -219,31 +219,49 @@ void avidumper::on_frame_threaded(const uint32_t* data, uint16_t width, uint16_t if(segment_movi_ptr > AVI_CUTOFF - 16 * segment_chunks.size() || (maxframes && segment_frames > maxframes)) fixup_avi_header_and_close(); + uint16_t rwidth = (width + 3) / 4 * 4; uint16_t rheight = (height + 3) / 4 * 4; bool this_is_keyframe; - if(width != pwidth || height != pheight || fps_n != pfps_n || fps_d != pfps_d || !avi_open) { + if(rwidth != pwidth || rheight != pheight || fps_n != pfps_n || fps_d != pfps_d || !avi_open) { std::cerr << "Starting segment # " << current_segment << ": " << width << "x" << height << "." << std::endl; fixup_avi_header_and_close(); - pwidth = width; - pheight = height; + pwidth = rwidth; + pheight = rheight; pfps_n = fps_n; pfps_d = fps_d; - pframe.resize(4 * static_cast(width) * height); - tframe.resize(4 * static_cast(width) * rheight); - cframe.resize(compressBound(4 * static_cast(width) * rheight) + 13); - memset(&tframe[0], 0, 4 * static_cast(width) * rheight); - open_and_write_avi_header(width, rheight, fps_n, fps_d); + pframe.resize(2 * static_cast(rwidth) * rheight); + tframe.resize(2 * static_cast(rwidth) * rheight); + cframe.resize(compressBound(tframe.size()) + 13); + memset(&tframe[0], 0, tframe.size()); + memset(&pframe[0], 0, pframe.size()); + open_and_write_avi_header(rwidth, rheight, fps_n, fps_d); } this_is_keyframe = (segment_frames == 0 || segment_frames - segment_last_keyframe >= keyframe_interval); - + uint8_t _magic[2] = {2, 1}; + uint16_t magic = *reinterpret_cast(_magic); + if(this_is_keyframe) { - memcpy(&tframe[0], data, 4 * static_cast(width) * height); + for(size_t i = 0; i < height; i++) + memcpy(&tframe[2 * i * rwidth], data + (i * width), 2 * width); + if(magic != 258) + for(size_t i = 0; i < tframe.size(); i += 2) { + tframe[i] ^= tframe[i + 1]; + tframe[i + 1] ^= tframe[i]; + tframe[i] ^= tframe[i + 1]; + } segment_last_keyframe = segment_frames; } else { - memcpy(&tframe[0], data, 4 * static_cast(width) * height); - for(size_t i = 0; i < 4 * static_cast(width) * height; i++) + for(size_t i = 0; i < height; i++) + memcpy(&tframe[2 * i * rwidth], data + (i * width), 2 * width); + if(magic != 258) + for(size_t i = 0; i < tframe.size(); i += 2) { + tframe[i] ^= tframe[i + 1]; + tframe[i + 1] ^= tframe[i]; + tframe[i] ^= tframe[i + 1]; + } + for(size_t i = 0; i < tframe.size(); i++) tframe[i] -= pframe[i]; } uLongf l = cframe.size() - 10; @@ -261,7 +279,7 @@ void avidumper::on_frame_threaded(const uint32_t* data, uint16_t width, uint16_t cframe[6] = (l + 2) >> 16; cframe[7] = (l + 2) >> 24; cframe[8] = (this_is_keyframe ? 0x3 : 0x2) | (compression_level << 4); - cframe[9] = 12; + cframe[9] = 4; avi_stream.write(reinterpret_cast(&cframe[0]), l + 10); if(!avi_stream) throw std::runtime_error("Error writing video frame"); @@ -276,7 +294,14 @@ void avidumper::on_frame_threaded(const uint32_t* data, uint16_t width, uint16_t if((segment_frames % 1200) == 0) print_summary(std::cerr); - memcpy(&pframe[0], data, 4 * static_cast(width) * height); + for(size_t i = 0; i < height; i++) + memcpy(&pframe[2 * i * rwidth], data + (i * width), 2 * width); + if(magic != 258) + for(size_t i = 0; i < pframe.size(); i += 2) { + pframe[i] ^= pframe[i + 1]; + pframe[i + 1] ^= pframe[i]; + pframe[i] ^= pframe[i + 1]; + } } void avidumper::on_end() throw(std::bad_alloc, std::runtime_error) @@ -477,16 +502,16 @@ void avidumper::open_and_write_avi_header(uint16_t width, uint16_t height, uint3 ptr(fixup_avi_length), u32(0), /* Video length (to be fixed later). */ u32(1000000), /* Suggested buffer size... Just give some random value. */ u32(9999), /* Quality... Doesn't matter. */ - u32(4), /* Video sample size... 32bpp. */ + u32(2), /* Video sample size... 16bpp. */ u32(0), u32(0), /* Bounding box upper left. */ u32(width), u32(height)); /* Bounding box lower right. */ /* BITMAPINFO header for the video stream. */ append(aviheader, str("strf"), u32(40), /* 40 byte header of type strf. */ u32(40), /* BITMAPINFOHEADER is 40 bytes. */ u32(width), u32(height), /* Image size. */ - u16(1), u16(32), /* 1 plane, 32 bits (RGB32). */ + u16(1), u16(16), /* 1 plane, 16 bits (RGB16). */ str("CSCD"), /* Compressed with Camstudio codec. */ - u32(4 * width * height), /* Image size. */ + u32(2 * width * height), /* Image size. */ u32(4000), u32(4000), /* Resolution... Give some random values. */ u32(0), u32(0)); /* Colors used values (0 => All colors used). */ /* Stream list header For stream #2, 104 bytes of data. */ diff --git a/avidump/avidump.hpp b/avidump/avidump.hpp index ff59b8de..adfc83dc 100644 --- a/avidump/avidump.hpp +++ b/avidump/avidump.hpp @@ -190,7 +190,7 @@ public: * throws std::bad_alloc: Not enough memory. * throws std::runtime_error: Error dumping frame. */ - void on_frame(const uint32_t* data, uint16_t width, uint16_t height, uint32_t fps_n, uint32_t fps_d) + void on_frame(const uint16_t* data, uint16_t width, uint16_t height, uint32_t fps_n, uint32_t fps_d) throw(std::bad_alloc, std::runtime_error); /** @@ -226,7 +226,7 @@ public: void set_capture_error(const char* err) throw(); private: void print_summary(std::ostream& str); - void on_frame_threaded(const uint32_t* data, uint16_t width, uint16_t height, uint32_t fps_n, uint32_t fps_d) + void on_frame_threaded(const uint16_t* data, uint16_t width, uint16_t height, uint32_t fps_n, uint32_t fps_d) throw(std::bad_alloc, std::runtime_error); void flush_audio_to(unsigned commit_ptr); void open_and_write_avi_header(uint16_t width, uint16_t height, uint32_t fps_n, uint32_t fps_d); @@ -274,7 +274,7 @@ private: thread_class* frame_thread; cv_class frame_cond; mutex_class frame_mutex; - const uint32_t* mt_data; + const uint16_t* mt_data; volatile uint16_t mt_width; volatile uint16_t mt_height; volatile uint32_t mt_fps_n; diff --git a/generic/framebuffer.cpp b/generic/framebuffer.cpp index 8cd8d03e..09b7a196 100644 --- a/generic/framebuffer.cpp +++ b/generic/framebuffer.cpp @@ -128,9 +128,6 @@ void redraw_framebuffer() lrc.queue = &rq; lrc.width = framebuffer.width * hscl; lrc.height = framebuffer.height * vscl; - lrc.rshift = main_screen.active_rshift; - lrc.gshift = main_screen.active_gshift; - lrc.bshift = main_screen.active_bshift; lua_callback_do_paint(&lrc); main_screen.reallocate(framebuffer.width * hscl + lrc.left_gap + lrc.right_gap, framebuffer.height * vscl + lrc.top_gap + lrc.bottom_gap, lrc.left_gap, lrc.top_gap); diff --git a/generic/lua.hpp b/generic/lua.hpp index cf11fe32..de0282cc 100644 --- a/generic/lua.hpp +++ b/generic/lua.hpp @@ -63,9 +63,6 @@ struct lua_render_context struct render_queue* queue; uint32_t width; uint32_t height; - uint32_t rshift; - uint32_t gshift; - uint32_t bshift; }; void init_lua() throw(); diff --git a/generic/render.cpp b/generic/render.cpp index 03c241dc..792b211f 100644 --- a/generic/render.cpp +++ b/generic/render.cpp @@ -29,12 +29,20 @@ extern uint32_t fontdata[]; namespace { - inline uint32_t blend(uint32_t orig, uint16_t ialpha, uint32_t pl, uint32_t ph) throw() + std::pair premultipy_color(uint16_t color, uint8_t alpha) { - const uint32_t X = 0xFF00FFU; - const uint32_t Y = 0xFF00FF00U; - return ((ialpha * ((orig >> 8) & X) + ph) & Y) | (((ialpha * (orig & X) + pl) - >> 8) & X); + uint32_t a, b; + a = color & 0x7C1F; + b = color & 0x03E0; + return std::make_pair(a * alpha, b * alpha); + } + + inline uint16_t blend(uint16_t orig, uint8_t ialpha, std::pair with) throw() + { + uint32_t a, b; + a = orig & 0x7C1F; + b = orig & 0x03E0; + return (((a * ialpha + with.first) >> 5) & 0x7C1F) | (((b * ialpha + with.second) >> 5) & 0x03E0); } //This is Jenkin's MIX function. @@ -107,15 +115,13 @@ render_object::~render_object() throw() { } -void render_text(struct screen& scr, int32_t x, int32_t y, const std::string& text, uint32_t fg, - uint16_t fgalpha, uint32_t bg, uint16_t bgalpha) throw(std::bad_alloc) +void render_text(struct screen& scr, int32_t x, int32_t y, const std::string& text, uint16_t fg, + uint8_t fgalpha, uint16_t bg, uint8_t bgalpha) throw(std::bad_alloc) { - uint32_t pfgl = (fg & 0xFF00FF) * fgalpha; - uint32_t pfgh = ((fg >> 8) & 0xFF00FF) * fgalpha; - uint32_t pbgl = (bg & 0xFF00FF) * bgalpha; - uint32_t pbgh = ((bg >> 8) & 0xFF00FF) * bgalpha; - uint16_t ifga = 256 - fgalpha; - uint16_t ibga = 256 - bgalpha; + auto pfg = premultipy_color(fg, fgalpha); + auto pbg = premultipy_color(bg, bgalpha); + uint8_t ifga = 32 - fgalpha; + uint8_t ibga = 32 - bgalpha; int32_t orig_x = x; uint32_t unicode_code = 0; uint8_t unicode_left = 0; @@ -171,20 +177,20 @@ void render_text(struct screen& scr, int32_t x, int32_t y, const std::string& te if(p.second == 0) { //Blank glyph. for(uint32_t j = 0; j < dh; j++) { - uint32_t* base = scr.rowptr(cy + j) + cx; + uint16_t* base = scr.rowptr(cy + j) + cx; for(uint32_t i = 0; i < dw; i++) - base[i] = blend(base[i], ibga, pbgl, pbgh); + base[i] = blend(base[i], ibga, pbg); } } else { //narrow/wide glyph. for(uint32_t j = 0; j < dh; j++) { uint32_t dataword = fontdata[p.second + (dy + j) / (32 / p.first)]; - uint32_t* base = scr.rowptr(cy + j) + cx; + uint16_t* base = scr.rowptr(cy + j) + cx; for(uint32_t i = 0; i < dw; i++) if(((dataword >> (31 - ((dy + j) % (32 / p.first)) * p.first - (dx + i))) & 1)) - base[i] = blend(base[i], ifga, pfgl, pfgh); + base[i] = blend(base[i], ifga, pfg); else - base[i] = blend(base[i], ibga, pbgl, pbgh); + base[i] = blend(base[i], ibga, pbg); } } x = next_x; @@ -221,11 +227,12 @@ render_queue::~render_queue() throw() clear(); } -uint32_t screen::make_color(uint8_t r, uint8_t g, uint8_t b) throw() +uint16_t screen::make_color(uint8_t r, uint8_t g, uint8_t b) throw() { - return (static_cast(r) << active_rshift) | - (static_cast(g) << active_gshift) | - (static_cast(b) << active_bshift); + uint16_t _r = r / 8; + uint16_t _g = g / 8; + uint16_t _b = b / 8; + return (_r << 10) + (_g << 5) + _b; } lcscreen::lcscreen(const uint16_t* mem, bool hires, bool interlace, bool overscan, bool region) throw() @@ -371,19 +378,19 @@ void screen::copy_from(lcscreen& scr, uint32_t hscale, uint32_t vscale) throw() copyable_width = (copyable_width > scr.width) ? scr.width : copyable_width; copyable_height = (copyable_height > scr.height) ? scr.height : copyable_height; for(uint32_t y = 0; y < height; y++) { - memset(rowptr(y), 0, 4 * width); + memset(rowptr(y), 0, 2 * width); } for(uint32_t y = 0; y < copyable_height; y++) { uint32_t line = y * vscale + originy; - uint32_t* ptr = rowptr(line) + originx; + uint16_t* ptr = rowptr(line) + originx; const uint16_t* sbase = scr.memory + y * scr.pitch; for(uint32_t x = 0; x < copyable_width; x++) { - uint32_t c = palette[sbase[x] % 32768]; + uint16_t c = sbase[x] % 32768; for(uint32_t i = 0; i < hscale; i++) *(ptr++) = c; } for(uint32_t j = 1; j < vscale; j++) - memcpy(rowptr(line + j) + originx, rowptr(line) + originx, 4 * hscale * copyable_width); + memcpy(rowptr(line + j) + originx, rowptr(line) + originx, 2 * hscale * copyable_width); } } @@ -404,12 +411,12 @@ void screen::reallocate(uint32_t _width, uint32_t _height, uint32_t _originx, ui flipped = upside_down; return; } - uint32_t* newmem = new uint32_t[_width * _height]; + uint16_t* newmem = new uint16_t[_width * _height]; width = _width; height = _height; originx = _originx; originy = _originy; - pitch = 4 * _width; + pitch = 2 * _width; if(memory && !user_memory) delete[] memory; memory = newmem; @@ -417,7 +424,7 @@ void screen::reallocate(uint32_t _width, uint32_t _height, uint32_t _originx, ui flipped = upside_down; } -void screen::set(uint32_t* _memory, uint32_t _width, uint32_t _height, uint32_t _originx, uint32_t _originy, +void screen::set(uint16_t* _memory, uint32_t _width, uint32_t _height, uint32_t _originx, uint32_t _originy, uint32_t _pitch) throw() { if(memory && !user_memory) @@ -432,23 +439,19 @@ void screen::set(uint32_t* _memory, uint32_t _width, uint32_t _height, uint32_t flipped = false; } -uint32_t* screen::rowptr(uint32_t row) throw() +uint16_t* screen::rowptr(uint32_t row) throw() { if(flipped) row = height - row - 1; - return reinterpret_cast(reinterpret_cast(memory) + row * pitch); + return reinterpret_cast(reinterpret_cast(memory) + row * pitch); } screen::screen() throw() { - uint32_t _magic = 403703808; - uint8_t* magic = reinterpret_cast(&_magic); memory = NULL; width = height = originx = originy = pitch = 0; user_memory = false; flipped = false; - active_rshift = active_gshift = active_bshift = 255; - set_palette(magic[0], magic[1], magic[2]); } screen::~screen() throw() @@ -456,35 +459,3 @@ screen::~screen() throw() if(memory && !user_memory) delete[] memory; } - -void screen::set_palette(uint32_t rshift, uint32_t gshift, uint32_t bshift) throw() -{ - if(rshift == active_rshift && gshift == active_gshift && bshift == active_bshift) - return; - uint32_t old_rshift = active_rshift; - uint32_t old_gshift = active_gshift; - uint32_t old_bshift = active_bshift; - uint32_t xpalette[32]; - for(unsigned i = 0; i < 32; i++) - xpalette[i] = (i * 255 / 31); - for(unsigned i = 0; i < 32768; i++) { - palette[i] = (xpalette[(i >> 10) & 31] << rshift) + - (xpalette[(i >> 5) & 31] << gshift) + - (xpalette[i & 31] << bshift); - } - active_rshift = rshift; - active_gshift = gshift; - active_bshift = bshift; - //Convert the data. - for(uint32_t j = 0; j < height; j++) { - uint32_t* rp = rowptr(j); - for(uint32_t i = 0; i < width; i++) { - uint32_t x = rp[i]; - uint32_t r = (x >> old_rshift) & 0xFF; - uint32_t g = (x >> old_gshift) & 0xFF; - uint32_t b = (x >> old_bshift) & 0xFF; - x = (r << active_rshift) | (g << active_gshift) | (b << active_bshift); - rp[i] = x; - } - } -} diff --git a/generic/render.hpp b/generic/render.hpp index 63963557..98ebf3f4 100644 --- a/generic/render.hpp +++ b/generic/render.hpp @@ -115,7 +115,7 @@ struct lcscreen }; /** - * Truecolor modifiable screen. + * Hicolor modifiable screen. */ struct screen { @@ -139,7 +139,7 @@ struct screen * parameter _originy: Y coordinate for origin. * parameter _pitch: Distance in bytes between successive scanlines. */ - void set(uint32_t* _memory, uint32_t _width, uint32_t _height, uint32_t _originx, uint32_t _originy, + void set(uint16_t* _memory, uint32_t _width, uint32_t _height, uint32_t _originx, uint32_t _originy, uint32_t _pitch) throw(); /** @@ -170,12 +170,12 @@ struct screen * * parameter row: Number of row (must be less than height). */ - uint32_t* rowptr(uint32_t row) throw(); + uint16_t* rowptr(uint32_t row) throw(); /** * Backing memory for this screen. */ - uint32_t* memory; + uint16_t* memory; /** * True if memory is given by user and must not be freed. @@ -212,20 +212,6 @@ struct screen */ uint32_t originy; -/** - * Palette. - */ - uint32_t palette[32768]; - -/** - * Sets the palette shifts, converting the existing image. - * - * parameter rshift Shift for red component. - * parameter gshift Shift for green component. - * parameter bshift Shift for blue component. - */ - void set_palette(uint32_t rshift, uint32_t gshift, uint32_t bshift) throw(); - /** * Returns color value with specified (r,g,b) values (scale 0-255). * @@ -234,22 +220,7 @@ struct screen * parameter b: Blue component. * returns: color element value. */ - uint32_t make_color(uint8_t r, uint8_t g, uint8_t b) throw(); - -/** - * Current red component shift. - */ - uint32_t active_rshift; - -/** - * Current green component shift. - */ - uint32_t active_gshift; - -/** - * Current blue component shift. - */ - uint32_t active_bshift; + uint16_t make_color(uint8_t r, uint8_t g, uint8_t b) throw(); private: screen(const screen&); screen& operator=(const screen&); @@ -327,12 +298,12 @@ std::pair find_glyph(uint32_t codepoint, int32_t x, int32_t y, * parameter _y: The y position to render to (relative to origin). * parameter _text: The text to render (UTF-8). * parameter _fg: Foreground color. - * parameter _fgalpha: Foreground alpha (0-256). + * parameter _fgalpha: Foreground alpha (0-32). * parameter _bg: Background color. - * parameter _bgalpha: Background alpha (0-256). + * parameter _bgalpha: Background alpha (0-32). * throws std::bad_alloc: Not enough memory. */ -void render_text(struct screen& scr, int32_t _x, int32_t _y, const std::string& _text, uint32_t _fg = 0xFFFFFFFFU, - uint16_t _fgalpha = 255, uint32_t _bg = 0, uint16_t _bgalpha = 0) throw(std::bad_alloc); +void render_text(struct screen& scr, int32_t _x, int32_t _y, const std::string& _text, uint16_t _fg = 0xFFFFFFFFU, + uint8_t _fgalpha = 255, uint16_t _bg = 0, uint8_t _bgalpha = 0) throw(std::bad_alloc); #endif diff --git a/lua/gui-core.cpp b/lua/gui-core.cpp index 994ef019..d807b8ed 100644 --- a/lua/gui-core.cpp +++ b/lua/gui-core.cpp @@ -12,10 +12,7 @@ namespace return 0; lua_pushnumber(LS, lua_render_ctx->width); lua_pushnumber(LS, lua_render_ctx->height); - lua_pushnumber(LS, lua_render_ctx->rshift); - lua_pushnumber(LS, lua_render_ctx->gshift); - lua_pushnumber(LS, lua_render_ctx->bshift); - return 5; + return 2; } } gui_resolution; diff --git a/lua/gui-text.cpp b/lua/gui-text.cpp index 67cb3093..b85a1619 100644 --- a/lua/gui-text.cpp +++ b/lua/gui-text.cpp @@ -5,22 +5,22 @@ namespace { struct render_object_text : public render_object { - render_object_text(int32_t _x, int32_t _y, const std::string& _text, uint32_t _fg = 0xFFFFFFFFU, - uint16_t _fgalpha = 255, uint32_t _bg = 0, uint16_t _bgalpha = 0) throw(std::bad_alloc); + render_object_text(int32_t _x, int32_t _y, const std::string& _text, uint16_t _fg = 0x7FFFU, + uint8_t _fgalpha = 32, uint16_t _bg = 0, uint8_t _bgalpha = 0) throw(std::bad_alloc); ~render_object_text() throw(); void operator()(struct screen& scr) throw(); private: int32_t x; int32_t y; - uint32_t fg; - uint16_t fgalpha; - uint32_t bg; - uint16_t bgalpha; + uint16_t fg; + uint8_t fgalpha; + uint16_t bg; + uint8_t bgalpha; std::string text; }; - render_object_text::render_object_text(int32_t _x, int32_t _y, const std::string& _text, uint32_t _fg, - uint16_t _fgalpha, uint32_t _bg, uint16_t _bgalpha) throw(std::bad_alloc) + render_object_text::render_object_text(int32_t _x, int32_t _y, const std::string& _text, uint16_t _fg, + uint8_t _fgalpha, uint16_t _bg, uint8_t _bgalpha) throw(std::bad_alloc) : x(_x), y(_y), fg(_fg), fgalpha(_fgalpha), bg(_bg), bgalpha(_bgalpha), text(_text) { } @@ -37,11 +37,9 @@ namespace function_ptr_luafun gui_text("gui.text", [](lua_State* LS, const std::string& fname) -> int { if(!lua_render_ctx) return 0; - uint32_t x255 = 255; - uint32_t fgc = (x255 << lua_render_ctx->rshift) | (x255 << lua_render_ctx->gshift) | - (x255 << lua_render_ctx->bshift); + uint32_t fgc = 0x7FFFU; uint32_t bgc = 0; - uint16_t fga = 256; + uint16_t fga = 32; uint16_t bga = 0; int32_t _x = get_numeric_argument(LS, 1, fname.c_str()); int32_t _y = get_numeric_argument(LS, 2, fname.c_str()); diff --git a/manual.lyx b/manual.lyx index a033647e..c01628e3 100644 --- a/manual.lyx +++ b/manual.lyx @@ -1760,7 +1760,7 @@ gui.resolution() \end_layout \begin_layout Standard -Returns 5-tuple (hresolution, vresolution, rshift, gshift, bshift). +Returns 2-tuple (hresolution, vresolution). \end_layout \begin_layout Subsubsection @@ -1793,13 +1793,17 @@ Use gui.resolution() to discover how to layout colors. \end_layout \begin_layout Itemize -Alpha range is 0(transparent)-256(opaque). +Alpha range is 0(transparent)-32(opaque). \end_layout \begin_layout Itemize Only available in on_paint() and on_video() callbacks. \end_layout +\begin_layout Itemize +Colors are 15 bits (1024 * r + 32 * g + b). +\end_layout + \begin_layout Subsubsection gui.repaint() \end_layout