Merge pull request #26 from rkitover/mac_hidpi
Mac OS X HiDPI fixes + other misc
This commit is contained in:
commit
db85f54b1c
|
@ -59,7 +59,11 @@ IF( NOT VERSION )
|
|||
endif(EXISTS ${PROJECT_SOURCE_DIR}/.git)
|
||||
ENDIF( NOT VERSION )
|
||||
|
||||
|
||||
IF(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
ADD_DEFINITIONS(-DDEBUG)
|
||||
ELSE()
|
||||
ADD_DEFINITIONS(-NDEBUG)
|
||||
ENDIF()
|
||||
|
||||
# Fill in SDLMAIN_LIBRARY on OS X manually to avoid using SDLMain.m
|
||||
# OS X users will have to compile and install SDL from source.
|
||||
|
@ -68,18 +72,38 @@ if( APPLE AND ENABLE_SDL )
|
|||
SET(SDL2MAIN_LIBRARY "-lSDL2main")
|
||||
endif( APPLE AND ENABLE_SDL )
|
||||
|
||||
# Add support for MacPorts and Homebrew on OS X
|
||||
# and ObjectiveC code
|
||||
# Add support for Homebrew, MacPorts and Fink on OS X
|
||||
# as well as for ObjectiveC code
|
||||
IF(APPLE)
|
||||
SET(CMAKE_INCLUDE_PATH "${CMAKE_INCLUDE_PATH};/usr/local/include;/opt/local/include")
|
||||
SET(CMAKE_LIBRARY_PATH "${CMAKE_LIBRARY_PATH};/usr/local/lib;/opt/local/lib")
|
||||
SET(CMAKE_PROGRAM_PATH "${CMAKE_PROGRAM_PATH};/usr/local/bin;/opt/local/bin")
|
||||
IF(EXISTS /usr/local/include)
|
||||
SET(CMAKE_INCLUDE_PATH "${CMAKE_INCLUDE_PATH};/usr/local/include")
|
||||
INCLUDE_DIRECTORIES("/usr/local/include")
|
||||
ELSEIF(EXISTS /opt/local/include)
|
||||
SET(CMAKE_INCLUDE_PATH "${CMAKE_INCLUDE_PATH};/opt/local/include")
|
||||
INCLUDE_DIRECTORIES("/opt/local/include")
|
||||
ELSEIF(EXISTS /sw/include)
|
||||
SET(CMAKE_INCLUDE_PATH "${CMAKE_INCLUDE_PATH};/sw/include")
|
||||
INCLUDE_DIRECTORIES("/sw/include")
|
||||
ENDIF()
|
||||
|
||||
link_directories("/usr/local/lib")
|
||||
include_directories("/usr/local/include")
|
||||
IF(EXISTS /usr/local/lib)
|
||||
SET(CMAKE_LIBRARY_PATH "${CMAKE_LIBRARY_PATH};/usr/local/lib")
|
||||
LINK_DIRECTORIES("/usr/local/lib")
|
||||
ELSEIF(EXISTS /opt/local/lib)
|
||||
SET(CMAKE_LIBRARY_PATH "${CMAKE_LIBRARY_PATH};/opt/local/lib")
|
||||
LINK_DIRECTORIES("/opt/local/lib")
|
||||
ELSEIF(EXISTS /sw/lib)
|
||||
SET(CMAKE_LIBRARY_PATH "${CMAKE_LIBRARY_PATH};/sw/lib")
|
||||
LINK_DIRECTORIES("/sw/lib")
|
||||
ENDIF()
|
||||
|
||||
link_directories("/opt/local/lib")
|
||||
include_directories("/opt/local/include")
|
||||
IF(EXISTS /usr/local/bin)
|
||||
SET(CMAKE_PROGRAM_PATH "${CMAKE_PROGRAM_PATH};/usr/local/bin")
|
||||
ELSEIF(EXISTS /opt/local/bin)
|
||||
SET(CMAKE_PROGRAM_PATH "${CMAKE_PROGRAM_PATH};/opt/local/bin")
|
||||
ELSEIF(EXISTS /sw/bin)
|
||||
SET(CMAKE_PROGRAM_PATH "${CMAKE_PROGRAM_PATH};/sw/bin")
|
||||
ENDIF()
|
||||
|
||||
# and compile as Objective-C++ for ObjectiveC #ifdefs
|
||||
SET(CMAKE_CXX_COMPILE_OBJECT "<CMAKE_CXX_COMPILER> -x objective-c++ <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
|
||||
|
|
|
@ -29,10 +29,15 @@ else(ENABLE_OPENAL)
|
|||
ADD_DEFINITIONS (-DNO_OAL)
|
||||
endif(ENABLE_OPENAL)
|
||||
|
||||
IF(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
SET(wxWidgets_USE_DEBUG ON) # noop if wx is compiled with --disable-debug, like in Mac Homebrew atm
|
||||
|
||||
IF(CMAKE_BUILD_TYPE EQUAL "Debug")
|
||||
SET(wxWidgets_USE_DEBUG ON)
|
||||
# and if this is the case, we can't set debug level without link failing
|
||||
IF(NOT wxWidgets_DEFINITIONS MATCHES "-DwxDEBUG_LEVEL=0")
|
||||
ADD_DEFINITIONS(-DwxDEBUG_LEVEL=1)
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
SET(wxWidgets_USE_UNICODE ON)
|
||||
# adv is for wxAboutBox
|
||||
# xml, html is for xrc
|
||||
|
|
|
@ -47,13 +47,11 @@ protected:
|
|||
{
|
||||
PaintEv(ev);
|
||||
}
|
||||
void OnSize(wxSizeEvent&);
|
||||
void DrawArea(wxWindowDC& dc);
|
||||
#if wxCHECK_VERSION(2, 9, 0) || !defined(__WXMAC__)
|
||||
wxGLContext ctx;
|
||||
#if wxCHECK_VERSION(2, 9, 0)
|
||||
wxGLContext* ctx;
|
||||
#endif
|
||||
bool did_init;
|
||||
void Init();
|
||||
void DrawingPanelInit();
|
||||
GLuint texid, vlist;
|
||||
int texsize;
|
||||
|
||||
|
@ -81,8 +79,7 @@ protected:
|
|||
PaintEv(ev);
|
||||
}
|
||||
void DrawArea(wxWindowDC&);
|
||||
bool did_init;
|
||||
void Init();
|
||||
void DrawingPanelInit();
|
||||
|
||||
DECLARE_CLASS()
|
||||
DECLARE_EVENT_TABLE()
|
||||
|
|
|
@ -2522,6 +2522,8 @@ bool MainFrame::BindControls()
|
|||
return false;
|
||||
}
|
||||
|
||||
panel->SetMainFrame(this);
|
||||
|
||||
panel->AdjustSize(false);
|
||||
// only the panel does idle events (the emulator loop)
|
||||
// however, do not enable until end of init, since errors will start
|
||||
|
|
|
@ -21,6 +21,10 @@
|
|||
{ \
|
||||
wxT(c), (n), d, NULL, &v, NULL, min, max \
|
||||
}
|
||||
#define DOUBLEOPT(c, n, d, v, min, max) \
|
||||
{ \
|
||||
wxT(c), (n), d, NULL, NULL, NULL, min, max, NULL, &v \
|
||||
}
|
||||
#define BOOLOPT(c, n, d, v) \
|
||||
{ \
|
||||
wxT(c), (n), d, NULL, NULL, NULL, 0, 0, &v \
|
||||
|
@ -156,7 +160,7 @@ opt_desc opts[] = {
|
|||
#else
|
||||
ENUMOPT("Display/RenderMethod", "", wxTRANSLATE("Render method; if unsupported, simple method will be used"), gopts.render_method, wxTRANSLATE("simple|opengl|cairo")),
|
||||
#endif
|
||||
INTOPT("Display/Scale", "", wxTRANSLATE("Default scale factor"), gopts.video_scale, 1, 6),
|
||||
DOUBLEOPT("Display/Scale", "", wxTRANSLATE("Default scale factor"), gopts.video_scale, 1, 6),
|
||||
BOOLOPT("Display/Stretch", "RetainAspect", wxTRANSLATE("Retain aspect ratio when resizing"), gopts.retain_aspect),
|
||||
|
||||
/// GB
|
||||
|
@ -523,6 +527,13 @@ void load_opts()
|
|||
wxLogWarning(_("Invalid value %d for option %s; valid values are %d - %d"), opt.curint, opt.opt, opt.min, opt.max);
|
||||
} else
|
||||
*opt.intopt = opt.curint;
|
||||
} else if (opt.doubleopt) {
|
||||
cfg->Read(opt.opt, &opt.curdouble, *opt.doubleopt);
|
||||
|
||||
if (opt.curdouble < opt.min || opt.curdouble > opt.max) {
|
||||
wxLogWarning(_("Invalid value %f for option %s; valid values are %f - %f"), opt.curdouble, opt.opt, opt.min, opt.max);
|
||||
} else
|
||||
*opt.doubleopt = opt.curdouble;
|
||||
} else if (opt.boolopt) {
|
||||
cfg->Read(opt.opt, opt.boolopt, *opt.boolopt);
|
||||
opt.curbool = *opt.boolopt;
|
||||
|
@ -648,6 +659,9 @@ void update_opts()
|
|||
} else if (opt.intopt) {
|
||||
if (*opt.intopt != opt.curint)
|
||||
cfg->Write(opt.opt, (opt.curint = *opt.intopt));
|
||||
} else if (opt.doubleopt) {
|
||||
if (*opt.doubleopt != opt.curdouble)
|
||||
cfg->Write(opt.opt, (opt.curdouble = *opt.doubleopt));
|
||||
} else if (opt.boolopt) {
|
||||
if (*opt.boolopt != opt.curbool)
|
||||
cfg->Write(opt.opt, (opt.curbool = *opt.boolopt));
|
||||
|
@ -805,6 +819,14 @@ bool opt_set(const wxChar* name, const wxChar* val)
|
|||
wxLogWarning(_("Invalid value %d for option %s; valid values are %d - %d"), ival, name, opt->min, opt->max);
|
||||
else
|
||||
*opt->intopt = ival;
|
||||
} else if (opt->doubleopt) {
|
||||
const wxString s(val);
|
||||
double dval;
|
||||
|
||||
if (!s.ToDouble(&dval) || dval < opt->min || dval > opt->max)
|
||||
wxLogWarning(_("Invalid value %f for option %s; valid values are %f - %f"), dval, name, opt->min, opt->max);
|
||||
else
|
||||
*opt->doubleopt = dval;
|
||||
} else {
|
||||
// GB/Palette[0-2] is virtual
|
||||
for (int i = 0; i < 3; i++) {
|
||||
|
|
|
@ -18,7 +18,7 @@ extern struct opts_t {
|
|||
wxVideoMode fs_mode;
|
||||
int max_threads;
|
||||
int render_method;
|
||||
int video_scale;
|
||||
double video_scale;
|
||||
bool retain_aspect;
|
||||
bool keep_on_top;
|
||||
|
||||
|
@ -90,11 +90,13 @@ extern struct opt_desc {
|
|||
wxString* stropt;
|
||||
int* intopt;
|
||||
const wxChar* enumvals;
|
||||
int min, max;
|
||||
double min, max;
|
||||
bool* boolopt;
|
||||
double* doubleopt;
|
||||
// current configured value
|
||||
wxString curstr;
|
||||
int curint;
|
||||
double curdouble;
|
||||
#define curbool curint
|
||||
} opts[];
|
||||
extern const int num_opts;
|
||||
|
|
182
src/wx/panel.cpp
182
src/wx/panel.cpp
|
@ -1,5 +1,10 @@
|
|||
#include <wx/dcbuffer.h>
|
||||
|
||||
#ifdef __WXMAC__
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#endif
|
||||
|
||||
#include "../../version.h"
|
||||
#include "../common/ConfigManager.h"
|
||||
#include "../common/Patch.h"
|
||||
|
@ -13,6 +18,19 @@
|
|||
|
||||
int emulating;
|
||||
|
||||
double HiDPIAware::HiDPIScaleFactor()
|
||||
{
|
||||
if (hidpi_scale_factor == 0) {
|
||||
#ifdef __WXMAC__
|
||||
hidpi_scale_factor = [[(NSView*)GetWindow()->GetHandle() window] backingScaleFactor];
|
||||
#else
|
||||
hidpi_scale_factor = 1.0;
|
||||
#endif
|
||||
}
|
||||
|
||||
return hidpi_scale_factor;
|
||||
}
|
||||
|
||||
IMPLEMENT_DYNAMIC_CLASS(GameArea, wxPanel)
|
||||
|
||||
GameArea::GameArea()
|
||||
|
@ -704,9 +722,12 @@ void GameArea::DelBorder()
|
|||
void GameArea::AdjustMinSize()
|
||||
{
|
||||
wxWindow* frame = wxGetApp().frame;
|
||||
double hidpi_scale_factor = HiDPIScaleFactor();
|
||||
|
||||
// note: could safely set min size to 1x or less regardless of video_scale
|
||||
// but setting it to scaled size makes resizing to default easier
|
||||
wxSize sz(basic_width * gopts.video_scale, basic_height * gopts.video_scale);
|
||||
wxSize sz((std::ceil(basic_width * gopts.video_scale) / hidpi_scale_factor),
|
||||
(std::ceil(basic_height * gopts.video_scale) / hidpi_scale_factor));
|
||||
SetMinSize(sz);
|
||||
#if wxCHECK_VERSION(2, 8, 8)
|
||||
sz = frame->ClientToWindowSize(sz);
|
||||
|
@ -719,7 +740,11 @@ void GameArea::AdjustMinSize()
|
|||
void GameArea::LowerMinSize()
|
||||
{
|
||||
wxWindow* frame = wxGetApp().frame;
|
||||
wxSize sz(basic_width, basic_height);
|
||||
double hidpi_scale_factor = HiDPIScaleFactor();
|
||||
|
||||
wxSize sz(std::ceil(basic_width / hidpi_scale_factor),
|
||||
std::ceil(basic_height / hidpi_scale_factor));
|
||||
|
||||
SetMinSize(sz);
|
||||
// do not take decorations into account
|
||||
frame->SetMinSize(sz);
|
||||
|
@ -732,7 +757,9 @@ void GameArea::AdjustSize(bool force)
|
|||
if (fullscreen)
|
||||
return;
|
||||
|
||||
const wxSize newsz(basic_width * gopts.video_scale, basic_height * gopts.video_scale);
|
||||
double hidpi_scale_factor = HiDPIScaleFactor();
|
||||
const wxSize newsz((std::ceil(basic_width * gopts.video_scale) / hidpi_scale_factor),
|
||||
(std::ceil(basic_height * gopts.video_scale) / hidpi_scale_factor));
|
||||
|
||||
if (!force) {
|
||||
wxSize sz = GetSize();
|
||||
|
@ -756,6 +783,15 @@ void GameArea::ShowFullScreen(bool full)
|
|||
return;
|
||||
}
|
||||
|
||||
// Some kbd accels can send a menu open event without a close event,
|
||||
// this happens on Mac in HiDPI mode for the fullscreen toggle accel.
|
||||
main_frame->SetMenusOpened(false);
|
||||
|
||||
// on Mac maximize is native fullscreen, so ignore fullscreen requests
|
||||
#ifdef __WXMAC__
|
||||
if (full && main_frame->IsMaximized()) return;
|
||||
#endif
|
||||
|
||||
fullscreen = full;
|
||||
|
||||
// just in case screen mode is going to change, go ahead and preemptively
|
||||
|
@ -1300,12 +1336,12 @@ DrawingPanel::DrawingPanel(int _width, int _height)
|
|||
// unused (as is rpi->Handle)
|
||||
_rpi->Output = (RENDPLUG_Output)filt_plugin.GetSymbol(wxT("RenderPluginOutput"));
|
||||
|
||||
scale = (_rpi->Flags & RPI_OUT_SCLMSK) >> RPI_OUT_SCLSH;
|
||||
scale *= (_rpi->Flags & RPI_OUT_SCLMSK) >> RPI_OUT_SCLSH;
|
||||
rpi = _rpi;
|
||||
gopts.filter = FF_PLUGIN; // now that there is a valid plugin
|
||||
} while (0);
|
||||
} else {
|
||||
scale = builtin_ff_scale(gopts.filter);
|
||||
scale *= builtin_ff_scale(gopts.filter);
|
||||
#define out_16 (systemColorDepth == 16)
|
||||
systemColorDepth = 32;
|
||||
}
|
||||
|
@ -1336,6 +1372,11 @@ DrawingPanel::DrawingPanel(int _width, int _height)
|
|||
utilUpdateSystemColorMaps(false);
|
||||
}
|
||||
|
||||
void DrawingPanel::DrawingPanelInit()
|
||||
{
|
||||
did_init = true;
|
||||
}
|
||||
|
||||
void DrawingPanel::PaintEv(wxPaintEvent& ev)
|
||||
{
|
||||
wxPaintDC dc(GetWindow());
|
||||
|
@ -1388,7 +1429,8 @@ public:
|
|||
|
||||
// Set these params before running
|
||||
int nthreads, threadno;
|
||||
int width, height, scale;
|
||||
int width, height;
|
||||
double scale;
|
||||
const RENDER_PLUGIN_INFO* rpi;
|
||||
uint8_t *dst, *delta;
|
||||
|
||||
|
@ -1407,10 +1449,10 @@ public:
|
|||
int instride = (width + inrb) * inbpp;
|
||||
int outbpp = out_16 ? 2 : systemColorDepth == 24 ? 3 : 4;
|
||||
int outrb = systemColorDepth == 24 ? 0 : 4;
|
||||
int outstride = width * outbpp * scale + outrb;
|
||||
int outstride = std::ceil(width * outbpp * scale) + outrb;
|
||||
delta += instride * procy;
|
||||
// + 1 for stupid top border
|
||||
dst += outstride * (procy + 1) * scale;
|
||||
dst += (int)std::ceil(outstride * (procy + 1) * scale);
|
||||
|
||||
while (nthreads == 1 || sig.Wait() == wxCOND_NO_ERROR) {
|
||||
if (!src /* && nthreads > 1 */) {
|
||||
|
@ -1561,10 +1603,10 @@ public:
|
|||
outdesc.SrcH = height; // + scale / 2
|
||||
outdesc.DstPtr = dst;
|
||||
outdesc.DstPitch = outstride;
|
||||
outdesc.DstW = width * scale;
|
||||
outdesc.DstW = std::ceil(width * scale);
|
||||
// on the other hand, there is at least 1 line below, so I'll add
|
||||
// that to dest in case safety checks in plugin use < instead of <=
|
||||
outdesc.DstH = height * scale + 1; // + scale * (scale / 2)
|
||||
outdesc.DstH = std::ceil(height * scale) + 1; // + scale * (scale / 2)
|
||||
rpi->Output(&outdesc);
|
||||
break;
|
||||
|
||||
|
@ -1588,18 +1630,18 @@ void DrawingPanel::DrawArea(uint8_t** data)
|
|||
// if not filtering, we still retain current image for redraws
|
||||
int outbpp = out_16 ? 2 : systemColorDepth == 24 ? 3 : 4;
|
||||
int outrb = systemColorDepth == 24 ? 0 : 4;
|
||||
int outstride = width * outbpp * scale + outrb;
|
||||
int outstride = std::ceil(width * outbpp * scale) + outrb;
|
||||
|
||||
if (!pixbuf2) {
|
||||
int allocstride = outstride, alloch = height;
|
||||
|
||||
// gb may write borders, so allocate enough for them
|
||||
if (width == GameArea::GBWidth && height == GameArea::GBHeight) {
|
||||
allocstride = GameArea::SGBWidth * outbpp * scale + outrb;
|
||||
allocstride = std::ceil(GameArea::SGBWidth * outbpp * scale) + outrb;
|
||||
alloch = GameArea::SGBHeight;
|
||||
}
|
||||
|
||||
pixbuf2 = (uint8_t*)calloc(allocstride, (alloch + 2) * scale);
|
||||
pixbuf2 = (uint8_t*)calloc(allocstride, std::ceil((alloch + 2) * scale));
|
||||
}
|
||||
|
||||
if (gopts.filter == FF_NONE) {
|
||||
|
@ -1701,7 +1743,7 @@ void DrawingPanel::DrawArea(uint8_t** data)
|
|||
if (!disableStatusMessages && !panel->osdtext.empty()) {
|
||||
if (systemGetClock() - panel->osdtime < OSD_TIME) {
|
||||
std::string message = ToString(panel->osdtext);
|
||||
int linelen = (width * scale - 20) / 8;
|
||||
int linelen = std::ceil(width * scale - 20) / 8;
|
||||
int nlines = (message.length() + linelen - 1) / linelen;
|
||||
int cury = height - 14 - nlines * 10;
|
||||
char* ptr = const_cast<char*>(message.c_str());
|
||||
|
@ -1862,6 +1904,7 @@ BasicDrawingPanel::BasicDrawingPanel(wxWindow* parent, int _width, int _height)
|
|||
if (gopts.filter == FF_NONE && gopts.ifb == IFB_NONE)
|
||||
// changing from 32 to 24 does not require regenerating color tables
|
||||
systemColorDepth = 24;
|
||||
if (!did_init) DrawingPanelInit();
|
||||
}
|
||||
|
||||
void BasicDrawingPanel::DrawArea(wxWindowDC& dc)
|
||||
|
@ -1874,12 +1917,12 @@ void BasicDrawingPanel::DrawArea(wxWindowDC& dc)
|
|||
bm = new wxBitmap(im);
|
||||
} else if (out_16) {
|
||||
// scaled by filters, top/right borders, transform to 24-bit
|
||||
wxImage im(width * scale, height * scale, false);
|
||||
uint16_t* src = (uint16_t*)todraw + (width + 2) * scale; // skip top border
|
||||
wxImage im(std::ceil(width * scale), std::ceil(height * scale), false);
|
||||
uint16_t* src = (uint16_t*)todraw + (int)std::ceil((width + 2) * scale); // skip top border
|
||||
uint8_t* dst = im.GetData();
|
||||
|
||||
for (int y = 0; y < height * scale; y++) {
|
||||
for (int x = 0; x < width * scale; x++, src++) {
|
||||
for (int y = 0; y < std::ceil(height * scale); y++) {
|
||||
for (int x = 0; x < std::ceil(width * scale); x++, src++) {
|
||||
*dst++ = ((*src >> systemRedShift) & 0x1f) << 3;
|
||||
*dst++ = ((*src >> systemGreenShift) & 0x1f) << 3;
|
||||
*dst++ = ((*src >> systemBlueShift) & 0x1f) << 3;
|
||||
|
@ -1892,12 +1935,12 @@ void BasicDrawingPanel::DrawArea(wxWindowDC& dc)
|
|||
} else // 32-bit
|
||||
{
|
||||
// scaled by filters, top/right borders, transform to 24-bit
|
||||
wxImage im(width * scale, height * scale, false);
|
||||
uint32_t* src = (uint32_t*)todraw + (width + 1) * scale; // skip top border
|
||||
wxImage im(std::ceil(width * scale), std::ceil(height * scale), false);
|
||||
uint32_t* src = (uint32_t*)todraw + (int)std::ceil((width + 1) * scale); // skip top border
|
||||
uint8_t* dst = im.GetData();
|
||||
|
||||
for (int y = 0; y < height * scale; y++) {
|
||||
for (int x = 0; x < width * scale; x++, src++) {
|
||||
for (int y = 0; y < std::ceil(height * scale); y++) {
|
||||
for (int x = 0; x < std::ceil(width * scale); x++, src++) {
|
||||
*dst++ = *src >> (systemRedShift - 3);
|
||||
*dst++ = *src >> (systemGreenShift - 3);
|
||||
*dst++ = *src >> (systemBlueShift - 3);
|
||||
|
@ -1912,8 +1955,8 @@ void BasicDrawingPanel::DrawArea(wxWindowDC& dc)
|
|||
double sx, sy;
|
||||
int w, h;
|
||||
GetClientSize(&w, &h);
|
||||
sx = (double)w / (double)(width * scale);
|
||||
sy = (double)h / (double)(height * scale);
|
||||
sx = w / (width * scale);
|
||||
sy = h / (height * scale);
|
||||
dc.SetUserScale(sx, sy);
|
||||
dc.DrawBitmap(*bm, 0, 0);
|
||||
delete bm;
|
||||
|
@ -1936,7 +1979,6 @@ IMPLEMENT_CLASS2(GLDrawingPanel, DrawingPanel, wxGLCanvas)
|
|||
// this would be easier in 2.9
|
||||
BEGIN_EVENT_TABLE(GLDrawingPanel, wxGLCanvas)
|
||||
EVT_PAINT(GLDrawingPanel::PaintEv2)
|
||||
EVT_SIZE(GLDrawingPanel::OnSize)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
// This is supposed to be the default, but DOUBLEBUFFER doesn't seem to be
|
||||
|
@ -1945,7 +1987,7 @@ static int glopts[] = {
|
|||
WX_GL_RGBA, WX_GL_DOUBLEBUFFER, 0
|
||||
};
|
||||
|
||||
#if wxCHECK_VERSION(2, 9, 0) || !defined(__WXMAC__)
|
||||
#if wxCHECK_VERSION(2, 9, 0)
|
||||
#define glc wxGLCanvas
|
||||
#else
|
||||
// shuffled parms for 2.9 indicates non-auto glcontext
|
||||
|
@ -1957,23 +1999,30 @@ GLDrawingPanel::GLDrawingPanel(wxWindow* parent, int _width, int _height)
|
|||
: glc(parent, wxID_ANY, glopts, wxPoint(0, 0), parent->GetSize(),
|
||||
wxFULL_REPAINT_ON_RESIZE)
|
||||
, DrawingPanel(_width, _height)
|
||||
, did_init(false)
|
||||
#if wxCHECK_VERSION(2, 9, 0) || !defined(__WXMAC__)
|
||||
, ctx(this)
|
||||
#endif
|
||||
{
|
||||
#ifdef __WXMAC__
|
||||
[(NSView *)GetHandle() setWantsBestResolutionOpenGLSurface:YES];
|
||||
#endif
|
||||
#if wxCHECK_VERSION(2, 9, 0)
|
||||
ctx = new wxGLContext(this);
|
||||
SetCurrent(*ctx);
|
||||
#endif
|
||||
if (!did_init) DrawingPanelInit();
|
||||
}
|
||||
|
||||
GLDrawingPanel::~GLDrawingPanel()
|
||||
{
|
||||
#if wxCHECK_VERSION(2, 9, 0)
|
||||
delete ctx;
|
||||
#endif
|
||||
#if 0
|
||||
|
||||
// this should be automatically deleted w/ context
|
||||
// it's also unsafe if panel no longer displayed
|
||||
if (did_init)
|
||||
{
|
||||
#if wxCHECK_VERSION(2, 9, 0) || !defined(__WXMAC__)
|
||||
SetContext(ctx);
|
||||
#if wxCHECK_VERSION(2, 9, 0)
|
||||
SetContext(*ctx);
|
||||
#else
|
||||
SetContext();
|
||||
#endif
|
||||
|
@ -1984,8 +2033,21 @@ GLDrawingPanel::~GLDrawingPanel()
|
|||
#endif
|
||||
}
|
||||
|
||||
void GLDrawingPanel::Init()
|
||||
void GLDrawingPanel::DrawingPanelInit()
|
||||
{
|
||||
#if wxCHECK_VERSION(2, 9, 0)
|
||||
SetCurrent(*ctx);
|
||||
#endif
|
||||
|
||||
DrawingPanel::DrawingPanelInit();
|
||||
|
||||
#ifdef DEBUG
|
||||
// you can use this to check that the gl surface is indeed high res
|
||||
GLint m_viewport[4];
|
||||
glGetIntegerv(GL_VIEWPORT, m_viewport);
|
||||
vbamDebug("GL VIEWPORT: %d, %d, %d, %d", m_viewport[0], m_viewport[1], m_viewport[2], m_viewport[3]);
|
||||
#endif
|
||||
|
||||
// taken from GTK front end almost verbatim
|
||||
glDisable(GL_CULL_FACE);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
@ -2013,12 +2075,13 @@ void GLDrawingPanel::Init()
|
|||
gopts.bilinear ? GL_LINEAR : GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
||||
gopts.bilinear ? GL_LINEAR : GL_NEAREST);
|
||||
|
||||
#define int_fmt out_16 ? GL_RGB5 : GL_RGB
|
||||
#define tex_fmt out_16 ? GL_BGRA : GL_RGBA, \
|
||||
out_16 ? GL_UNSIGNED_SHORT_1_5_5_5_REV : GL_UNSIGNED_BYTE
|
||||
#if 0
|
||||
texsize = width > height ? width : height;
|
||||
texsize *= scale;
|
||||
texsize = std::ceil(texsize * scale);
|
||||
// texsize = 1 << ffs(texsize);
|
||||
texsize = texsize | (texsize >> 1);
|
||||
texsize = texsize | (texsize >> 2);
|
||||
|
@ -2029,7 +2092,7 @@ void GLDrawingPanel::Init()
|
|||
#else
|
||||
// but really, most cards support non-p2 and rect
|
||||
// if not, use cairo or wx renderer
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, int_fmt, width * scale, height * scale, 0, tex_fmt, NULL);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, int_fmt, std::ceil(width * scale), std::ceil(height * scale), 0, tex_fmt, NULL);
|
||||
#endif
|
||||
glClearColor(0.0, 0.0, 0.0, 1.0);
|
||||
// non-portable vsync code
|
||||
|
@ -2062,22 +2125,21 @@ void GLDrawingPanel::Init()
|
|||
#endif
|
||||
#endif
|
||||
#endif
|
||||
did_init = true;
|
||||
}
|
||||
|
||||
void GLDrawingPanel::DrawArea(wxWindowDC& dc)
|
||||
{
|
||||
#if wxCHECK_VERSION(2, 9, 0) || !defined(__WXMAC__)
|
||||
SetCurrent(ctx);
|
||||
#if wxCHECK_VERSION(2, 9, 0)
|
||||
SetCurrent(*ctx);
|
||||
#else
|
||||
SetCurrent();
|
||||
#endif
|
||||
|
||||
if (!did_init)
|
||||
Init();
|
||||
DrawingPanelInit();
|
||||
|
||||
if (todraw) {
|
||||
int rowlen = width * scale + (out_16 ? 2 : 1);
|
||||
int rowlen = std::ceil(width * scale) + (out_16 ? 2 : 1);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, rowlen);
|
||||
#if wxBYTE_ORDER == wxBIG_ENDIAN
|
||||
|
||||
|
@ -2086,30 +2148,14 @@ void GLDrawingPanel::DrawArea(wxWindowDC& dc)
|
|||
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
|
||||
|
||||
#endif
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, int_fmt, width * scale, height * scale,
|
||||
0, tex_fmt, todraw + rowlen * (out_16 ? 2 : 4) * scale);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, int_fmt, std::ceil(width * scale), (int)std::ceil(height * scale),
|
||||
0, tex_fmt, todraw + (int)std::ceil(rowlen * (out_16 ? 2 : 4) * scale));
|
||||
glCallList(vlist);
|
||||
} else
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
SwapBuffers();
|
||||
}
|
||||
|
||||
void GLDrawingPanel::OnSize(wxSizeEvent& ev)
|
||||
{
|
||||
if (!did_init)
|
||||
return;
|
||||
|
||||
int w, h;
|
||||
GetClientSize(&w, &h);
|
||||
#if wxCHECK_VERSION(2, 9, 0) || !defined(__WXMAC__)
|
||||
SetCurrent(ctx);
|
||||
#else
|
||||
SetCurrent();
|
||||
#endif
|
||||
glViewport(0, 0, w, h);
|
||||
ev.Skip(); // propagate to parent
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef NO_CAIRO
|
||||
|
@ -2141,6 +2187,8 @@ CairoDrawingPanel::CairoDrawingPanel(wxWindow* parent, int _width, int _height)
|
|||
|
||||
// FIXME: should be "true" for GBA carts if lcd mode selected
|
||||
utilUpdateSystemColorMaps(false);
|
||||
|
||||
if (!did_init) DrawingPanelInit();
|
||||
}
|
||||
|
||||
CairoDrawingPanel::~CairoDrawingPanel()
|
||||
|
@ -2194,8 +2242,8 @@ void CairoDrawingPanel::DrawArea(wxWindowDC& dc)
|
|||
else {
|
||||
if (!conv_surf)
|
||||
conv_surf = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
|
||||
width * scale,
|
||||
height * scale);
|
||||
std::ceil(width * scale),
|
||||
std::ceil(height * scale));
|
||||
|
||||
if (!conv_surf) {
|
||||
wxLogError(_("Cannot create conversion buffer"));
|
||||
|
@ -2203,11 +2251,11 @@ void CairoDrawingPanel::DrawArea(wxWindowDC& dc)
|
|||
}
|
||||
|
||||
surf = cairo_surface_reference(conv_surf);
|
||||
uint16_t* src = (uint16_t*)todraw + (width + 2) * scale; // skip top border
|
||||
uint16_t* src = (uint16_t*)todraw + (int)std::ceil((width + 2) * scale); // skip top border
|
||||
uint32_t* dst = (uint32_t*)cairo_image_surface_get_data(surf);
|
||||
|
||||
for (int y = 0; y < height * scale; y++) {
|
||||
for (int x = 0; x < width * scale; x++, src++) {
|
||||
for (int y = 0; y < std::ceil(height * scale); y++) {
|
||||
for (int x = 0; x < std::ceil(width * scale); x++, src++) {
|
||||
*dst++ = (((*src >> systemRedShift) & 0x1f) << 19) | (((*src >> systemGreenShift) & 0x1f) << 11) | (((*src >> systemBlueShift) & 0x1f) << 3);
|
||||
}
|
||||
|
||||
|
@ -2222,8 +2270,8 @@ void CairoDrawingPanel::DrawArea(wxWindowDC& dc)
|
|||
double sx, sy;
|
||||
int w, h;
|
||||
GetClientSize(&w, &h);
|
||||
sx = (double)width / (double)w;
|
||||
sy = (double)height / (double)h;
|
||||
sx = (double)width / w;
|
||||
sy = (double)height / h;
|
||||
cairo_matrix_t mat;
|
||||
cairo_matrix_init_scale(&mat, sx, sy);
|
||||
cairo_pattern_set_matrix(pat, &mat);
|
||||
|
@ -2253,6 +2301,7 @@ DXDrawingPanel::DXDrawingPanel(wxWindow* parent, int _width, int _height)
|
|||
, DrawingPanel(_width, _height)
|
||||
{
|
||||
// FIXME: implement
|
||||
if (!did_init) DrawingPanelInit();
|
||||
}
|
||||
|
||||
void DXDrawingPanel::DrawArea(wxWindowDC& dc)
|
||||
|
@ -2401,7 +2450,8 @@ void GameArea::HidePointer()
|
|||
return;
|
||||
|
||||
// FIXME: make time configurable
|
||||
if (fullscreen || (systemGetClock() - mouse_active_time) > 3000) {
|
||||
if ((fullscreen || (systemGetClock() - mouse_active_time) > 3000) &&
|
||||
!(main_frame && (main_frame->MenusOpened() || main_frame->DialogOpened()))) {
|
||||
pointer_blanked = true;
|
||||
SetCursor(wxCursor(wxCURSOR_BLANK));
|
||||
|
||||
|
|
|
@ -30,9 +30,31 @@
|
|||
IMPLEMENT_APP(wxvbamApp)
|
||||
IMPLEMENT_DYNAMIC_CLASS(MainFrame, wxFrame)
|
||||
|
||||
// For spewing stuff to terminal when debugging
|
||||
void vbamDebug(const char* format, ...) {
|
||||
#ifdef DEBUG
|
||||
wxLog *active_log = wxLog::GetActiveTarget();
|
||||
|
||||
wxLogStderr log_to_stderr;
|
||||
|
||||
wxLog::SetActiveTarget(&log_to_stderr);
|
||||
|
||||
va_list argptr;
|
||||
va_start(argptr, format);
|
||||
wxVLogDebug(format, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
wxLog::SetActiveTarget(active_log);
|
||||
#endif
|
||||
}
|
||||
|
||||
// generate config file path
|
||||
static void get_config_path(wxPathList& path, bool exists = true)
|
||||
{
|
||||
// we want paths with "visualboyadvance-m" not "vbam", so change appname temporarily
|
||||
wxString current_app_name = wxGetApp().GetAppName();
|
||||
wxGetApp().SetAppName(_("visualboyadvance-m"));
|
||||
|
||||
// local config dir first, then global
|
||||
// locale-specific res first, then main
|
||||
wxStandardPathsBase& stdp = wxStandardPaths::Get();
|
||||
|
@ -44,6 +66,15 @@ static void get_config_path(wxPathList& path, bool exists = true)
|
|||
if ((wxDirExists(s) && wxIsWritable(s)) || ((!exists || !wxDirExists(s)) && parent.IsDirWritable())) \
|
||||
path.Add(s); \
|
||||
} while (0)
|
||||
|
||||
vbamDebug("GetUserLocalDataDir(): %s", static_cast<const char*>(stdp.GetUserLocalDataDir().utf8_str()));
|
||||
vbamDebug("GetUserDataDir(): %s", static_cast<const char*>(stdp.GetUserDataDir().utf8_str()));
|
||||
vbamDebug("GetLocalizedResourcesDir(wxGetApp().locale.GetCanonicalName()): %s", static_cast<const char*>(stdp.GetLocalizedResourcesDir(wxGetApp().locale.GetCanonicalName()).utf8_str()));
|
||||
vbamDebug("GetResourcesDir(): %s", static_cast<const char*>(stdp.GetResourcesDir().utf8_str()));
|
||||
vbamDebug("GetDataDir(): %s", static_cast<const char*>(stdp.GetDataDir().utf8_str()));
|
||||
vbamDebug("GetLocalDataDir(): %s", static_cast<const char*>(stdp.GetLocalDataDir().utf8_str()));
|
||||
vbamDebug("GetPluginsDir(): %s", static_cast<const char*>(stdp.GetPluginsDir().utf8_str()));
|
||||
|
||||
// NOTE: this does not support XDG (freedesktop.org) paths
|
||||
add_path(GetUserLocalDataDir());
|
||||
add_path(GetUserDataDir());
|
||||
|
@ -52,6 +83,8 @@ static void get_config_path(wxPathList& path, bool exists = true)
|
|||
add_path(GetDataDir());
|
||||
add_path(GetLocalDataDir());
|
||||
add_path(GetPluginsDir());
|
||||
|
||||
wxGetApp().SetAppName(current_app_name);
|
||||
}
|
||||
|
||||
static void tack_full_path(wxString& s, const wxString& app = wxEmptyString)
|
||||
|
@ -459,7 +492,7 @@ bool wxvbamApp::OnCmdLineParsed(wxCmdLineParser& cl)
|
|||
|
||||
for (int i = 0; i < num_opts; i++) {
|
||||
wxPrintf(wxT("%s (%s"), opts[i].opt,
|
||||
opts[i].boolopt ? (const wxChar*)wxT("flag") : opts[i].stropt ? (const wxChar*)wxT("string") : opts[i].enumvals ? opts[i].enumvals : opts[i].intopt ? (const wxChar*)wxT("int") : (const wxChar*)wxT("string"));
|
||||
opts[i].boolopt ? (const wxChar*)wxT("flag") : opts[i].stropt ? (const wxChar*)wxT("string") : opts[i].enumvals ? opts[i].enumvals : opts[i].intopt ? (const wxChar*)wxT("int") : opts[i].doubleopt ? (const wxChar*)wxT("decimal") : (const wxChar*)wxT("string"));
|
||||
|
||||
if (opts[i].enumvals) {
|
||||
const wxChar* evx = wxGetTranslation(opts[i].enumvals);
|
||||
|
@ -557,6 +590,7 @@ EVT_DROP_FILES(MainFrame::OnDropFile)
|
|||
// pause game if menu pops up
|
||||
EVT_MENU_OPEN(MainFrame::MenuPopped)
|
||||
EVT_MENU_CLOSE(MainFrame::MenuPopped)
|
||||
EVT_MENU_HIGHLIGHT_ALL(MainFrame::MenuPopped)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
void MainFrame::OnActivate(wxActivateEvent& event)
|
||||
|
@ -950,7 +984,7 @@ int MainFrame::newest_state_slot()
|
|||
// Removing the nesting counter may help, but on wxGTK I still get lockups.
|
||||
void MainFrame::MenuPopped(wxMenuEvent& evt)
|
||||
{
|
||||
bool popped = evt.GetEventType() == wxEVT_MENU_OPEN;
|
||||
bool popped = evt.GetEventType() != wxEVT_MENU_CLOSE;
|
||||
#if 0
|
||||
|
||||
if (popped)
|
||||
|
@ -985,6 +1019,21 @@ void MainFrame::MenuPopped(wxMenuEvent& evt)
|
|||
panel->Resume();
|
||||
}
|
||||
|
||||
void MainFrame::SetMenusOpened(bool state)
|
||||
{
|
||||
if (state) {
|
||||
menus_opened = 1;
|
||||
paused = true;
|
||||
panel->Pause();
|
||||
}
|
||||
else {
|
||||
menus_opened = 0;
|
||||
paused = false;
|
||||
pause_next = false;
|
||||
panel->Resume();
|
||||
}
|
||||
}
|
||||
|
||||
// ShowModal that also disables emulator loop
|
||||
// uses dialog_opened as a nesting counter
|
||||
int MainFrame::ShowModal(wxDialog* dlg)
|
||||
|
|
|
@ -38,6 +38,9 @@ void CheckPointer(T pointer)
|
|||
}
|
||||
}
|
||||
|
||||
// For spewing stuff to terminal
|
||||
void vbamDebug(const char* format, ...);
|
||||
|
||||
/// Helper functions to convert WX's crazy string types to std::string
|
||||
|
||||
inline std::string ToString(wxCharBuffer aString)
|
||||
|
@ -278,6 +281,12 @@ public:
|
|||
// Check for online updates to the emulator
|
||||
bool CheckForUpdates();
|
||||
|
||||
virtual bool MenusOpened() { return menus_opened != 0; }
|
||||
|
||||
virtual void SetMenusOpened(bool state);
|
||||
|
||||
virtual bool DialogOpened() { return dialog_opened != 0; }
|
||||
|
||||
// required for building from xrc
|
||||
DECLARE_DYNAMIC_CLASS();
|
||||
// required for event handling
|
||||
|
@ -333,6 +342,15 @@ private:
|
|||
#include "cmdhandlers.h"
|
||||
};
|
||||
|
||||
// helper class to add HiDPI awareness (mostly for Mac OS X)
|
||||
class HiDPIAware {
|
||||
public:
|
||||
double HiDPIScaleFactor();
|
||||
virtual wxWindow* GetWindow() = 0;
|
||||
private:
|
||||
double hidpi_scale_factor = 0;
|
||||
};
|
||||
|
||||
// a helper class to avoid forgetting StopModal()
|
||||
class ModalPause {
|
||||
public:
|
||||
|
@ -420,11 +438,13 @@ enum audioapi { AUD_SDL,
|
|||
|
||||
class DrawingPanel;
|
||||
|
||||
class GameArea : public wxPanel {
|
||||
class GameArea : public wxPanel, public HiDPIAware {
|
||||
public:
|
||||
GameArea();
|
||||
virtual ~GameArea();
|
||||
|
||||
virtual void SetMainFrame(MainFrame* parent) { main_frame = parent; }
|
||||
|
||||
// set to game title + link info
|
||||
void SetFrameTitle();
|
||||
|
||||
|
@ -540,7 +560,11 @@ public:
|
|||
void StartGamePlayback(const wxString& fname);
|
||||
void StopGamePlayback();
|
||||
|
||||
virtual wxWindow* GetWindow() { return this; }
|
||||
|
||||
protected:
|
||||
MainFrame* main_frame;
|
||||
|
||||
// set minsize of frame & panel to unscaled screen size
|
||||
void LowerMinSize();
|
||||
// set minsize of frame & panel to scaled screen size
|
||||
|
@ -599,7 +623,7 @@ extern bool cmditem_lt(const struct cmditem& cmd1, const struct cmditem& cmd2);
|
|||
|
||||
class FilterThread;
|
||||
|
||||
class DrawingPanel : public wxObject {
|
||||
class DrawingPanel : public wxObject, public HiDPIAware {
|
||||
public:
|
||||
DrawingPanel(int _width, int _height);
|
||||
~DrawingPanel();
|
||||
|
@ -611,7 +635,10 @@ public:
|
|||
protected:
|
||||
virtual void DrawArea(wxWindowDC&) = 0;
|
||||
virtual void DrawOSD(wxWindowDC&);
|
||||
int width, height, scale;
|
||||
int width, height;
|
||||
double scale;
|
||||
virtual void DrawingPanelInit();
|
||||
bool did_init = false;
|
||||
uint8_t* todraw;
|
||||
uint8_t *pixbuf1, *pixbuf2;
|
||||
FilterThread* threads;
|
||||
|
|
Loading…
Reference in New Issue