Compare commits

...

13 commits

Author SHA1 Message Date
KojoZero
75b31cf018
Merge 36118a1409 into 4867bb2e2b 2026-05-31 00:21:23 +02:00
KojoZero
36118a1409 attempted build fix 2 2026-05-13 23:23:33 -07:00
KojoZero
12fa52f636 attempted build fix 1 2026-05-13 23:11:30 -07:00
KojoZero
9149f29c1a updated TouchDirectlyPressed, fixed auto map, and cursor rotation 2026-04-29 22:36:35 -07:00
KojoZero
0ba8e18dc4 added c-stick toggle and stylus related gui changes 2026-04-28 20:13:55 -07:00
KojoZero
ae3bd188c0 implemented functioning right stick cursor 2026-04-28 02:34:38 -07:00
KojoZero
bb5dbf4c0f setup cursor class and related variables/methods 2026-04-26 14:18:14 -07:00
KojoZero
93cdb65693 expose inputs related to cursor from hid 2026-04-26 11:21:20 -07:00
KojoZero
f83e60243e added cursor to vulkan 2026-04-24 13:27:49 -07:00
KojoZero
e489fac61b added uniforms for vulkan 2026-04-24 08:54:20 -07:00
KojoZero
2dfab0ac69 fixed rfrag_tex_coord y axis, prototyping cursor position 2026-04-23 20:59:13 -07:00
KojoZero
ff127ce517 enabled cursor only on bottom screen 2026-04-23 20:28:54 -07:00
KojoZero
c22816591d implemented cursor draw in opengl 2026-04-23 20:03:42 -07:00
25 changed files with 663 additions and 106 deletions

View file

