2021-12-04 21:33:04 +01:00
|
|
|
#include "qt_rendererstack.hpp"
|
|
|
|
|
#include "ui_qt_rendererstack.h"
|
|
|
|
|
|
|
|
|
|
#include "qt_softwarerenderer.hpp"
|
|
|
|
|
#include "qt_hardwarerenderer.hpp"
|
|
|
|
|
|
2021-12-29 23:49:09 +06:00
|
|
|
#include "qt_mainwindow.hpp"
|
|
|
|
|
|
2021-12-10 01:03:20 +06:00
|
|
|
#include "evdev_mouse.hpp"
|
|
|
|
|
|
2021-12-08 17:02:28 +06:00
|
|
|
#include <QScreen>
|
|
|
|
|
|
2021-11-30 16:26:49 +06:00
|
|
|
#ifdef __APPLE__
|
|
|
|
|
#include <CoreGraphics/CoreGraphics.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
extern "C"
|
|
|
|
|
{
|
|
|
|
|
#include <86box/mouse.h>
|
|
|
|
|
#include <86box/plat.h>
|
|
|
|
|
#include <86box/video.h>
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-29 23:49:09 +06:00
|
|
|
extern MainWindow* main_window;
|
2021-12-04 21:33:04 +01:00
|
|
|
RendererStack::RendererStack(QWidget *parent) :
|
|
|
|
|
QStackedWidget(parent),
|
|
|
|
|
ui(new Ui::RendererStack)
|
|
|
|
|
{
|
|
|
|
|
ui->setupUi(this);
|
2021-12-15 00:37:48 +02:00
|
|
|
|
2021-12-10 01:03:20 +06:00
|
|
|
#ifdef WAYLAND
|
|
|
|
|
if (QApplication::platformName().contains("wayland")) {
|
|
|
|
|
wl_init();
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef EVDEV_INPUT
|
|
|
|
|
if (QApplication::platformName() == "xcb" || QApplication::platformName() == "eglfs") {
|
|
|
|
|
evdev_init();
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2021-12-04 21:33:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RendererStack::~RendererStack()
|
|
|
|
|
{
|
|
|
|
|
delete ui;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-01 11:15:42 +06:00
|
|
|
extern "C" void macos_poll_mouse();
|
2021-11-30 16:26:49 +06:00
|
|
|
void
|
|
|
|
|
qt_mouse_capture(int on)
|
|
|
|
|
{
|
|
|
|
|
if (!on)
|
|
|
|
|
{
|
|
|
|
|
mouse_capture = 0;
|
|
|
|
|
QApplication::setOverrideCursor(Qt::ArrowCursor);
|
|
|
|
|
#ifdef __APPLE__
|
|
|
|
|
CGAssociateMouseAndMouseCursorPosition(true);
|
|
|
|
|
#endif
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
mouse_capture = 1;
|
|
|
|
|
QApplication::setOverrideCursor(Qt::BlankCursor);
|
|
|
|
|
#ifdef __APPLE__
|
|
|
|
|
CGAssociateMouseAndMouseCursorPosition(false);
|
|
|
|
|
#endif
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-04 21:33:04 +01:00
|
|
|
void RendererStack::mousePoll()
|
2021-11-30 16:26:49 +06:00
|
|
|
{
|
2021-12-01 11:15:42 +06:00
|
|
|
#ifdef __APPLE__
|
|
|
|
|
return macos_poll_mouse();
|
|
|
|
|
#else
|
2021-11-30 16:26:49 +06:00
|
|
|
mouse_x = mousedata.deltax;
|
|
|
|
|
mouse_y = mousedata.deltay;
|
|
|
|
|
mouse_z = mousedata.deltaz;
|
|
|
|
|
mousedata.deltax = mousedata.deltay = mousedata.deltaz = 0;
|
|
|
|
|
mouse_buttons = mousedata.mousebuttons;
|
2021-12-02 16:26:33 +06:00
|
|
|
#ifdef WAYLAND
|
2021-12-05 12:02:57 +06:00
|
|
|
if (QApplication::platformName().contains("wayland"))
|
2021-12-02 16:26:33 +06:00
|
|
|
wl_mouse_poll();
|
|
|
|
|
#endif
|
2021-12-10 01:03:20 +06:00
|
|
|
#ifdef EVDEV_INPUT
|
|
|
|
|
evdev_mouse_poll();
|
|
|
|
|
#endif
|
2021-12-01 11:15:42 +06:00
|
|
|
#endif
|
2021-11-30 16:26:49 +06:00
|
|
|
}
|
|
|
|
|
|
2021-12-09 00:01:22 +06:00
|
|
|
int ignoreNextMouseEvent = 1;
|
2021-12-04 21:33:04 +01:00
|
|
|
void RendererStack::mouseReleaseEvent(QMouseEvent *event)
|
2021-11-30 16:26:49 +06:00
|
|
|
{
|
2022-02-05 01:01:06 +05:00
|
|
|
if (this->geometry().contains(event->pos()) && event->button() == Qt::LeftButton && !mouse_capture && (isMouseDown & 1))
|
2021-11-30 16:26:49 +06:00
|
|
|
{
|
2021-12-01 01:11:06 +06:00
|
|
|
plat_mouse_capture(1);
|
2021-12-02 16:26:33 +06:00
|
|
|
this->setCursor(Qt::BlankCursor);
|
2021-12-09 00:01:22 +06:00
|
|
|
if (!ignoreNextMouseEvent) ignoreNextMouseEvent++; // Avoid jumping cursor when moved.
|
2022-02-05 01:01:06 +05:00
|
|
|
isMouseDown &= ~1;
|
2021-11-30 16:26:49 +06:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (mouse_capture && event->button() == Qt::MiddleButton && mouse_get_buttons() < 3)
|
|
|
|
|
{
|
2021-12-01 01:11:06 +06:00
|
|
|
plat_mouse_capture(0);
|
2021-12-02 16:26:33 +06:00
|
|
|
this->setCursor(Qt::ArrowCursor);
|
2022-02-05 01:01:06 +05:00
|
|
|
isMouseDown &= ~1;
|
2021-11-30 16:26:49 +06:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (mouse_capture)
|
|
|
|
|
{
|
|
|
|
|
mousedata.mousebuttons &= ~event->button();
|
|
|
|
|
}
|
2022-02-05 01:01:06 +05:00
|
|
|
isMouseDown &= ~1;
|
2021-11-30 16:26:49 +06:00
|
|
|
}
|
2021-12-04 21:33:04 +01:00
|
|
|
void RendererStack::mousePressEvent(QMouseEvent *event)
|
2021-11-30 16:26:49 +06:00
|
|
|
{
|
2022-02-05 01:01:06 +05:00
|
|
|
isMouseDown |= 1;
|
2021-11-30 16:26:49 +06:00
|
|
|
if (mouse_capture)
|
|
|
|
|
{
|
|
|
|
|
mousedata.mousebuttons |= event->button();
|
|
|
|
|
}
|
2021-12-29 23:49:09 +06:00
|
|
|
if (main_window->frameGeometry().contains(event->pos()) && !geometry().contains(event->pos()))
|
|
|
|
|
{
|
|
|
|
|
main_window->windowHandle()->startSystemMove();
|
|
|
|
|
}
|
2021-12-02 16:26:33 +06:00
|
|
|
event->accept();
|
2021-11-30 16:26:49 +06:00
|
|
|
}
|
2021-12-04 21:33:04 +01:00
|
|
|
void RendererStack::wheelEvent(QWheelEvent *event)
|
2021-11-30 16:26:49 +06:00
|
|
|
{
|
|
|
|
|
if (mouse_capture)
|
|
|
|
|
{
|
2021-12-06 16:33:25 +06:00
|
|
|
mousedata.deltaz += event->pixelDelta().y();
|
2021-11-30 16:26:49 +06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-04 21:33:04 +01:00
|
|
|
void RendererStack::mouseMoveEvent(QMouseEvent *event)
|
2021-11-30 16:26:49 +06:00
|
|
|
{
|
2021-12-02 16:26:33 +06:00
|
|
|
if (QApplication::platformName().contains("wayland"))
|
|
|
|
|
{
|
|
|
|
|
event->accept();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-11-30 16:26:49 +06:00
|
|
|
if (!mouse_capture) { event->ignore(); return; }
|
|
|
|
|
#ifdef __APPLE__
|
|
|
|
|
event->accept();
|
|
|
|
|
return;
|
|
|
|
|
#else
|
|
|
|
|
static QPoint oldPos = QCursor::pos();
|
|
|
|
|
if (ignoreNextMouseEvent) { oldPos = event->pos(); ignoreNextMouseEvent--; event->accept(); return; }
|
|
|
|
|
mousedata.deltax += event->pos().x() - oldPos.x();
|
|
|
|
|
mousedata.deltay += event->pos().y() - oldPos.y();
|
2021-12-09 00:01:22 +06:00
|
|
|
if (QApplication::platformName() == "eglfs")
|
|
|
|
|
{
|
|
|
|
|
leaveEvent((QEvent*)event);
|
|
|
|
|
ignoreNextMouseEvent--;
|
|
|
|
|
}
|
|
|
|
|
else if (event->globalPos().x() == 0 || event->globalPos().y() == 0) leaveEvent((QEvent*)event);
|
|
|
|
|
else if (event->globalPos().x() == (screen()->geometry().width() - 1) || event->globalPos().y() == (screen()->geometry().height() - 1)) leaveEvent((QEvent*)event);
|
2021-11-30 16:26:49 +06:00
|
|
|
oldPos = event->pos();
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-08 16:27:58 +06:00
|
|
|
void RendererStack::leaveEvent(QEvent* event)
|
|
|
|
|
{
|
|
|
|
|
if (QApplication::platformName().contains("wayland"))
|
|
|
|
|
{
|
|
|
|
|
event->accept();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!mouse_capture) return;
|
|
|
|
|
QCursor::setPos(mapToGlobal(QPoint(width() / 2, height() / 2)));
|
|
|
|
|
ignoreNextMouseEvent = 2;
|
|
|
|
|
event->accept();
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 19:58:09 +01:00
|
|
|
void RendererStack::switchRenderer(Renderer renderer) {
|
|
|
|
|
startblit();
|
2021-12-15 20:02:35 +01:00
|
|
|
if (current) {
|
|
|
|
|
removeWidget(current.get());
|
2021-12-15 19:58:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (renderer) {
|
|
|
|
|
case Renderer::Software:
|
|
|
|
|
{
|
2022-01-15 21:45:34 +02:00
|
|
|
auto sw = new SoftwareRenderer(this);
|
2021-12-31 13:02:27 +06:00
|
|
|
rendererWindow = sw;
|
2021-12-15 21:09:59 +02:00
|
|
|
connect(this, &RendererStack::blitToRenderer, sw, &SoftwareRenderer::onBlit, Qt::QueuedConnection);
|
2021-12-29 23:49:09 +06:00
|
|
|
current.reset(this->createWindowContainer(sw, this));
|
2021-12-15 19:58:09 +01:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case Renderer::OpenGL:
|
|
|
|
|
{
|
2021-12-17 12:17:54 +06:00
|
|
|
this->createWinId();
|
2021-12-18 00:37:30 +06:00
|
|
|
auto hw = new HardwareRenderer(this);
|
2021-12-31 13:02:27 +06:00
|
|
|
rendererWindow = hw;
|
2021-12-15 21:09:59 +02:00
|
|
|
connect(this, &RendererStack::blitToRenderer, hw, &HardwareRenderer::onBlit, Qt::QueuedConnection);
|
2021-12-17 12:17:54 +06:00
|
|
|
current.reset(this->createWindowContainer(hw, this));
|
2021-12-15 19:58:09 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case Renderer::OpenGLES:
|
|
|
|
|
{
|
2021-12-17 12:17:54 +06:00
|
|
|
this->createWinId();
|
2021-12-26 11:52:50 +06:00
|
|
|
auto hw = new HardwareRenderer(this, HardwareRenderer::RenderType::OpenGLES);
|
2021-12-31 13:02:27 +06:00
|
|
|
rendererWindow = hw;
|
2021-12-15 21:09:59 +02:00
|
|
|
connect(this, &RendererStack::blitToRenderer, hw, &HardwareRenderer::onBlit, Qt::QueuedConnection);
|
2021-12-17 12:17:54 +06:00
|
|
|
current.reset(this->createWindowContainer(hw, this));
|
2021-12-27 16:32:03 +06:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case Renderer::OpenGL3:
|
|
|
|
|
{
|
|
|
|
|
this->createWinId();
|
|
|
|
|
auto hw = new HardwareRenderer(this, HardwareRenderer::RenderType::OpenGL3);
|
2021-12-31 13:02:27 +06:00
|
|
|
rendererWindow = hw;
|
2021-12-27 16:32:03 +06:00
|
|
|
connect(this, &RendererStack::blitToRenderer, hw, &HardwareRenderer::onBlit, Qt::QueuedConnection);
|
|
|
|
|
current.reset(this->createWindowContainer(hw, this));
|
2021-12-15 19:58:09 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-01-15 21:45:34 +02:00
|
|
|
|
|
|
|
|
imagebufs = std::move(rendererWindow->getBuffers());
|
|
|
|
|
|
2021-12-15 19:58:09 +01:00
|
|
|
current->setFocusPolicy(Qt::NoFocus);
|
2021-12-18 00:37:30 +06:00
|
|
|
current->setFocusProxy(this);
|
2021-12-15 20:02:35 +01:00
|
|
|
addWidget(current.get());
|
2021-12-15 21:19:46 +02:00
|
|
|
|
2021-12-25 15:34:00 +06:00
|
|
|
this->setStyleSheet("background-color: black");
|
2021-12-15 21:19:46 +02:00
|
|
|
|
2021-12-15 19:58:09 +01:00
|
|
|
endblit();
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-04 21:33:04 +01:00
|
|
|
// called from blitter thread
|
|
|
|
|
void RendererStack::blit(int x, int y, int w, int h)
|
2021-11-30 16:26:49 +06:00
|
|
|
{
|
2022-01-15 21:45:34 +02:00
|
|
|
if ((w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (buffer32 == NULL) || std::get<std::atomic_flag*>(imagebufs[currentBuf])->test_and_set())
|
2021-11-30 16:26:49 +06:00
|
|
|
{
|
|
|
|
|
video_blit_complete();
|
2021-12-04 21:33:04 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
sx = x;
|
|
|
|
|
sy = y;
|
|
|
|
|
sw = this->w = w;
|
|
|
|
|
sh = this->h = h;
|
2022-01-15 21:45:34 +02:00
|
|
|
uint8_t* imagebits = std::get<uint8_t*>(imagebufs[currentBuf]);
|
2022-01-14 12:39:49 +06:00
|
|
|
for (int y1 = y; y1 < (y + h - 1); y1++)
|
|
|
|
|
{
|
|
|
|
|
auto scanline = imagebits + (y1 * (2048) * 4) + (x * 4);
|
|
|
|
|
video_copy(scanline, &(buffer32->line[y1][x]), w * 4);
|
|
|
|
|
}
|
2021-12-04 21:33:04 +01:00
|
|
|
|
|
|
|
|
if (screenshots)
|
|
|
|
|
{
|
2021-12-26 00:49:21 +06:00
|
|
|
video_screenshot((uint32_t *)imagebits, x, y, 2048);
|
2021-12-04 21:33:04 +01:00
|
|
|
}
|
|
|
|
|
video_blit_complete();
|
2022-01-15 21:45:34 +02:00
|
|
|
emit blitToRenderer(currentBuf, sx, sy, sw, sh);
|
|
|
|
|
currentBuf = (currentBuf + 1) % imagebufs.size();
|
2021-12-04 21:33:04 +01:00
|
|
|
}
|