Switch internally to 16-bit graphics instead of 32-bit

This commit is contained in:
Ilari Liusvaara 2011-09-26 23:35:13 +03:00
parent 9c3cdb57c5
commit 99468dc616
11 changed files with 313 additions and 294 deletions

View file

@ -488,6 +488,8 @@ namespace
std::list<std::string>::iterator commandhistory_itr;
screen* current_screen;
SDL_Surface* hwsurf;
SDL_Surface* swsurf;
std::pair<uint32_t, uint32_t> 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<uint32_t*>(data + pitch * (y1 + j))[i] = color;
reinterpret_cast<uint32_t*>(data + pitch * (y2 - 1 - j))[i] = color;
reinterpret_cast<uint16_t*>(data + pitch * (y1 + j))[i] = color;
reinterpret_cast<uint16_t*>(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<uint32_t*>(data + pitch * i)[x1 + j] = color;
reinterpret_cast<uint32_t*>(data + pitch * i)[x2 - 1 - j] = color;
reinterpret_cast<uint16_t*>(data + pitch * i)[x1 + j] = color;
reinterpret_cast<uint16_t*>(data + pitch * i)[x2 - 1 - j] = color;
}
}
@ -658,7 +660,7 @@ namespace
void draw_string(uint8_t* base, uint32_t pitch, std::vector<uint32_t> s, uint32_t x, uint32_t y,
uint32_t maxwidth, uint32_t hilite_mode = 0, uint32_t hilite_pos = 0)
{
base += y * static_cast<size_t>(pitch) + 4 * x;
base += y * static_cast<size_t>(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<uint32_t*>(base + pitch * j);
uint16_t* ptr = reinterpret_cast<uint16_t*>(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<uint32_t*>(base + pitch * j);
uint16_t* ptr = reinterpret_cast<uint16_t*>(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<uint32_t*>(base + pitch * j);
uint16_t* ptr = reinterpret_cast<uint16_t*>(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<uint8_t*>(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<uint8_t*>(surf->pixels) + j * surf->pitch + 2 * (x1 - 6), 0,
2 * (x2 - x1 + 12));
uint16_t bordercolor = 0x7E00;
draw_rectangle(reinterpret_cast<uint8_t*>(surf->pixels), surf->pitch, x1 - 4, y1 - 4, x2 + 4, y2 + 4,
bordercolor, 2);
@ -777,11 +777,11 @@ namespace
if(static_cast<uint32_t>(pos_y) > height)
break;
uint8_t* base = reinterpret_cast<uint8_t*>(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<uint32_t*>(base + surf->pitch * j);
uint16_t* ptr = reinterpret_cast<uint16_t*>(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,108 +1205,125 @@ void window::set_main_surface(screen& scr) throw()
notify_screen_update(true);
}
void window::notify_screen_update(bool full) throw()
namespace
{
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;
return false;
}
last_ui_update = curtime;
screen_is_dirty = false;
return true;
}
std::pair<uint32_t, uint32_t> 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<uint32_t, uint32_t> 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(...) {
}
}
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<uint32_t>(hwsurf->w) != win_w || static_cast<uint32_t>(hwsurf->h) != win_h ||
old_screen_w != screen_w || old_screen_h != screen_h || full) {
//Create/Resize the window.
if(!hwsurf || static_cast<uint32_t>(hwsurf->w) != win_w || static_cast<uint32_t>(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;
}
if(current_screen)
current_screen->set_palette(hwsurf->format->Rshift, hwsurf->format->Gshift,
hwsurf->format->Bshift);
void redraw_borders(SDL_Surface* swsurf, std::pair<uint32_t, uint32_t> screensize,
std::pair<uint32_t, uint32_t> 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<uint8_t*>(hwsurf->pixels), hwsurf->pitch, 2, 2, win_w - 2,
win_h - 28, bordercolor, 2);
draw_rectangle(reinterpret_cast<uint8_t*>(hwsurf->pixels), hwsurf->pitch, 2, win_h - 26,
win_w - 2, win_h - 2, bordercolor, 2);
} else {
draw_rectangle(reinterpret_cast<uint8_t*>(hwsurf->pixels), hwsurf->pitch, 2, 2, screen_w + 10,
screen_h + 10, bordercolor, 2);
draw_rectangle(reinterpret_cast<uint8_t*>(hwsurf->pixels), hwsurf->pitch, screen_w + 12, 2,
screen_w + 276, screen_h + 10, bordercolor, 2);
draw_rectangle(reinterpret_cast<uint8_t*>(hwsurf->pixels), hwsurf->pitch, 2, screen_h + 12,
win_w - 2, screen_h + MAXMESSAGES * 16 + 20, bordercolor, 2);
draw_rectangle(reinterpret_cast<uint8_t*>(hwsurf->pixels), hwsurf->pitch, 2,
screen_h + MAXMESSAGES * 16 + 22, win_w - 2, screen_h + MAXMESSAGES * 16 + 46,
bordercolor, 2);
}
SDL_UnlockSurface(hwsurf);
old_screen_w = screen_w;
old_screen_h = screen_h;
}
SDL_LockSurface(hwsurf);
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) {
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<uint8_t*>(hwsurf->pixels) + i * hwsurf->pitch + 24, 0,
4 * screen_w);
for(uint32_t i = 0; i < current_screen->height; i++)
memcpy(reinterpret_cast<uint8_t*>(hwsurf->pixels) + (i + 6) * hwsurf->pitch + 24,
reinterpret_cast<uint8_t*>(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<uint8_t*>(hwsurf->pixels) + i * hwsurf->pitch + 24, 0,
4 * screen_w);
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<uint8_t*>(swsurf->pixels), swsurf->pitch, scrbox_min_x,
scrbox_min_y, scrbox_max_x, scrbox_max_y, bordercolor, 2);
draw_rectangle(reinterpret_cast<uint8_t*>(swsurf->pixels), swsurf->pitch, stsbox_min_x,
stsbox_min_y, stsbox_max_x, stsbox_max_y, bordercolor, 2);
}
//Draw status.
uint32_t status_x = screen_w + 16;
draw_rectangle(reinterpret_cast<uint8_t*>(swsurf->pixels), swsurf->pitch, msgbox_min_x,
msgbox_min_y, msgbox_max_x, msgbox_max_y, bordercolor, 2);
draw_rectangle(reinterpret_cast<uint8_t*>(swsurf->pixels), swsurf->pitch, cmdbox_min_x,
cmdbox_min_y, cmdbox_max_x, cmdbox_max_y, bordercolor, 2);
}
void draw_main_screen(SDL_Surface* swsurf, std::pair<uint32_t, uint32_t> 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<uint8_t*>(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<uint8_t*>(swsurf->pixels) + i * swsurf->pitch + 12, 0,
2 * screensize.first);
if(current_screen) {
for(uint32_t i = 0; i < ch; i++)
memcpy(reinterpret_cast<uint8_t*>(swsurf->pixels) + (i + 6) * swsurf->pitch + 12,
reinterpret_cast<uint8_t*>(current_screen->memory) + current_screen->pitch * i,
2 * cw);
}
}
void draw_status_area(SDL_Surface* swsurf, std::pair<uint32_t, uint32_t> 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<uint8_t*>(hwsurf->pixels), hwsurf->pitch, msg, status_x, status_y,
draw_string(reinterpret_cast<uint8_t*>(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<uint8_t*>(hwsurf->pixels), hwsurf->pitch, "", status_x, status_y,
while(status_y - 6 < screensize.second / 16 * 16) {
draw_string(reinterpret_cast<uint8_t*>(swsurf->pixels), swsurf->pitch, "", status_x, status_y,
256);
status_y += 16;
}
}
//Draw messages.
void draw_messages(SDL_Surface* swsurf, std::pair<uint32_t, uint32_t> screensize,
std::pair<uint32_t, uint32_t> windowsize)
{
uint32_t message_y;
if(!console_mode)
message_y = screen_h + 16;
message_y = screensize.second + 16;
else
message_y = 6;
for(size_t j = 0; j < maxmessages; j++)
@ -1315,36 +1332,84 @@ void window::notify_screen_update(bool full) throw()
if(messagebuffer_first_show + j < messagebuffer_next_seq)
o << (messagebuffer_first_show + j + 1) << ": "
<< messagebuffer[messagebuffer_first_show + j];
draw_string(reinterpret_cast<uint8_t*>(hwsurf->pixels), hwsurf->pitch, o.str(), 6,
message_y + 16 * j, win_w - 12);
draw_string(reinterpret_cast<uint8_t*>(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<uint8_t*>(hwsurf->pixels), hwsurf->pitch, "--More--", win_w - 76,
message_y + 16 * maxmessages - 16, 64);
draw_string(reinterpret_cast<uint8_t*>(swsurf->pixels), swsurf->pitch, "--More--",
windowsize.first - 76, message_y + 16 * maxmessages - 16, 64);
} catch(...) {
}
}
//Draw command_buf.
uint32_t command_y = win_h - 22;
void draw_command(SDL_Surface* swsurf, std::pair<uint32_t, uint32_t> 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<uint8_t*>(hwsurf->pixels), hwsurf->pitch, command_showas,
command_cursor / 4, 6, command_y, win_w - 12, command_overwrite);
draw_command(reinterpret_cast<uint8_t*>(swsurf->pixels), swsurf->pitch, command_showas,
command_cursor / 4, 6, command_y, windowsize.first - 12, command_overwrite);
else
draw_string(reinterpret_cast<uint8_t*>(hwsurf->pixels), hwsurf->pitch, "", 6, command_y,
win_w - 12);
draw_string(reinterpret_cast<uint8_t*>(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)

View file

@ -47,9 +47,6 @@ namespace
hscl = 2;
if(dump_large && _frame.height < 400)
vscl = 2;
uint32_t _magic = 403703808;
uint8_t* magic = reinterpret_cast<uint8_t*>(&_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 *

View file

@ -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<size_t>(width) * height);
tframe.resize(4 * static_cast<size_t>(width) * rheight);
cframe.resize(compressBound(4 * static_cast<size_t>(width) * rheight) + 13);
memset(&tframe[0], 0, 4 * static_cast<size_t>(width) * rheight);
open_and_write_avi_header(width, rheight, fps_n, fps_d);
pframe.resize(2 * static_cast<size_t>(rwidth) * rheight);
tframe.resize(2 * static_cast<size_t>(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<uint16_t*>(_magic);
if(this_is_keyframe) {
memcpy(&tframe[0], data, 4 * static_cast<size_t>(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<size_t>(width) * height);
for(size_t i = 0; i < 4 * static_cast<size_t>(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<char*>(&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<size_t>(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. */

View file

@ -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;

View file

@ -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);

View file

@ -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();

View file

@ -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<uint32_t, uint32_t> 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<uint32_t, uint32_t> 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<uint32_t>(r) << active_rshift) |
(static_cast<uint32_t>(g) << active_gshift) |
(static_cast<uint32_t>(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<uint32_t*>(reinterpret_cast<uint8_t*>(memory) + row * pitch);
return reinterpret_cast<uint16_t*>(reinterpret_cast<uint8_t*>(memory) + row * pitch);
}
screen::screen() throw()
{
uint32_t _magic = 403703808;
uint8_t* magic = reinterpret_cast<uint8_t*>(&_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;
}
}
}

View file

@ -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<uint32_t, size_t> 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

View file

@ -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;

View file

@ -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<int32_t>(LS, 1, fname.c_str());
int32_t _y = get_numeric_argument<int32_t>(LS, 2, fname.c_str());

View file

@ -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