@ -33,6 +33,7 @@ const std::array<int, Settings::NativeButton::NumButtons> QtConfig::default_butt
Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X, Qt::Key_T, Qt::Key_G,
Qt::Key_F, Qt::Key_H, Qt::Key_Q, Qt::Key_W, Qt::Key_M, Qt::Key_N,
Qt::Key_O, Qt::Key_P, Qt::Key_1, Qt::Key_2, Qt::Key_B, Qt::Key_V,
Qt::Key_U,
};
const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> QtConfig::default_analogs{{

View file

@ -171,7 +171,7 @@ ConfigureInput::ConfigureInput(Core::System& _system, QWidget* parent)
ui->buttonDpadUp, ui->buttonDpadDown, ui->buttonDpadLeft, ui->buttonDpadRight,
ui->buttonL, ui->buttonR, ui->buttonStart, ui->buttonSelect,
ui->buttonDebug, ui->buttonGpio14, ui->buttonZL, ui->buttonZR,
ui->buttonHome, ui->buttonPower,
ui->buttonHome, ui->buttonPower, ui->buttonToggleCStick,
};
analog_map_buttons = {{

View file

@ -29,7 +29,7 @@
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -68,6 +68,14 @@
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaContents">
<property name="geometry">
<rect>
<x>0</x>
<y>-180</y>
<width>416</width>
<height>802</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<layout class="QGridLayout" name="gridLayout_7">
@ -88,7 +96,7 @@
<item>
<widget class="QLabel" name="label_18">
<property name="text">
<string>ZR:</string>
<string>Stylus Touch / ZR:</string>
</property>
</widget>
</item>
@ -124,7 +132,7 @@
<item>
<widget class="QLabel" name="label_20">
<property name="text">
<string>ZL:</string>
<string>Stylus Mod / ZL:</string>
</property>
</widget>
</item>
@ -344,17 +352,17 @@
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_6">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_25">
<item row="2" column="0">
<layout class="QVBoxLayout" name="verticalLayout_28">
<item>
<widget class="QLabel" name="label_29">
<widget class="QLabel" name="label_36">
<property name="text">
<string>Start:</string>
<string>Circle Mod:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonStart">
<widget class="QPushButton" name="buttonCircleMod">
<property name="text">
<string/>
</property>
@ -380,24 +388,6 @@
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QVBoxLayout" name="verticalLayout_27">
<item>
<widget class="QLabel" name="label_31">
<property name="text">
<string>Home:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonHome">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="1">
<layout class="QVBoxLayout" name="verticalLayout_34">
<item>
@ -416,24 +406,6 @@
</item>
</layout>
</item>
<item row="2" column="0">
<layout class="QVBoxLayout" name="verticalLayout_28">
<item>
<widget class="QLabel" name="label_36">
<property name="text">
<string>Circle Mod:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonCircleMod">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="1">
<layout class="QVBoxLayout" name="verticalLayout_33">
<item>
@ -452,6 +424,42 @@
</item>
</layout>
</item>
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_25">
<item>
<widget class="QLabel" name="label_29">
<property name="text">
<string>Start:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonStart">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QVBoxLayout" name="verticalLayout_27">
<item>
<widget class="QLabel" name="label_31">
<property name="text">
<string>Home:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonHome">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0">
<layout class="QVBoxLayout" name="verticalLayout_32">
<item>
@ -470,6 +478,24 @@
</item>
</layout>
</item>
<item row="3" column="1">
<layout class="QVBoxLayout" name="verticalLayout_40">
<item>
<widget class="QLabel" name="label_42">
<property name="text">
<string>Toggle C-Stick:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonToggleCStick">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
@ -572,7 +598,7 @@
<item>
<layout class="QHBoxLayout" name="sliderCirclePadDeadzoneAndModifierHorizontalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
<enum>QLayout::SizeConstraint::SetDefaultConstraint</enum>
</property>
<item>
<widget class="QLabel" name="labelCirclePadDeadzoneAndModifier">
@ -580,7 +606,7 @@
<string>Deadzone: 0</string>
</property>
<property name="alignment">
<set>Qt::AlignHCenter</set>
<set>Qt::AlignmentFlag::AlignHCenter</set>
</property>
</widget>
</item>
@ -589,7 +615,7 @@
<item>
<widget class="QSlider" name="sliderCirclePadDeadzoneAndModifier">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
</item>
@ -634,25 +660,25 @@
<item row="4" column="1" colspan="2">
<layout class="QVBoxLayout" name="verticalLayout_38">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
<enum>QLayout::SizeConstraint::SetDefaultConstraint</enum>
</property>
<item>
<widget class="QLabel" name="label_14">
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
<enum>Qt::LayoutDirection::LeftToRight</enum>
</property>
<property name="text">
<string>Diagonals</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
<set>Qt::AlignmentFlag::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
</item>
@ -697,7 +723,7 @@
<item row="14" column="1" colspan="2">
<widget class="Line" name="line_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
</item>
@ -707,7 +733,7 @@
<item row="1" column="1">
<widget class="QGroupBox" name="faceButtons_5">
<property name="title">
<string>C-Stick</string>
<string>Stylus / C-Stick</string>
</property>
<property name="flat">
<bool>false</bool>
@ -868,14 +894,14 @@
<string>Diagonals</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
<set>Qt::AlignmentFlag::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
</item>
@ -884,7 +910,7 @@
<item row="9" column="0" colspan="2">
<layout class="QVBoxLayout" name="sliderCStickDeadzoneAndModifierVerticalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
<enum>QLayout::SizeConstraint::SetDefaultConstraint</enum>
</property>
<item>
<layout class="QHBoxLayout" name="sliderCStickDeadzoneAndModifierHorizontalLayout">
@ -894,7 +920,7 @@
<string>Deadzone: 0</string>
</property>
<property name="alignment">
<set>Qt::AlignHCenter</set>
<set>Qt::AlignmentFlag::AlignHCenter</set>
</property>
</widget>
</item>
@ -903,7 +929,7 @@
<item>
<widget class="QSlider" name="sliderCStickDeadzoneAndModifier">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
</item>
@ -919,7 +945,7 @@
<item row="7" column="0" colspan="2">
<widget class="Line" name="line_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
</item>
@ -957,7 +983,7 @@
</size>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
<enum>Qt::LayoutDirection::LeftToRight</enum>
</property>
<property name="text">
<string>Motion / Touch...</string>
@ -985,7 +1011,7 @@
</size>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
<enum>Qt::LayoutDirection::LeftToRight</enum>
</property>
<property name="text">
<string>Auto Map</string>
@ -1013,7 +1039,7 @@
</size>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
<enum>Qt::LayoutDirection::LeftToRight</enum>
</property>
<property name="text">
<string>Clear All</string>
@ -1041,7 +1067,7 @@
</size>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
<enum>Qt::LayoutDirection::LeftToRight</enum>
</property>
<property name="text">
<string>Restore Defaults</string>
@ -1094,6 +1120,7 @@
<tabstop>buttonCircleMod</tabstop>
<tabstop>buttonDebug</tabstop>
<tabstop>buttonGpio14</tabstop>
<tabstop>buttonToggleCStick</tabstop>
<tabstop>buttonMotionTouch</tabstop>
<tabstop>buttonAutoMap</tabstop>
<tabstop>buttonClearAll</tabstop>

View file

@ -151,6 +151,8 @@ enum Values {
Home,
Power,
ToggleCStick,
NumButtons,
};
@ -185,6 +187,7 @@ static const std::array<const char*, NumButtons> mapping = {{
"button_zr",
"button_home",
"button_power",
"button_togglecstick",
}};
} // namespace NativeButton

View file

@ -121,6 +121,8 @@ add_library(citra_core STATIC EXCLUDE_FROM_ALL
frontend/camera/interface.h
frontend/emu_window.cpp
frontend/emu_window.h
frontend/cursor.cpp
frontend/cursor.h
frontend/framebuffer_layout.cpp
frontend/framebuffer_layout.h
frontend/image_interface.cpp

View file

@ -0,0 +1,276 @@
#include "cursor.h"
#include <cmath>
#include <algorithm>
#include "common/logging/log.h"
#include "common/logging/types.h"
#include "core/hle/service/hid/hid.h"
void Cursor::update(){
if (emuWindow != nullptr){
stylusInput = Service::HID::Module::getStylusInputs();
modButtons = Service::HID::Module::getModButtons();
setRotation();
if (deviceInUse == 0){
if (!Service::HID::Module::cstickEnabled){
if (inMacro){
runMacro();
} else {
// LOG_INFO(Core, "Stylus X: {:.2f}, Stylus Y: {:.2f}, Stylus Mod: {}, Stylus Touch: {}", stylusInput[0], stylusInput[1], stylusInput[2], stylusInput[3]);
// Reset the cursor position if macro was just played
if (justFinishedMacro > 0){
justFinishedMacro = 0;
rawCursorPos[0] = macroInitPos[0];
rawCursorPos[1] = macroInitPos[1];
}
// Macros
if (modButtons[0]){
circle(0);
return;
} else if (modButtons[1]){
rub();
return;
} else if (modButtons[2]){
if (!macroBtnPressed){
// Add macro
return;
}
} else if (modButtons[3]){
circle(1);
return;
} else {
if (macroBtnPressed){
macroBtnPressed = false;
}
}
normStylusDirection[0] = stylusInput[0];
normStylusDirection[1] = stylusInput[1];
int maxSpeed = 50;
float multiplier = 0.5f * pow(4.0f, maxSpeed / 100.0f); // 0 is 0.5x speed, 100 is 2.0x speed.
float heightSpeed = (240.0f / 33.0f) * multiplier;
bool stylusModPressed = stylusInput[2];
float responsecurve = 175.0f / 100.0f;
float speedupratio = 400.0f / 100.0f;
float joystickScaled[2] = {0.0f};
float radialLength = std::sqrt((normStylusDirection[0] * normStylusDirection[0]) + (normStylusDirection[1] * normStylusDirection[1]));
float finalLength;
float curvedLength;
if (radialLength > 0) {
// Get X and Y as a relation to the radial length
float rComponents[2];
rComponents[0] = normStylusDirection[0]/radialLength;
rComponents[1] = normStylusDirection[1]/radialLength;
// Apply response curve and output
curvedLength = std::pow(radialLength, responsecurve);
finalLength = stylusModPressed ? curvedLength * speedupratio : curvedLength;
joystickScaled[0] = rComponents[0] * finalLength;
joystickScaled[1] = rComponents[1] * finalLength;
}
// The code below sets the cursor position to the position of the joystick (absolute). Needs to be readjusted for standalone melonDS
// _joystickCursorPosition = vec2((NDS_SCREEN_WIDTH/2.0f)+(std::min<float>(1.0,(normStylusDirection[0]/0.7071))*(NDS_SCREEN_WIDTH/2.0f)), (NDS_SCREEN_HEIGHT/2.0f)+(std::min<float>(1.0,(normStylusDirection[1]/0.7071))*(NDS_SCREEN_HEIGHT/2.0f)));
float tempX = joystickScaled[0];
float tempY = joystickScaled[1];
switch (rotation)
{
case 1: // 90°
joystickScaled[0] = tempY;
joystickScaled[1] = -tempX;
break;
case 2: // 180°
joystickScaled[0] = -tempX;
joystickScaled[1] = -tempY;
break;
case 3: // 270°
joystickScaled[0] = -tempY;
joystickScaled[1] = tempX;
break;
default:
break;
}
rawCursorPos[0] += joystickScaled[0]*heightSpeed;
rawCursorPos[1] += joystickScaled[1]*heightSpeed;
// Clamp to region and ready position information for touchscreen
clamp();
updateCursorPos();
// Handle stylus touch button presses
if (stylusInput[3]){
touchScreen();
wasTouching = true;
} else if (wasTouching && !stylusInput[3]){
release();
wasTouching = false;
}
}
}
} else {
//Update cursor based on mouse position
clamp();
updateCursorPos();
// Handle stylus touch button presses
if (stylusInput[3]){
touchScreen();
wasTouching = true;
} else if (wasTouching && !stylusInput[3]){
release();
wasTouching = false;
}
setDeviceInUse(0);
}
}
}
void Cursor::setDeviceInUse(int device){
deviceInUse = device;
}
void Cursor::setRawCursorPos(float x, float y){
rawCursorPos[0] = x;
rawCursorPos[1] = y;
}
void Cursor::clamp(){
rawCursorPos[0] = std::clamp(rawCursorPos[0], 0.0f, 319.0f);
rawCursorPos[1] = std::clamp(rawCursorPos[1], 0.0f, 239.0f);
}
void Cursor::touchScreen(){
emuWindow->TouchDirectlyPressed(cursorPos[0], cursorPos[1]);
}
void Cursor::release(){
emuWindow->TouchReleased();
}
void Cursor::setEmuWindow(Frontend::EmuWindow* emuWindow){
this->emuWindow = emuWindow;
}
void Cursor::updateCursorPos(){
cursorPos[0] = std::floor(rawCursorPos[0]);
cursorPos[1] = std::floor(rawCursorPos[1]);
}
void Cursor::circle(int direction){
macroBtnPressed = true;
inMacro = true;
wasTouching = true;
macroType = 1;
float radius = 240.0f/4.0f;
if (justFinishedMacro != 1){ // Set the original position if just starting
macroInitPos = {rawCursorPos[0], rawCursorPos[1]};
}
std::vector<std::array<float, 2>> offsetArray;
if (direction == 0){
offsetArray.push_back({(0.0f*radius), (-1.0f*radius)});
offsetArray.push_back({(0.7071f*radius), (-0.7071f*radius)});
offsetArray.push_back({(1.0f*radius), (0.0f*radius)});
offsetArray.push_back({(0.7071f*radius), (0.7071f*radius)});
offsetArray.push_back({(0.0f*radius), (1.0f*radius)});
offsetArray.push_back({(-0.7071f*radius), (0.7071f*radius)});
offsetArray.push_back({(-1.0f*radius), (0.0f*radius)});
offsetArray.push_back({(-0.7071f*radius), (-0.7071f*radius)});
} else {
offsetArray.push_back({(0.0f*radius), (-1.0f*radius)});
offsetArray.push_back({(-0.7071f*radius), (-0.7071f*radius)});
offsetArray.push_back({(-1.0f*radius), (0.0f*radius)});
offsetArray.push_back({(-0.7071f*radius), (0.7071f*radius)});
offsetArray.push_back({(0.0f*radius), (1.0f*radius)});
offsetArray.push_back({(0.7071f*radius), (0.7071f*radius)});
offsetArray.push_back({(1.0f*radius), (0.0f*radius)});
offsetArray.push_back({(0.7071f*radius), (-0.7071f*radius)});
}
offsetArray = rotateVector(offsetArray);
for (std::size_t i = 0; i < offsetArray.size(); i++){
macroPositions.push_back({rawCursorPos[0]+offsetArray[i][0], rawCursorPos[1]+offsetArray[i][1]});
}
macroFrames = macroPositions.size();
runMacro();
}
void Cursor::rub(){
macroBtnPressed = true;
inMacro = true;
wasTouching = true;
macroType = 2;
float radius = 240.0f/6.0f;
if (justFinishedMacro != 2){ // Set the original position if just starting
macroInitPos = {rawCursorPos[0], rawCursorPos[1]};
}
std::vector<std::array<float, 2>> offsetArray;
offsetArray.push_back({(0.0f*radius), 0});
offsetArray.push_back({(0.5f*radius), 0});
offsetArray.push_back({(1.0f*radius), 0});
offsetArray.push_back({(0.5f*radius), 0});
offsetArray.push_back({(0.0f*radius), 0});
offsetArray.push_back({(-0.5f*radius), 0});
offsetArray.push_back({(-1.0f*radius), 0});
offsetArray.push_back({(-0.5f*radius), 0});
offsetArray = rotateVector(offsetArray);
for (std::size_t i = 0; i < offsetArray.size(); i++){
macroPositions.push_back({rawCursorPos[0]+offsetArray[i][0], rawCursorPos[1]+offsetArray[i][1]});
}
macroFrames = macroPositions.size();
runMacro();
}
void Cursor::runMacro(){
rawCursorPos[0] = macroPositions.front()[0];
rawCursorPos[1] = macroPositions.front()[1];
macroPositions.pop_front();
clamp();
updateCursorPos();
touchScreen();
macroFrames--;
if (macroFrames == 0){
macroPositions.clear();
inMacro = false;
justFinishedMacro = macroType;
}
}
void Cursor::setRotation(){
if (emuWindow->GetFramebufferLayout().is_portrait){
rotation = 1;
} else {
rotation = 0;
}
}
std::vector<std::array<float, 2>> Cursor::rotateVector(std::vector<std::array<float, 2>> input){
for (auto& currArray : input){
float tempX = currArray[0];
float tempY = currArray[1];
switch (rotation)
{
case 1: // 90°
currArray[0] = tempY;
currArray[1] = -tempX;
break;
case 2: // 180°
currArray[0] = -tempX;
currArray[1] = -tempY;
break;
case 3: // 270°
currArray[0] = -tempY;
currArray[1] = tempX;
break;
default:
break;
}
}
return input;
}

View file

@ -0,0 +1,48 @@
#ifndef CURSOR_H
#define CURSOR_H
#include <queue>
#include "emu_window.h"
#include <array>
#include <vector>
namespace Frontend {
class EmuWindow;
}
class Cursor
{
public:
void update();
void setRawCursorPos(float x, float y);
void setDeviceInUse(int device);
void setEmuWindow(Frontend::EmuWindow* emuWindow);
void setRotation();
int cursorPos[2];
float normStylusDirection[2];
bool cursorEnabled = true;
private:
Frontend::EmuWindow* emuWindow = nullptr;
float rawCursorPos[2] = {159, 119};
void touchScreen();
void release();
void clamp();
void updateCursorPos();
bool wasTouching;
std::array<float, 4> stylusInput;
std::array<float, 4> modButtons;
void circle(int direction); //0 is clockwise, 1 is counter clockwise
void rub();
void runMacro();
std::vector<std::array<float, 2>> rotateVector(std::vector<std::array<float, 2>> input);
bool inMacro;
std::deque<std::array<float, 2>> macroPositions;
int macroFrames;
bool macroBtnPressed;
int macroType;
int justFinishedMacro;
std::array<float, 2> macroInitPos;
int rotation;
int deviceInUse; //0 is Gamepad, 1 is Mouse/Tablet
};
#endif // CURSOR_H

View file

@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include <cmath>
#include <mutex>
#include "common/settings.h"
@ -191,6 +192,16 @@ bool EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) {
return true;
}
bool EmuWindow::TouchDirectlyPressed(unsigned internal_x, unsigned internal_y) {
//This assumes 0, 0 is bottom left corner
std::scoped_lock guard{touch_state->mutex};
std::clamp<unsigned>(internal_x, 0, 319);
std::clamp<unsigned>(internal_y, 0, 239);
touch_state->touch_pressed = true;
touch_state->touch_x = internal_x/320.0f;
touch_state->touch_y = (239-internal_y)/240.0f;
return true;
}
void EmuWindow::TouchReleased() {
std::scoped_lock guard{touch_state->mutex};
touch_state->touch_pressed = false;

View file

@ -199,6 +199,9 @@ public:
*/
bool TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y);
/// Signal a touch pressed event occured, bypassing the framebuffer (e.g. stylus touch button pressed on controller)
bool TouchDirectlyPressed(unsigned internal_x, unsigned internal_y);
/// Signal that a touch released event has occurred (e.g. mouse click released)
void TouchReleased();

View file

@ -639,6 +639,7 @@ FramebufferLayout reverseLayout(FramebufferLayout layout) {
layout.additional_screen.top = layout.height - oldRight;
layout.additional_screen.bottom = layout.height - oldLeft;
}
layout.is_portrait = true;
return layout;
}

View file

@ -24,12 +24,15 @@
#include "core/hle/service/ir/ir_user.h"
#include "core/hle/service/service.h"
#include "core/movie.h"
#include "hid.h"
SERVICE_CONSTRUCT_IMPL(Service::HID::Module)
SERIALIZE_EXPORT_IMPL(Service::HID::Module)
namespace Service::HID {
std::array<float, 4> Module::stylusInput = {};
std::array<float, 4> Module::modButtons = {};
bool Module::cstickEnabled = false;
template <class Archive>
void Module::serialize(Archive& ar, const unsigned int file_version) {
DEBUG_SERIALIZATION_POINT;
@ -121,8 +124,16 @@ void Module::LoadInputDevices() {
Settings::values.current_input_profile.buttons.begin() +
Settings::NativeButton::BUTTON_HID_END,
buttons.begin(), Input::CreateDevice<Input::ButtonDevice>);
zl_button = Input::CreateDevice<Input::ButtonDevice>(
Settings::values.current_input_profile.buttons[Settings::NativeButton::ZL]);
zr_button = Input::CreateDevice<Input::ButtonDevice>(
Settings::values.current_input_profile.buttons[Settings::NativeButton::ZR]);
toggle_cstick_button = Input::CreateDevice<Input::ButtonDevice>(
Settings::values.current_input_profile.buttons[Settings::NativeButton::ToggleCStick]);
circle_pad = Input::CreateDevice<Input::AnalogDevice>(
Settings::values.current_input_profile.analogs[Settings::NativeAnalog::CirclePad]);
c_stick = Input::CreateDevice<Input::AnalogDevice>(
Settings::values.current_input_profile.analogs[Settings::NativeAnalog::CStick]);
motion_device = Input::CreateDevice<Input::MotionDevice>(
Settings::values.current_input_profile.motion_device);
touch_device = Input::CreateDevice<Input::TouchDevice>(
@ -217,6 +228,24 @@ void Module::UpdatePadCallback(std::uintptr_t user_data, s64 cycles_late) {
state.debug.Assign(buttons[Debug - BUTTON_HID_BEGIN]->GetStatus());
state.gpio14.Assign(buttons[Gpio14 - BUTTON_HID_BEGIN]->GetStatus());
// Setting up inputs for Cursor Class.
float c_stick_x_f, c_stick_y_f;
std::tie(c_stick_x_f, c_stick_y_f) = c_stick->GetStatus();
stylusInput[0] = c_stick_x_f;
stylusInput[1] = c_stick_y_f;
stylusInput[2] = static_cast<float>(zl_button->GetStatus());
stylusInput[3] = static_cast<float>(zr_button->GetStatus());
for (int i = 0; i < 4; i++){
modButtons[i] = zl_button->GetStatus() && buttons[i - BUTTON_HID_BEGIN]->GetStatus();
}
//Toggle for Cstick
if (!prev_toggle_cstick_button_state && toggle_cstick_button->GetStatus()){
cstickEnabled = !cstickEnabled;
}
//LOG_INFO(Service_HID, "C-Stick Enabled: {}, Prev C-Stick Button State {}, Current C-Stick Button State {}", cstickEnabled, prev_toggle_cstick_button_state, toggle_cstick_button->GetStatus());
prev_toggle_cstick_button_state = toggle_cstick_button->GetStatus();
// Get current circle pad position and update circle pad direction
float circle_pad_x_f, circle_pad_y_f;
std::tie(circle_pad_x_f, circle_pad_y_f) = circle_pad->GetStatus();
@ -320,6 +349,14 @@ void Module::UpdatePadCallback(std::uintptr_t user_data, s64 cycles_late) {
system.CoreTiming().ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event);
}
std::array<float, 4> Module::getStylusInputs(){
return stylusInput;
}
std::array<float, 4> Module::getModButtons(){
return modButtons;
}
void Module::UpdateAccelerometerCallback(std::uintptr_t user_data, s64 cycles_late) {
SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer());

View file

@ -242,9 +242,8 @@ public:
class Interface : public ServiceFramework<Interface> {
public:
Interface(std::shared_ptr<Module> hid, const char* name, u32 max_session);
// Stylus X, Y, ZL, ZR
std::shared_ptr<Module> GetModule() const;
protected:
/**
* HID::GetIPCHandles service function
@ -335,7 +334,9 @@ public:
void UseArticClient(const std::shared_ptr<Network::ArticBase::Client>& client);
void ReloadInputDevices();
static std::array<float, 4> getStylusInputs();
static std::array<float, 4> getModButtons();
static bool cstickEnabled;
const PadState& GetState() const;
// Updating period for each HID device. These empirical values are measured from a 11.2 3DS.
@ -388,12 +389,18 @@ private:
std::atomic<bool> is_device_reload_pending{true};
std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>
buttons;
std::unique_ptr<Input::ButtonDevice> zl_button;
std::unique_ptr<Input::ButtonDevice> zr_button;
std::unique_ptr<Input::ButtonDevice> toggle_cstick_button;
std::unique_ptr<Input::AnalogDevice> circle_pad;
std::unique_ptr<Input::AnalogDevice> c_stick;
std::unique_ptr<Input::MotionDevice> motion_device;
std::unique_ptr<Input::TouchDevice> controller_touch_device;
std::unique_ptr<Input::TouchDevice> touch_device;
std::unique_ptr<Input::TouchDevice> touch_btn_device;
static std::array<float, 4> stylusInput;
static std::array<float, 4> modButtons;
bool prev_toggle_cstick_button_state = false;
std::shared_ptr<ArticBaseController> artic_controller;
std::shared_ptr<Network::ArticBase::Client> artic_client;

View file

@ -262,13 +262,20 @@ void ExtraHID::SendHIDStatus() {
} else {
float x, y;
std::tie(x, y) = c_stick->GetStatus();
response.buttons.battery_level.Assign(0x1F);
response.c_stick.header.Assign(static_cast<u8>(ResponseID::PollHID));
if (Service::HID::Module::cstickEnabled){
response.c_stick.c_stick_x.Assign(static_cast<u32>(C_STICK_CENTER + C_STICK_RADIUS * x));
response.c_stick.c_stick_y.Assign(static_cast<u32>(C_STICK_CENTER + C_STICK_RADIUS * y));
response.buttons.battery_level.Assign(0x1F);
response.buttons.zl_not_held.Assign(!zl->GetStatus());
response.buttons.zr_not_held.Assign(!zr->GetStatus());
} else {
response.c_stick.c_stick_x.Assign(static_cast<u32>(C_STICK_CENTER));
response.c_stick.c_stick_y.Assign(static_cast<u32>(C_STICK_CENTER));
response.buttons.zl_not_held.Assign(true);
response.buttons.zr_not_held.Assign(true);
}
response.buttons.r_not_held.Assign(1);
response.unknown = 0;
}

View file

@ -140,6 +140,7 @@ constexpr std::array<SDL_GameControllerButton, Settings::NativeButton::NumButton
SDL_CONTROLLER_BUTTON_INVALID,
SDL_CONTROLLER_BUTTON_GUIDE,
SDL_CONTROLLER_BUTTON_INVALID,
SDL_CONTROLLER_BUTTON_LEFTSTICK,
}};
struct SDLJoystickDeleter {

View file

@ -11,8 +11,48 @@ layout(binding = 0) uniform sampler2D color_texture;
uniform vec4 i_resolution;
uniform vec4 o_resolution;
uniform vec2 cursor_pos;
uniform bool cursor_enable;
uniform int layer;
in vec2 pixelUnit;
void main() {
color = texture(color_texture, frag_tex_coord);
vec4 pixel = texture(color_texture, frag_tex_coord);
vec2 rfrag_tex_coord = vec2(frag_tex_coord.y, frag_tex_coord.x);
//Cursor
if (cursor_enable){
//Black Outline
if (rfrag_tex_coord.x <= (cursor_pos.x + (2.0*pixelUnit.x)) &&
rfrag_tex_coord.x >= (cursor_pos.x - (1.0*pixelUnit.x))) {
if (rfrag_tex_coord.y <= (cursor_pos.y + (5.0*pixelUnit.y)) &&
rfrag_tex_coord.y >= (cursor_pos.y - (4.0*pixelUnit.y))) {
pixel = vec4(0.0, 0.0, 0.0, 1.0);
}
}
if (rfrag_tex_coord.y <= (cursor_pos.y + (2.0*pixelUnit.y)) &&
rfrag_tex_coord.y >= (cursor_pos.y - (1.0*pixelUnit.y))) {
if (rfrag_tex_coord.x <= (cursor_pos.x + (5.0*pixelUnit.x)) &&
rfrag_tex_coord.x >= (cursor_pos.x - (4.0*pixelUnit.x))) {
pixel = vec4(0.0, 0.0, 0.0, 1.0);
}
}
//White Cross
if (rfrag_tex_coord.x <= (cursor_pos.x + (1.0*pixelUnit.x)) &&
rfrag_tex_coord.x >= (cursor_pos.x - (0.0*pixelUnit.x))) {
if (rfrag_tex_coord.y <= (cursor_pos.y + (4.0*pixelUnit.y)) &&
rfrag_tex_coord.y >= (cursor_pos.y - (3.0*pixelUnit.y))) {
pixel = vec4(1.0, 1.0, 1.0, 1.0);
}
}
if (rfrag_tex_coord.y <= (cursor_pos.y + (1.0*pixelUnit.y)) &&
rfrag_tex_coord.y >= (cursor_pos.y - (0.0*pixelUnit.y))) {
if (rfrag_tex_coord.x <= (cursor_pos.x + (4.0*pixelUnit.x)) &&
rfrag_tex_coord.x >= (cursor_pos.x - (3.0*pixelUnit.x))) {
pixel = vec4(1.0, 1.0, 1.0, 1.0);
}
}
}
color = vec4(pixel.rgb, 1.0);
}

View file

@ -13,11 +13,13 @@ layout(location = 0) out vec2 frag_tex_coord;
// The third row could be used for projection, which we don't need in 2D. It hence is assumed to
// implicitly be [0, 0, 1]
uniform mat3x2 modelview_matrix;
out vec2 pixelUnit;
void main() {
// Multiply input position by the rotscale part of the matrix and then manually translate by
// the last column. This is equivalent to using a full 3x3 matrix and expanding the vector
// to `vec3(vert_position.xy, 1.0)`
gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0);
frag_tex_coord = vert_tex_coord;
pixelUnit.x = 1/320.0;
pixelUnit.y = 1/240.0;
}

View file

@ -7,11 +7,13 @@
layout (location = 0) in vec2 frag_tex_coord;
layout (location = 0) out vec4 color;
layout (location = 1) in vec2 pixelUnit;
layout (push_constant, std140) uniform DrawInfo {
mat4 modelview_matrix;
vec4 i_resolution;
vec4 o_resolution;
vec2 cursor_pos;
int cursor_enable;
int screen_id_l;
int screen_id_r;
int layer;
@ -20,6 +22,7 @@ layout (push_constant, std140) uniform DrawInfo {
layout (set = 0, binding = 0) uniform sampler2D screen_textures[3];
vec4 GetScreen(int screen_id) {
#ifdef ARRAY_DYNAMIC_INDEX
return texture(screen_textures[screen_id], frag_tex_coord);
@ -36,5 +39,42 @@ vec4 GetScreen(int screen_id) {
}
void main() {
color = GetScreen(screen_id_l);
vec4 pixel = GetScreen(screen_id_l);
vec2 rfrag_tex_coord = vec2(frag_tex_coord.y, frag_tex_coord.x);
//Cursor
if (cursor_enable == 1){
//Black Outline
if (rfrag_tex_coord.x <= (cursor_pos.x + (2.0*pixelUnit.x)) &&
rfrag_tex_coord.x >= (cursor_pos.x - (1.0*pixelUnit.x))) {
if (rfrag_tex_coord.y <= (cursor_pos.y + (5.0*pixelUnit.y)) &&
rfrag_tex_coord.y >= (cursor_pos.y - (4.0*pixelUnit.y))) {
pixel = vec4(0.0, 0.0, 0.0, 1.0);
}
}
if (rfrag_tex_coord.y <= (cursor_pos.y + (2.0*pixelUnit.y)) &&
rfrag_tex_coord.y >= (cursor_pos.y - (1.0*pixelUnit.y))) {
if (rfrag_tex_coord.x <= (cursor_pos.x + (5.0*pixelUnit.x)) &&
rfrag_tex_coord.x >= (cursor_pos.x - (4.0*pixelUnit.x))) {
pixel = vec4(0.0, 0.0, 0.0, 1.0);
}
}
//White Cross
if (rfrag_tex_coord.x <= (cursor_pos.x + (1.0*pixelUnit.x)) &&
rfrag_tex_coord.x >= (cursor_pos.x - (0.0*pixelUnit.x))) {
if (rfrag_tex_coord.y <= (cursor_pos.y + (4.0*pixelUnit.y)) &&
rfrag_tex_coord.y >= (cursor_pos.y - (3.0*pixelUnit.y))) {
pixel = vec4(1.0, 1.0, 1.0, 1.0);
}
}
if (rfrag_tex_coord.y <= (cursor_pos.y + (1.0*pixelUnit.y)) &&
rfrag_tex_coord.y >= (cursor_pos.y - (0.0*pixelUnit.y))) {
if (rfrag_tex_coord.x <= (cursor_pos.x + (4.0*pixelUnit.x)) &&
rfrag_tex_coord.x >= (cursor_pos.x - (3.0*pixelUnit.x))) {
pixel = vec4(1.0, 1.0, 1.0, 1.0);
}
}
}
color = vec4(pixel.rgb, 1.0);
}

View file

@ -8,11 +8,13 @@
layout (location = 0) in vec2 vert_position;
layout (location = 1) in vec2 vert_tex_coord;
layout (location = 0) out vec2 frag_tex_coord;
layout (location = 1) out vec2 pixelUnit;
layout (push_constant, std140) uniform DrawInfo {
mat4 modelview_matrix;
vec4 i_resolution;
vec4 o_resolution;
vec2 cursor_pos;
int cursor_enable;
int screen_id_l;
int screen_id_r;
int layer;
@ -22,4 +24,6 @@ void main() {
vec4 position = vec4(vert_position, 0.0, 1.0) * modelview_matrix;
gl_Position = vec4(position.x, position.y, 0.0, 1.0);
frag_tex_coord = vert_tex_coord;
pixelUnit.x = 1/320.0;
pixelUnit.y = 1/240.0;
}

View file

@ -24,6 +24,8 @@ layout (push_constant, std140) uniform DrawInfo {
mat4 modelview_matrix;
vec4 i_resolution;
vec4 o_resolution;
vec2 cursor_pos;
int cursor_enable;
int screen_id_l;
int screen_id_r;
int layer;

View file

@ -12,6 +12,8 @@ layout (push_constant, std140) uniform DrawInfo {
mat4 modelview_matrix;
vec4 i_resolution;
vec4 o_resolution;
vec2 cursor_pos;
int cursor_enable;
int screen_id_l;
int screen_id_r;
int layer;

View file

@ -7,6 +7,8 @@
#include "common/common_types.h"
#include "core/frontend/framebuffer_layout.h"
#include "video_core/rasterizer_interface.h"
#include "core/frontend/cursor.h"
class Cursor;
namespace Frontend {
class EmuWindow;
@ -109,6 +111,7 @@ protected:
RendererSettings settings;
Frontend::EmuWindow& render_window; /// Reference to the render window handle.
Frontend::EmuWindow* secondary_window; /// Reference to the secondary render window handle.
Cursor* vCursor;
protected:
f32 current_fps = 0.0f; /// Current framerate, should be set by the renderer

View file

@ -78,6 +78,8 @@ RendererOpenGL::RendererOpenGL(Core::System& system, Pica::PicaCore& pica_,
rasterizer{system.Memory(), pica, system.CustomTexManager(), *this, driver},
frame_dumper{system, window} {
const bool has_debug_tool = driver.HasDebugTool();
vCursor = new Cursor();
vCursor->setEmuWindow(&window);
window.mailbox = std::make_unique<OGLTextureMailbox>(has_debug_tool);
if (secondary_window) {
secondary_window->mailbox = std::make_unique<OGLTextureMailbox>(has_debug_tool);
@ -235,6 +237,7 @@ void RendererOpenGL::RenderToMailbox(const Layout::FramebufferLayout& layout,
state.draw.draw_framebuffer = frame->render.handle;
state.Apply();
vCursor->update();
DrawScreens(layout, flipped);
// Create a fence for the frontend to wait on and swap this frame to OffTex
frame->render_fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
@ -433,6 +436,8 @@ void RendererOpenGL::ReloadShader(Settings::StereoRenderOption render_3d) {
uniform_i_resolution = glGetUniformLocation(shader.handle, "i_resolution");
uniform_o_resolution = glGetUniformLocation(shader.handle, "o_resolution");
uniform_layer = glGetUniformLocation(shader.handle, "layer");
uniform_cursor_pos = glGetUniformLocation(shader.handle, "cursor_pos");
uniform_cursor_enable = glGetUniformLocation(shader.handle, "cursor_enable");
attrib_position = glGetAttribLocation(shader.handle, "vert_position");
attrib_tex_coord = glGetAttribLocation(shader.handle, "vert_tex_coord");
}
@ -556,11 +561,17 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float x, fl
const u32 scale_factor = GetResolutionScaleFactor();
const GLuint sampler = samplers[Settings::values.filter_mode.GetValue()].handle;
glUniform4f(uniform_i_resolution, static_cast<float>(screen_info.texture.width * scale_factor),
static_cast<float>(screen_info.texture.height * scale_factor),
1.0f / static_cast<float>(screen_info.texture.width * scale_factor),
1.0f / static_cast<float>(screen_info.texture.height * scale_factor));
glUniform4f(uniform_o_resolution, h, w, 1.0f / h, 1.0f / w);
glUniform4f(uniform_i_resolution, static_cast<float>(screen_info.texture.height * scale_factor),
static_cast<float>(screen_info.texture.width * scale_factor),
1.0f / static_cast<float>(screen_info.texture.height * scale_factor),
1.0f / static_cast<float>(screen_info.texture.width * scale_factor));
glUniform4f(uniform_o_resolution, w, h, 1.0f / w, 1.0f / h);
if (currScreenDraw == 1){
glUniform1i(uniform_cursor_enable, 1);
} else {
glUniform1i(uniform_cursor_enable, 0);
}
glUniform2f(uniform_cursor_pos, vCursor->cursorPos[0]/320.0f, vCursor->cursorPos[1]/240.0f);
state.texture_units[0].texture_2d = screen_info.display_texture;
state.texture_units[0].sampler = sampler;
state.Apply();
@ -627,11 +638,17 @@ void RendererOpenGL::DrawSingleScreenStereo(const ScreenInfo& screen_info_l,
const u32 scale_factor = GetResolutionScaleFactor();
const GLuint sampler = samplers[Settings::values.filter_mode.GetValue()].handle;
glUniform4f(uniform_i_resolution,
static_cast<float>(screen_info_l.texture.width * scale_factor),
static_cast<float>(screen_info_l.texture.height * scale_factor),
1.0f / static_cast<float>(screen_info_l.texture.width * scale_factor),
1.0f / static_cast<float>(screen_info_l.texture.height * scale_factor));
glUniform4f(uniform_o_resolution, h, w, 1.0f / h, 1.0f / w);
static_cast<float>(screen_info_l.texture.width * scale_factor),
1.0f / static_cast<float>(screen_info_l.texture.height * scale_factor),
1.0f / static_cast<float>(screen_info_l.texture.width * scale_factor));
glUniform4f(uniform_o_resolution, w, h, 1.0f / w, 1.0f / h);
if (currScreenDraw == 1){
glUniform1i(uniform_cursor_enable, 1);
} else {
glUniform1i(uniform_cursor_enable, 0);
}
glUniform2f(uniform_cursor_pos, vCursor->cursorPos[0]/320.0f, vCursor->cursorPos[1]/240.0f);
state.texture_units[0].texture_2d = screen_info_l.display_texture;
state.texture_units[1].texture_2d = screen_info_r.display_texture;
state.texture_units[0].sampler = sampler;
@ -736,6 +753,7 @@ void RendererOpenGL::DrawTopScreen(const Layout::FramebufferLayout& layout,
if (!layout.top_screen_enabled) {
return;
}
currScreenDraw = 0;
int leftside, rightside;
leftside = Settings::values.swap_eyes_3d.GetValue() ? 1 : 0;
rightside = Settings::values.swap_eyes_3d.GetValue() ? 0 : 1;
@ -797,7 +815,7 @@ void RendererOpenGL::DrawBottomScreen(const Layout::FramebufferLayout& layout,
if (!layout.bottom_screen_enabled) {
return;
}
currScreenDraw = 1;
const float bottom_screen_left = static_cast<float>(bottom_screen.left);
const float bottom_screen_top = static_cast<float>(bottom_screen.top);
const float bottom_screen_width = static_cast<float>(bottom_screen.GetWidth());

View file

@ -107,9 +107,13 @@ private:
GLuint uniform_o_resolution;
GLuint uniform_layer;
// Shader uniform for onscreen cursor
GLuint uniform_cursor_pos;
GLuint uniform_cursor_enable;
// Shader attribute input indices
GLuint attrib_position;
GLuint attrib_tex_coord;
int currScreenDraw; // 0 is Top, 1 is Bottom
FrameDumperOpenGL frame_dumper;
};

View file

@ -127,6 +127,8 @@ RendererVulkan::RendererVulkan(Core::System& system, Pica::PicaCore& pica_,
update_queue,
main_present_window.ImageCount()},
present_heap{instance, scheduler.GetMasterSemaphore(), PRESENT_BINDINGS, 32} {
vCursor = new Cursor();
vCursor->setEmuWindow(&window);
CompileShaders();
BuildLayouts();
BuildPipelines();
@ -249,7 +251,7 @@ void RendererVulkan::RenderToWindow(PresentWindow& window, const Layout::Framebu
clear_color.float32[1] = Settings::values.bg_green.GetValue();
clear_color.float32[2] = Settings::values.bg_blue.GetValue();
clear_color.float32[3] = 1.0f;
vCursor->update();
DrawScreens(frame, layout, flipped);
scheduler.Flush(frame->render_ready);
@ -783,11 +785,17 @@ void RendererVulkan::DrawSingleScreen(u32 screen_id, float x, float y, float w,
const u32 scale_factor = GetResolutionScaleFactor();
draw_info.i_resolution =
Common::MakeVec(static_cast<f32>(screen_info.texture.width * scale_factor),
static_cast<f32>(screen_info.texture.height * scale_factor),
1.0f / static_cast<f32>(screen_info.texture.width * scale_factor),
1.0f / static_cast<f32>(screen_info.texture.height * scale_factor));
draw_info.o_resolution = Common::MakeVec(h, w, 1.0f / h, 1.0f / w);
Common::MakeVec(static_cast<f32>(screen_info.texture.height * scale_factor),
static_cast<f32>(screen_info.texture.width * scale_factor),
1.0f / static_cast<f32>(screen_info.texture.height * scale_factor),
1.0f / static_cast<f32>(screen_info.texture.width * scale_factor));
draw_info.o_resolution = Common::MakeVec(w, h, 1.0f / w, 1.0f / h);
if (currScreenDraw == 1){
draw_info.cursor_enable = 1;
} else {
draw_info.cursor_enable = 0;
}
draw_info.cursor_pos = Common::MakeVec(vCursor->cursorPos[0]/320.0f, vCursor->cursorPos[1]/240.0f);
draw_info.screen_id_l = screen_id;
scheduler.Record([this, offset = offset, info = draw_info](vk::CommandBuffer cmdbuf) {
@ -855,11 +863,17 @@ void RendererVulkan::DrawSingleScreenStereo(u32 screen_id_l, u32 screen_id_r, fl
const u32 scale_factor = GetResolutionScaleFactor();
draw_info.i_resolution =
Common::MakeVec(static_cast<f32>(screen_info_l.texture.width * scale_factor),
static_cast<f32>(screen_info_l.texture.height * scale_factor),
1.0f / static_cast<f32>(screen_info_l.texture.width * scale_factor),
1.0f / static_cast<f32>(screen_info_l.texture.height * scale_factor));
draw_info.o_resolution = Common::MakeVec(h, w, 1.0f / h, 1.0f / w);
Common::MakeVec(static_cast<f32>(screen_info_l.texture.height * scale_factor),
static_cast<f32>(screen_info_l.texture.width * scale_factor),
1.0f / static_cast<f32>(screen_info_l.texture.height * scale_factor),
1.0f / static_cast<f32>(screen_info_l.texture.width * scale_factor));
draw_info.o_resolution = Common::MakeVec(w, h, 1.0f / w, 1.0f / h);
if (currScreenDraw == 1){
draw_info.cursor_enable = 1;
} else {
draw_info.cursor_enable = 0;
}
draw_info.cursor_pos = Common::MakeVec(vCursor->cursorPos[0]/320.0f, vCursor->cursorPos[1]/240.0f);
draw_info.screen_id_l = screen_id_l;
draw_info.screen_id_r = screen_id_r;
@ -886,6 +900,7 @@ void RendererVulkan::DrawTopScreen(const Layout::FramebufferLayout& layout,
if (!layout.top_screen_enabled) {
return;
}
currScreenDraw = 0;
int leftside, rightside;
leftside = Settings::values.swap_eyes_3d.GetValue() ? 1 : 0;
rightside = Settings::values.swap_eyes_3d.GetValue() ? 0 : 1;
@ -944,7 +959,7 @@ void RendererVulkan::DrawBottomScreen(const Layout::FramebufferLayout& layout,
if (!layout.bottom_screen_enabled) {
return;
}
currScreenDraw = 1;
const float bottom_screen_left = static_cast<float>(bottom_screen.left);
const float bottom_screen_top = static_cast<float>(bottom_screen.top);
const float bottom_screen_width = static_cast<float>(bottom_screen.GetWidth());
@ -1007,7 +1022,6 @@ void RendererVulkan::DrawScreens(Frame* frame, const Layout::FramebufferLayout&
if (settings.shader_update_requested.exchange(false)) {
ReloadPipeline(layout.render_3d_mode);
}
PrepareDraw(frame, layout);
const auto& top_screen = layout.top_screen;

View file

@ -6,6 +6,7 @@
#include "common/common_types.h"
#include "common/math_util.h"
#include "core/frontend/cursor.h"
#include "video_core/renderer_base.h"
#ifdef HAVE_LIBRETRO
#include "citra_libretro/libretro_vk.h"
@ -58,12 +59,14 @@ struct PresentUniformData {
std::array<f32, 4 * 4> modelview;
Common::Vec4f i_resolution;
Common::Vec4f o_resolution;
Common::Vec2f cursor_pos;
int cursor_enable = 0;
int screen_id_l = 0;
int screen_id_r = 0;
int layer = 0;
int reverse_interlaced = 0;
};
static_assert(sizeof(PresentUniformData) == 112,
static_assert(sizeof(PresentUniformData) == 124,
"PresentUniformData does not structure in shader!");
class RendererVulkan : public VideoCore::RendererBase {
@ -151,6 +154,7 @@ private:
vk::ShaderModule cursor_fragment_shader{};
vk::Pipeline cursor_pipeline{};
vk::UniquePipelineLayout cursor_pipeline_layout{};
int currScreenDraw; // 0 is Top, 1 is Bottom
};
} // namespace Vulkan