Skip to content

Commit

Permalink
Qt: Initial shader editor support
Browse files Browse the repository at this point in the history
  • Loading branch information
wheremyfoodat committed Jul 14, 2024
1 parent e608436 commit d874778
Show file tree
Hide file tree
Showing 9 changed files with 130 additions and 24 deletions.
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -457,11 +457,11 @@ if(NOT BUILD_HYDRA_CORE AND NOT BUILD_LIBRETRO_CORE)

set(FRONTEND_SOURCE_FILES src/panda_qt/main.cpp src/panda_qt/screen.cpp src/panda_qt/main_window.cpp src/panda_qt/about_window.cpp
src/panda_qt/config_window.cpp src/panda_qt/zep.cpp src/panda_qt/text_editor.cpp src/panda_qt/cheats_window.cpp src/panda_qt/mappings.cpp
src/panda_qt/patch_window.cpp src/panda_qt/elided_label.cpp
src/panda_qt/patch_window.cpp src/panda_qt/elided_label.cpp src/panda_qt/shader_editor.cpp
)
set(FRONTEND_HEADER_FILES include/panda_qt/screen.hpp include/panda_qt/main_window.hpp include/panda_qt/about_window.hpp
include/panda_qt/config_window.hpp include/panda_qt/text_editor.hpp include/panda_qt/cheats_window.hpp
include/panda_qt/patch_window.hpp include/panda_qt/elided_label.hpp
include/panda_qt/patch_window.hpp include/panda_qt/elided_label.hpp include/panda_qt/shader_editor.hpp
)

source_group("Source Files\\Qt" FILES ${FRONTEND_SOURCE_FILES})
Expand Down
7 changes: 4 additions & 3 deletions include/panda_qt/main_window.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "panda_qt/config_window.hpp"
#include "panda_qt/patch_window.hpp"
#include "panda_qt/screen.hpp"
#include "panda_qt/shader_editor.hpp"
#include "panda_qt/text_editor.hpp"
#include "services/hid.hpp"

Expand Down Expand Up @@ -48,6 +49,7 @@ class MainWindow : public QMainWindow {
EditCheat,
PressTouchscreen,
ReleaseTouchscreen,
ReloadUbershader,
};

