This commit is contained in:
Jonian Guveli 2024-12-28 17:45:01 +00:00 committed by GitHub
commit d77bee0504
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 188 additions and 13 deletions

View file

@ -579,11 +579,13 @@ void RendererGL::display() {
OpenGL::draw(OpenGL::TriangleStrip, 4);
}
#ifndef __LIBRETRO__
if constexpr (!Helpers::isHydraCore()) {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
screenFramebuffer.bind(OpenGL::ReadFramebuffer);
glBlitFramebuffer(0, 0, 400, 480, 0, 0, outputWindowWidth, outputWindowHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);
}
#endif
}
void RendererGL::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control) {

View file

@ -1,6 +1,7 @@
#include <stdexcept>
#include <cstdio>
#include <regex>
#include <chrono>
#include <libretro.h>
@ -17,8 +18,32 @@ static retro_input_state_t inputStateCallback;
static retro_hw_render_callback hwRender;
static std::filesystem::path savePath;
static bool screenTouched;
static std::string touchScreenMode;
static bool renderTouchScreen;
static auto cursorTimeout = 0;
static auto cursorMovedAt = std::chrono::steady_clock::now();
static bool cursorVisible = false;
static bool screenTouched;
static int lastMouseX;
static int lastMouseY;
static int touchX = 0;
static int touchY = 0;
class CursorRenderer {
OpenGL::Program shader;
OpenGL::VertexArray vao;
OpenGL::VertexBuffer vbo;
public:
void init();
void deinit();
void draw(float x, float y, float size = 5);
};
std::unique_ptr<CursorRenderer> cursorRenderer;
std::unique_ptr<Emulator> emulator;
RendererGL* renderer;
@ -46,9 +71,11 @@ static void videoResetContext() {
#endif
emulator->initGraphicsContext(nullptr);
cursorRenderer->init();
}
static void videoDestroyContext() {
cursorRenderer->deinit();
emulator->deinitGraphicsContext();
}
@ -123,8 +150,11 @@ static void inputInit() {
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L"},
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "X"},
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Y"},
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "Screen Touch"},
{0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Circle Pad X"},
{0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Circle Pad Y"},
{0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Pointer X"},
{0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Pointer Y"},
{0},
};
@ -183,6 +213,9 @@ static void configInit() {
{"panda3ds_write_protect_virtual_sd", "Write protect virtual SD card; disabled|enabled"},
{"panda3ds_battery_level", "Battery percentage; 5|10|20|30|50|70|90|100"},
{"panda3ds_use_charger", "Charger plugged; enabled|disabled"},
{"panda3ds_touchscreen_mode", "Touchscreen touch mode; Auto|Pointer|Joystick|None"},
{"panda3ds_render_touchscreen", "Render touchscreen pointer; disabled|enabled"},
{"panda3ds_hide_cursor_timeout", "Hide touchScreen pointer timeout; 3 Seconds|5 Seconds|10 Seconds|15 Seconds|20 Seconds|Never Hide"},
{nullptr, nullptr},
};
@ -215,8 +248,13 @@ static void configUpdate() {
config.lightShadergenThreshold = fetchVariableRange("panda3ds_ubershader_lighting_override_threshold", 1, 8);
config.discordRpcEnabled = false;
touchScreenMode = fetchVariable("panda3ds_touchscreen_mode", "Auto");
renderTouchScreen = fetchVariableBool("panda3ds_render_touchscreen", false);
cursorTimeout = fetchVariableInt("panda3ds_hide_cursor_timeout", 3);
// Handle any settings that might need the emulator core to be notified when they're changed, and save the config.
emulator->setAudioEnabled(config.audioEnabled);
config.save();
}
@ -229,6 +267,95 @@ static void configCheckVariables() {
}
}
static void updateCursorVisibility() {
if (renderTouchScreen && cursorTimeout) {
if (cursorVisible) {
auto current = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(current - cursorMovedAt).count();
if (elapsed >= cursorTimeout) {
cursorVisible = false;
}
}
} else {
cursorVisible = true;
}
}
void CursorRenderer::init() {
#ifdef USING_GLES
static const std::string version = R"(
#version 300 es
precision mediump float;
)";
#else
static const std::string version = R"(
#version 410 core
)";
#endif
std::string vertex = version + R"(
in vec2 position;
void main() { gl_Position = vec4(position, 0.0, 1.0); }
)";
std::string fragment = version + R"(
out vec4 color;
void main() { color = vec4(1.0, 1.0, 1.0, 1.0); }
)";
OpenGL::Shader vertCursor(vertex.c_str(), OpenGL::Vertex);
OpenGL::Shader fragCursor(fragment.c_str(), OpenGL::Fragment);
shader.create({vertCursor, fragCursor});
vbo.createFixedSize(12 * 12 * sizeof(GLfloat));
vbo.bind();
vao.create();
vao.bind();
vao.setAttributeFloat<float>(0, 2, 4 * sizeof(GLfloat), nullptr);
vao.enableAttribute(0);
vertCursor.free();
fragCursor.free();
}
void CursorRenderer::deinit() {
shader.free();
vao.free();
vbo.free();
}
void CursorRenderer::draw(float x, float y, float size) {
shader.use();
vao.bind();
vbo.bind();
glEnable(GL_BLEND);
glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR);
float centerX = (x / 320) * 2.0f - 1.0f;
float centerY = 1.0f - (y / 240) * 2.0f;
GLfloat sizeX = size / 320;
GLfloat sizeY = size / 240;
GLfloat cursor[] = {
centerX - sizeX, centerY - sizeY, -0.5f, -0.5f,
centerX + sizeX, centerY - sizeY, 0.5f, -0.5f,
centerX + sizeX, centerY + sizeY, 0.5f, 0.5f,
centerX - sizeX, centerY + sizeY, -0.5f, 0.5f
};
vbo.bufferVertsSub(cursor, 12 * sizeof(GLfloat));
OpenGL::setViewport(40, 0, 320, 240);
OpenGL::draw(OpenGL::TriangleFan, 0, 4);
glDisable(GL_BLEND);
}
void retro_get_system_info(retro_system_info* info) {
info->need_fullpath = true;
info->valid_extensions = "3ds|3dsx|elf|axf|cci|cxi|app";
@ -285,10 +412,12 @@ void retro_init() {
}
emulator = std::make_unique<Emulator>();
cursorRenderer = std::make_unique<CursorRenderer>();
}
void retro_deinit() {
emulator = nullptr;
cursorRenderer = nullptr;
}
bool retro_load_game(const retro_game_info* game) {
@ -321,6 +450,7 @@ void retro_reset() {
void retro_run() {
configCheckVariables();
updateCursorVisibility();
renderer->setFBO(hwRender.get_current_framebuffer());
renderer->resetStateManager();
@ -351,26 +481,62 @@ void retro_run() {
bool touchScreen = false;
const int posX = inputStateCallback(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X);
const int posY = inputStateCallback(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y);
const int newX = static_cast<int>((posX + 0x7fff) / (float)(0x7fff * 2) * emulator->width);
const int newY = static_cast<int>((posY + 0x7fff) / (float)(0x7fff * 2) * emulator->height);
int pointerX = touchX;
int pointerY = touchY;
const int offsetX = 40;
const int offsetY = emulator->height / 2;
const bool inScreenX = newX >= offsetX && newX <= emulator->width - offsetX;
const bool inScreenY = newY >= offsetY && newY <= emulator->height;
if (touchScreenMode == "Pointer" || touchScreenMode == "Auto") {
const int posX = inputStateCallback(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X);
const int posY = inputStateCallback(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y);
if (inScreenX && inScreenY) {
touchScreen |= inputStateCallback(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_LEFT);
touchScreen |= inputStateCallback(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_PRESSED);
const int newX = static_cast<int>((posX + 0x7fff) / (float)(0x7fff * 2) * emulator->width);
const int newY = static_cast<int>((posY + 0x7fff) / (float)(0x7fff * 2) * emulator->height);
const bool inScreenX = newX >= offsetX && newX <= emulator->width - offsetX;
const bool inScreenY = newY >= offsetY && newY <= emulator->height;
if (inScreenX && inScreenY) {
touchScreen |= inputStateCallback(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_LEFT);
touchScreen |= inputStateCallback(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_PRESSED);
}
if ((posX != 0 || posY != 0) && (lastMouseX != newX || lastMouseY != newY)) {
lastMouseX = newX;
lastMouseY = newY;
pointerX = newX - offsetX;
pointerY = newY - offsetY;
}
}
if (touchScreenMode == "Joystick" || touchScreenMode == "Auto") {
const float speedX = (emulator->width / 60.0);
const float speedY = (emulator->height / 2 / 60.0);
const float moveX = getAxisState(RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X);
const float moveY = getAxisState(RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y);
touchScreen |= getButtonState(RETRO_DEVICE_ID_JOYPAD_R3);
if (moveX != 0 || moveY != 0) {
pointerX += static_cast<int>((moveX / 32767) * speedX);
pointerY += static_cast<int>((moveY / 32767) * speedY);
}
}
if (cursorTimeout && (pointerX != touchX || pointerY != touchY)) {
cursorVisible = true;
cursorMovedAt = std::chrono::steady_clock::now();
}
touchX = std::clamp(pointerX, 0, (int)(emulator->width - (offsetX * 2)));
touchY = std::clamp(pointerY, 0, (int)(emulator->height - offsetY));
if (touchScreen) {
u16 x = static_cast<u16>(newX - offsetX);
u16 y = static_cast<u16>(newY - offsetY);
u16 x = static_cast<u16>(touchX);
u16 y = static_cast<u16>(touchY);
hid.setTouchScreenPress(x, y);
screenTouched = true;
@ -382,6 +548,13 @@ void retro_run() {
hid.updateInputs(emulator->getTicks());
emulator->runFrame();
if (renderTouchScreen && cursorVisible) {
cursorRenderer->draw(touchX, touchY);
}
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, 400, 480, 0, 0, 400, 480, GL_COLOR_BUFFER_BIT, GL_LINEAR);
videoCallback(RETRO_HW_FRAME_BUFFER_VALID, emulator->width, emulator->height, 0);
}