Support screen rotation & flipping

This commit is contained in:
Ilari Liusvaara 2013-01-19 20:16:55 +02:00
parent 0dacba56a3
commit 4467f693f5
3 changed files with 90 additions and 10 deletions

View file

@ -20,6 +20,9 @@ class wxKeyEvent;
extern double horizontal_scale_factor;
extern double vertical_scale_factor;
extern int scaling_flags;
extern bool hflip_enabled;
extern bool vflip_enabled;
extern bool rotate_enabled;
wxString towxstring(const std::string& str) throw(std::bad_alloc);
std::string tostdstring(const wxString& str) throw(std::bad_alloc);

View file

@ -116,6 +116,9 @@ enum
double horizontal_scale_factor = 1.0;
double vertical_scale_factor = 1.0;
int scaling_flags = SWS_POINT;
bool hflip_enabled = false;
bool vflip_enabled = false;
bool rotate_enabled = false;
namespace
{
@ -123,9 +126,13 @@ namespace
std::string last_volume_record = "0dB";
std::string last_volume_voice = "0dB";
unsigned char* screen_buffer;
uint32_t* rotate_buffer;
uint32_t old_width;
uint32_t old_height;
int old_flags = SWS_POINT;
bool old_hflip = false;
bool old_vflip = false;
bool old_rotate = false;
bool main_window_dirty;
struct thread* emulation_thread;
@ -706,36 +713,84 @@ void wxwin_mainwindow::panel::on_paint(wxPaintEvent& e)
uint8_t* dstp[1];
int dsts[1];
wxPaintDC dc(this);
uint32_t tw = main_screen.get_width() * horizontal_scale_factor + 0.5;
uint32_t th = main_screen.get_height() * vertical_scale_factor + 0.5;
uint32_t tw, th;
bool aux = hflip_enabled || vflip_enabled || rotate_enabled;
if(rotate_enabled) {
tw = main_screen.get_height() * horizontal_scale_factor + 0.5;
th = main_screen.get_width() * vertical_scale_factor + 0.5;
} else {
tw = main_screen.get_width() * horizontal_scale_factor + 0.5;
th = main_screen.get_height() * vertical_scale_factor + 0.5;
}
if(!tw || !th) {
main_window_dirty = false;
return;
}
if(!screen_buffer || tw != old_width || th != old_height || scaling_flags != old_flags) {
if(!screen_buffer || tw != old_width || th != old_height || scaling_flags != old_flags ||
hflip_enabled != old_hflip || vflip_enabled != old_vflip || rotate_enabled != old_rotate) {
if(screen_buffer)
delete[] screen_buffer;
if(rotate_buffer)
delete[] rotate_buffer;
old_height = th;
old_width = tw;
old_flags = scaling_flags;
old_hflip = hflip_enabled;
old_vflip = vflip_enabled;
old_rotate = rotate_enabled;
uint32_t w = main_screen.get_width();
uint32_t h = main_screen.get_height();
if(w && h)
ctx = sws_getCachedContext(ctx, w, h, PIX_FMT_RGBA, tw, th, PIX_FMT_BGR24, scaling_flags,
NULL, NULL, NULL);
ctx = sws_getCachedContext(ctx, rotate_enabled ? h : w, rotate_enabled ? w : h, PIX_FMT_RGBA,
tw, th, PIX_FMT_BGR24, scaling_flags, NULL, NULL, NULL);
tw = max(tw, static_cast<uint32_t>(128));
th = max(th, static_cast<uint32_t>(112));
screen_buffer = new unsigned char[tw * th * 3];
if(aux)
rotate_buffer = new uint32_t[main_screen.get_width() * main_screen.get_height()];
SetMinSize(wxSize(tw, th));
signal_resize_needed();
}
srcs[0] = 4 * main_screen.get_width();
if(aux) {
//Hflip, Vflip or rotate active.
size_t width = main_screen.get_width();
size_t height = main_screen.get_height();
size_t width1 = width - 1;
size_t height1 = height - 1;
size_t stride = main_screen.rowptr(1) - main_screen.rowptr(0);
uint32_t* pixels = main_screen.rowptr(0);
if(rotate_enabled) {
for(unsigned y = 0; y < height; y++) {
uint32_t* pixels2 = pixels + (vflip_enabled ? (height1 - y) : y) * stride;
uint32_t* dpixels = rotate_buffer + (height1 - y);
if(hflip_enabled)
for(unsigned x = 0; x < width; x++)
dpixels[x * height] = pixels2[width1 - x];
else
for(unsigned x = 0; x < width; x++)
dpixels[x * height] = pixels2[x];
}
} else {
for(unsigned y = 0; y < height; y++) {
uint32_t* pixels2 = pixels + (vflip_enabled ? (height1 - y) : y) * stride;
uint32_t* dpixels = rotate_buffer + y * width;
if(hflip_enabled)
for(unsigned x = 0; x < width; x++)
dpixels[x] = pixels2[width1 - x];
else
for(unsigned x = 0; x < width; x++)
dpixels[x] = pixels2[x];
}
}
}
srcs[0] = 4 * (rotate_enabled ? main_screen.get_height() : main_screen.get_width());
dsts[0] = 3 * tw;
srcp[0] = reinterpret_cast<unsigned char*>(main_screen.rowptr(0));
srcp[0] = reinterpret_cast<unsigned char*>(aux ? rotate_buffer : main_screen.rowptr(0));
dstp[0] = screen_buffer;
memset(screen_buffer, 0, tw * th * 3);
if(main_screen.get_width() && main_screen.get_height())
sws_scale(ctx, srcp, srcs, 0, main_screen.get_height(), dstp, dsts);
sws_scale(ctx, srcp, srcs, 0, rotate_enabled ? main_screen.get_width() : main_screen.get_height(),
dstp, dsts);
wxBitmap bmp(wxImage(tw, th, screen_buffer, true));
dc.DrawBitmap(bmp, 0, 0, false);
main_window_dirty = false;

View file

@ -915,6 +915,9 @@ public:
wxeditor_esettings_screen(wxWindow* parent);
~wxeditor_esettings_screen();
void on_configure(wxCommandEvent& e);
wxCheckBox* hflip;
wxCheckBox* vflip;
wxCheckBox* rotate;
private:
void refresh();
wxStaticText* xscale;
@ -927,7 +930,7 @@ wxeditor_esettings_screen::wxeditor_esettings_screen(wxWindow* parent)
: wxPanel(parent, -1)
{
wxButton* tmp;
top_s = new wxFlexGridSizer(3, 3, 0, 0);
top_s = new wxFlexGridSizer(6, 3, 0, 0);
SetSizer(top_s);
top_s->Add(new wxStaticText(this, -1, wxT("X scale factor: ")), 0, wxGROW);
top_s->Add(xscale = new wxStaticText(this, -1, wxT("")), 1, wxGROW);
@ -944,6 +947,15 @@ wxeditor_esettings_screen::wxeditor_esettings_screen(wxWindow* parent)
top_s->Add(tmp = new wxButton(this, wxID_HIGHEST + 3, wxT("Change...")), 0, wxGROW);
tmp->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxeditor_esettings_screen::on_configure),
NULL, this);
top_s->Add(new wxStaticText(this, -1, wxT("Hflip: ")), 0, wxGROW);
top_s->Add(hflip = new wxCheckBox(this, -1, wxT("")), 1, wxGROW);
top_s->Add(new wxStaticText(this, -1, wxT("")), 0, wxGROW);
top_s->Add(new wxStaticText(this, -1, wxT("Vflip: ")), 0, wxGROW);
top_s->Add(vflip = new wxCheckBox(this, -1, wxT("")), 1, wxGROW);
top_s->Add(new wxStaticText(this, -1, wxT("")), 0, wxGROW);
top_s->Add(new wxStaticText(this, -1, wxT("Rotate: ")), 0, wxGROW);
top_s->Add(rotate = new wxCheckBox(this, -1, wxT("")), 1, wxGROW);
top_s->Add(new wxStaticText(this, -1, wxT("")), 0, wxGROW);
refresh();
top_s->SetSizeHints(this);
Fit();
@ -1019,6 +1031,9 @@ void wxeditor_esettings_screen::refresh()
xscale->SetLabel(towxstring((stringfmt() << horizontal_scale_factor).str()));
yscale->SetLabel(towxstring((stringfmt() << vertical_scale_factor).str()));
algo->SetLabel(towxstring(getalgo(scaling_flags)));
hflip->SetValue(hflip_enabled);
vflip->SetValue(vflip_enabled);
rotate->SetValue(rotate_enabled);
top_s->Layout();
Fit();
}
@ -1746,6 +1761,7 @@ private:
wxeditor_esettings_hotkeys* hotkeytab;
wxeditor_esettings_bindings* bindtab;
wxeditor_esettings_advanced* advtab;
wxeditor_esettings_screen* screentab;
};
wxeditor_esettings::wxeditor_esettings(wxWindow* parent, bool hotkeys_only)
@ -1763,12 +1779,13 @@ wxeditor_esettings::wxeditor_esettings(wxWindow* parent, bool hotkeys_only)
hotkeytab = new wxeditor_esettings_hotkeys(this);
bindtab = NULL;
advtab = NULL;
screentab = NULL;
top_s->Add(hotkeytab);
} else {
tabset = new wxNotebook(this, -1, wxDefaultPosition, wxDefaultSize, wxNB_TOP);
tabset->AddPage(new wxeditor_esettings_joystick(tabset), wxT("Joysticks"));
tabset->AddPage(new wxeditor_esettings_paths(tabset), wxT("Paths"));
tabset->AddPage(new wxeditor_esettings_screen(tabset), wxT("Scaling"));
tabset->AddPage(screentab = new wxeditor_esettings_screen(tabset), wxT("Scaling"));
tabset->AddPage(hotkeytab = new wxeditor_esettings_hotkeys(tabset), wxT("Hotkeys"));
tabset->AddPage(new wxeditor_esettings_aliases(tabset), wxT("Aliases"));
tabset->AddPage(bindtab = new wxeditor_esettings_bindings(tabset), wxT("Bindings"));
@ -1802,6 +1819,11 @@ bool wxeditor_esettings::ShouldPreventAppExit() const
void wxeditor_esettings::on_close(wxCommandEvent& e)
{
keygrabber.ungrab_keys();
if(screentab) {
hflip_enabled = screentab->hflip->GetValue();
vflip_enabled = screentab->vflip->GetValue();
rotate_enabled = screentab->rotate->GetValue();
}
EndModal(wxID_OK);
}