// Tagged union representing our message queue messages
Expand Down Expand Up @@ -99,6 +101,7 @@ class MainWindow : public QMainWindow {
CheatsWindow* cheatsEditor;
TextEditorWindow* luaEditor;
PatchWindow* patchWindow;
ShaderEditorWindow* shaderEditor;

// We use SDL's game controller API since it's the sanest API that supports as many controllers as possible
SDL_GameController* gameController = nullptr;
Expand All @@ -110,9 +113,6 @@ class MainWindow : public QMainWindow {
void selectROM();
void dumpDspFirmware();
void dumpRomFS();
void openLuaEditor();
void openCheatsEditor();
void openPatchWindow();
void showAboutMenu();
void initControllers();
void pollControllers();
Expand All @@ -139,5 +139,6 @@ class MainWindow : public QMainWindow {
void mouseReleaseEvent(QMouseEvent* event) override;

void loadLuaScript(const std::string& code);
void reloadShader(const std::string& shader);
void editCheat(u32 handle, const std::vector<uint8_t>& cheat, const std::function<void(u32)>& callback);
};
28 changes: 28 additions & 0 deletions include/panda_qt/shader_editor.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#pragma once

#include <QApplication>
#include <QDialog>
#include <QWidget>
#include <string>

#include "zep.h"
#include "zep/mode_repl.h"
#include "zep/regress.h"

class ShaderEditorWindow : public QDialog {
Q_OBJECT

private:
Zep::ZepWidget_Qt zepWidget;
Zep::IZepReplProvider replProvider;
static constexpr float fontSize = 14.0f;

// Whether this backend supports shader editor
bool shaderEditorSupported = true;

public:
ShaderEditorWindow(QWidget* parent, const std::string& filename, const std::string& initialText);
void setText(const std::string& text) { zepWidget.GetEditor().GetMRUBuffer()->SetText(text); }

void setEnable(bool enable);
};
8 changes: 8 additions & 0 deletions include/renderer.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once
#include <array>
#include <span>
#include <string>
#include <optional>

#include "PICA/pica_vertex.hpp"
Expand Down Expand Up @@ -66,6 +67,13 @@ class Renderer {
// This function does things like write back or cache necessary state before we delete our context
virtual void deinitGraphicsContext() = 0;

// Functions for hooking up the renderer core to the frontend's shader editor for editing ubershaders in real time
// SupportsShaderReload: Indicates whether the backend offers ubershader reload support or not
// GetUbershader/SetUbershader: Gets or sets the renderer's current ubershader
virtual bool supportsShaderReload() { return false; }
virtual std::string getUbershader() { return ""; }
virtual void setUbershader(const std::string& shader) {}

// Functions for initializing the graphics context for the Qt frontend, where we don't have the convenience of SDL_Window
#ifdef PANDA3DS_FRONTEND_QT
virtual void initGraphicsContext(GL::Context* context) { Helpers::panic("Tried to initialize incompatible renderer with GL context"); }
Expand Down
6 changes: 5 additions & 1 deletion include/renderer_gl/renderer_gl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,11 @@ class RendererGL final : public Renderer {
void textureCopy(u32 inputAddr, u32 outputAddr, u32 totalBytes, u32 inputSize, u32 outputSize, u32 flags) override;
void drawVertices(PICA::PrimType primType, std::span<const PICA::Vertex> vertices) override; // Draw the given vertices
void deinitGraphicsContext() override;


virtual bool supportsShaderReload() override { return true; }
virtual std::string getUbershader() override;
virtual void setUbershader(const std::string& shader) override;

std::optional<ColourBuffer> getColourBuffer(u32 addr, PICA::ColorFmt format, u32 width, u32 height, bool createIfnotFound = true);

// Note: The caller is responsible for deleting the currently bound FBO before calling this
Expand Down
5 changes: 4 additions & 1 deletion src/core/renderer_gl/renderer_gl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -812,4 +812,7 @@ void RendererGL::deinitGraphicsContext() {
// All other GL objects should be invalidated automatically and be recreated by the next call to initGraphicsContext
// TODO: Make it so that depth and colour buffers get written back to 3DS memory
printf("RendererGL::DeinitGraphicsContext called\n");
}
}

std::string RendererGL::getUbershader() { return ""; }
void RendererGL::setUbershader(const std::string& shader) {}
20 changes: 10 additions & 10 deletions src/host_shaders/opengl_fragment_shader.frag
Original file line number Diff line number Diff line change
Expand Up @@ -279,26 +279,26 @@ void calcLighting(out vec4 primary_color, out vec4 secondary_color) {
}
}

uint lookup_config = bitfieldExtract(GPUREG_LIGHTi_CONFIG, 4, 4);
uint lookup_config = bitfieldExtract(GPUREG_LIGHTING_CONFIG0, 4, 4);
if (lookup_config == 0u) {
d[D1_LUT] = 0.0;
d[FR_LUT] = 0.0;
d[D1_LUT] = 1.0;
d[FR_LUT] = 1.0;
d[RG_LUT] = d[RB_LUT] = d[RR_LUT];
} else if (lookup_config == 1u) {
d[D0_LUT] = 0.0;
d[D1_LUT] = 0.0;
d[D0_LUT] = 1.0;
d[D1_LUT] = 1.0;
d[RG_LUT] = d[RB_LUT] = d[RR_LUT];
} else if (lookup_config == 2u) {
d[FR_LUT] = 0.0;
d[SP_LUT] = 0.0;
d[FR_LUT] = 1.0;
d[SP_LUT] = 1.0;
d[RG_LUT] = d[RB_LUT] = d[RR_LUT];
} else if (lookup_config == 3u) {
d[SP_LUT] = 0.0;
d[SP_LUT] = 1.0;
d[RG_LUT] = d[RB_LUT] = d[RR_LUT] = 1.0;
} else if (lookup_config == 4u) {
d[FR_LUT] = 0.0;
d[FR_LUT] = 1.0;
} else if (lookup_config == 5u) {
d[D1_LUT] = 0.0;
d[D1_LUT] = 1.0;
} else if (lookup_config == 6u) {
d[RG_LUT] = d[RB_LUT] = d[RR_LUT];
}
Expand Down
22 changes: 15 additions & 7 deletions src/panda_qt/main_window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,14 @@ MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent)
auto luaEditorAction = toolsMenu->addAction(tr("Open Lua Editor"));
auto cheatsEditorAction = toolsMenu->addAction(tr("Open Cheats Editor"));
auto patchWindowAction = toolsMenu->addAction(tr("Open Patch Window"));
auto shaderEditorAction = toolsMenu->addAction(tr("Open Shader Editor"));
auto dumpDspFirmware = toolsMenu->addAction(tr("Dump loaded DSP firmware"));

connect(dumpRomFSAction, &QAction::triggered, this, &MainWindow::dumpRomFS);
connect(luaEditorAction, &QAction::triggered, this, &MainWindow::openLuaEditor);
connect(cheatsEditorAction, &QAction::triggered, this, &MainWindow::openCheatsEditor);
connect(patchWindowAction, &QAction::triggered, this, &MainWindow::openPatchWindow);
connect(luaEditorAction, &QAction::triggered, this, [this]() { luaEditor->show(); });
connect(shaderEditorAction, &QAction::triggered, this, [this]() { shaderEditor->show(); });
connect(cheatsEditorAction, &QAction::triggered, this, [this]() { cheatsEditor->show(); });
connect(patchWindowAction, &QAction::triggered, this, [this]() { patchWindow->show(); });
connect(dumpDspFirmware, &QAction::triggered, this, &MainWindow::dumpDspFirmware);

auto aboutAction = aboutMenu->addAction(tr("About Panda3DS"));
Expand All @@ -75,6 +77,8 @@ MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent)
cheatsEditor = new CheatsWindow(emu, {}, this);
patchWindow = new PatchWindow(this);
luaEditor = new TextEditorWindow(this, "script.lua", "");
shaderEditor = new ShaderEditorWindow(this, "shader.glsl", "");
shaderEditor->setEnable(emu->getRenderer()->supportsShaderReload());

auto args = QCoreApplication::arguments();
if (args.size() > 1) {
Expand Down Expand Up @@ -294,10 +298,6 @@ void MainWindow::showAboutMenu() {
about.exec();
}

void MainWindow::openLuaEditor() { luaEditor->show(); }
void MainWindow::openCheatsEditor() { cheatsEditor->show(); }
void MainWindow::openPatchWindow() { patchWindow->show(); }

void MainWindow::dispatchMessage(const EmulatorMessage& message) {
switch (message.type) {
case MessageType::LoadROM:
Expand Down Expand Up @@ -453,6 +453,14 @@ void MainWindow::loadLuaScript(const std::string& code) {
sendMessage(message);
}

void MainWindow::reloadShader(const std::string& shader) {
EmulatorMessage message{.type = MessageType::ReloadUbershader};

// Make a copy of the code on the heap to send via the message queue
message.string.str = new std::string(shader);
sendMessage(message);
}

void MainWindow::editCheat(u32 handle, const std::vector<uint8_t>& cheat, const std::function<void(u32)>& callback) {
EmulatorMessage message{.type = MessageType::EditCheat};

Expand Down
54 changes: 54 additions & 0 deletions src/panda_qt/shader_editor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#include <QPushButton>
#include <QVBoxLayout>

#include "panda_qt/main_window.hpp"
#include "panda_qt/shader_editor.hpp"

using namespace Zep;

ShaderEditorWindow::ShaderEditorWindow(QWidget* parent, const std::string& filename, const std::string& initialText)
: QDialog(parent), zepWidget(this, qApp->applicationDirPath().toStdString(), fontSize) {
resize(600, 600);

// Register our extensions
ZepRegressExCommand::Register(zepWidget.GetEditor());
ZepReplExCommand::Register(zepWidget.GetEditor(), &replProvider);

// Default to standard mode instead of vim mode, initialize text box
zepWidget.GetEditor().InitWithText(filename, initialText);
zepWidget.GetEditor().SetGlobalMode(Zep::ZepMode_Standard::StaticName());

// Layout for widgets
QVBoxLayout* mainLayout = new QVBoxLayout();
setLayout(mainLayout);

QPushButton* button = new QPushButton(tr("Reload shader"), this);
button->setFixedSize(100, 20);

// When the Load Script button is pressed, send the current text to the MainWindow, which will upload it to the emulator's lua object
connect(button, &QPushButton::pressed, this, [this]() {
if (parentWidget()) {
auto buffer = zepWidget.GetEditor().GetMRUBuffer();
const std::string text = buffer->GetBufferText(buffer->Begin(), buffer->End());

static_cast<MainWindow*>(parentWidget())->reloadShader(text);
} else {
// This should be unreachable, only here for safety purposes
printf("Text editor does not have any parent widget, click doesn't work :(\n");
}
});

mainLayout->addWidget(button);
mainLayout->addWidget(&zepWidget);
}

void ShaderEditorWindow::setEnable(bool enable) {
shaderEditorSupported = enable;

if (enable) {
setDisabled(false);
} else {
setDisabled(true);
setText("Shader editor window is not available for this renderer backend");
}
}

0 comments on commit d874778

Please sign in to comment.