提交 721cb3de 编写于 作者: S Shaolin 提交者: jp9000

UI: Add Multiview projector

Jim note:

- Refactored code significantly
- Added a context menu option to exclude specific scenes from projectors
- Made it so multiview projectors update when scenes are
  added/removed/renamed
- Increased text quality
- Removed the color sources and replaced them with simple solid
  rectangles
- Increased the border size of "program" and "preview" scenes in the
  lower scene list

Closes jp9000/obs-studio#1068
上级 78411de7
......@@ -78,6 +78,9 @@ Defaults="Defaults"
HideMixer="Hide in Mixer"
TransitionOverride="Transition Override"
None="None"
StudioMode.Preview="Preview"
StudioMode.Program="Program"
ShowInMultiview="Show in Multiview"
# warning if program already open
AlreadyRunning.Title="OBS is already running"
......
......@@ -139,6 +139,7 @@ OBSBasic::OBSBasic(QWidget *parent)
projectorArray.resize(10, "");
previewProjectorArray.resize(10, 0);
multiviewProjectorArray.resize(10, 0);
studioProgramProjectorArray.resize(10, 0);
setAcceptDrops(true);
......@@ -320,7 +321,8 @@ static obs_data_t *GenerateSaveData(obs_data_array_t *sceneOrder,
OBSScene &scene, OBSSource &curProgramScene,
obs_data_array_t *savedProjectorList,
obs_data_array_t *savedPreviewProjectorList,
obs_data_array_t *savedStudioProgramProjectorList)
obs_data_array_t *savedStudioProgramProjectorList,
obs_data_array_t *savedMultiviewProjectorList)
{
obs_data_t *saveData = obs_data_create();
......@@ -366,6 +368,8 @@ static obs_data_t *GenerateSaveData(obs_data_array_t *sceneOrder,
savedPreviewProjectorList);
obs_data_set_array(saveData, "saved_studio_preview_projectors",
savedStudioProgramProjectorList);
obs_data_set_array(saveData, "saved_multiview_projectors",
savedMultiviewProjectorList);
obs_data_array_release(sourcesArray);
obs_data_set_string(saveData, "current_transition",
......@@ -468,6 +472,21 @@ obs_data_array_t *OBSBasic::SaveStudioProgramProjectors()
return saveProjector;
}
obs_data_array_t *OBSBasic::SaveMultiviewProjectors()
{
obs_data_array_t *saveProjector = obs_data_array_create();
for (size_t i = 0; i < multiviewProjectorArray.size(); i++) {
obs_data_t *data = obs_data_create();
obs_data_set_int(data, "saved_multiview_projectors",
multiviewProjectorArray.at(i));
obs_data_array_push_back(saveProjector, data);
obs_data_release(data);
}
return saveProjector;
}
void OBSBasic::Save(const char *file)
{
OBSScene scene = GetCurrentScene();
......@@ -482,11 +501,14 @@ void OBSBasic::Save(const char *file)
obs_data_array_t *savedPreviewProjectorList = SavePreviewProjectors();
obs_data_array_t *savedStudioProgramProjectorList =
SaveStudioProgramProjectors();
obs_data_array_t *savedMultiviewProjectorList =
SaveMultiviewProjectors();
obs_data_t *saveData = GenerateSaveData(sceneOrder, quickTrData,
ui->transitionDuration->value(), transitions,
scene, curProgramScene, savedProjectorList,
savedPreviewProjectorList,
savedStudioProgramProjectorList);
savedStudioProgramProjectorList,
savedMultiviewProjectorList);
obs_data_set_bool(saveData, "preview_locked", ui->preview->Locked());
obs_data_set_bool(saveData, "scaling_enabled",
......@@ -515,6 +537,7 @@ void OBSBasic::Save(const char *file)
obs_data_array_release(savedProjectorList);
obs_data_array_release(savedPreviewProjectorList);
obs_data_array_release(savedStudioProgramProjectorList);
obs_data_array_release(savedMultiviewProjectorList);
}
static void LoadAudioDevice(const char *name, int channel, obs_data_t *parent)
......@@ -653,6 +676,19 @@ void OBSBasic::LoadSavedStudioProgramProjectors(obs_data_array_t *array)
}
}
void OBSBasic::LoadSavedMultiviewProjectors(obs_data_array_t *array)
{
size_t num = obs_data_array_count(array);
for (size_t i = 0; i < num; i++) {
obs_data_t *data = obs_data_array_item(array, i);
multiviewProjectorArray.at(i) = obs_data_get_int(data,
"saved_multiview_projectors");
obs_data_release(data);
}
}
static void LogFilter(obs_source_t*, obs_source_t *filter, void *v_val)
{
const char *name = obs_source_get_name(filter);
......@@ -784,6 +820,8 @@ void OBSBasic::Load(const char *file)
ui->transitionDuration->setValue(newDuration);
SetTransition(curTransition);
/* ------------------- */
obs_data_array_t *savedProjectors = obs_data_get_array(data,
"saved_projectors");
......@@ -792,6 +830,8 @@ void OBSBasic::Load(const char *file)
obs_data_array_release(savedProjectors);
/* ------------------- */
obs_data_array_t *savedPreviewProjectors = obs_data_get_array(data,
"saved_preview_projectors");
......@@ -800,6 +840,8 @@ void OBSBasic::Load(const char *file)
obs_data_array_release(savedPreviewProjectors);
/* ------------------- */
obs_data_array_t *savedStudioProgramProjectors = obs_data_get_array(data,
"saved_studio_preview_projectors");
......@@ -808,6 +850,16 @@ void OBSBasic::Load(const char *file)
obs_data_array_release(savedStudioProgramProjectors);
/* ------------------- */
obs_data_array_t *savedMultiviewProjectors = obs_data_get_array(data,
"saved_multiview_projectors");
if (savedMultiviewProjectors)
LoadSavedMultiviewProjectors(savedMultiviewProjectors);
obs_data_array_release(savedMultiviewProjectors);
retryScene:
curScene = obs_get_source_by_name(sceneName);
......@@ -1927,6 +1979,11 @@ void OBSBasic::SaveProjectDeferred()
Save(savePath);
}
OBSSource OBSBasic::GetProgramSource()
{
return OBSGetStrongRef(programScene);
}
OBSScene OBSBasic::GetCurrentScene()
{
QListWidgetItem *item = ui->scenes->currentItem();
......@@ -2088,6 +2145,8 @@ void OBSBasic::AddScene(OBSSource source)
obs_source_t *source = obs_scene_get_source(scene);
blog(LOG_INFO, "User added scene '%s'",
obs_source_get_name(source));
OBSProjector::UpdateMultiviewProjectors();
}
if (api)
......@@ -2122,6 +2181,8 @@ void OBSBasic::RemoveScene(OBSSource source)
if (!disableSaving) {
blog(LOG_INFO, "User Removed scene '%s'",
obs_source_get_name(source));
OBSProjector::UpdateMultiviewProjectors();
}
if (api)
......@@ -2203,7 +2264,8 @@ static void RenameListValues(QListWidget *listWidget, const QString &newName,
items[i]->setText(newName);
}
void OBSBasic::RenameSources(QString newName, QString prevName)
void OBSBasic::RenameSources(OBSSource source, QString newName,
QString prevName)
{
RenameListValues(ui->scenes, newName, prevName);
......@@ -2221,6 +2283,10 @@ void OBSBasic::RenameSources(QString newName, QString prevName)
}
SaveProject();
obs_scene_t *scene = obs_scene_from_source(source);
if (scene)
OBSProjector::UpdateMultiviewProjectors();
}
void OBSBasic::SelectSceneItem(OBSScene scene, OBSSceneItem item, bool select)
......@@ -2816,11 +2882,13 @@ void OBSBasic::SourceDeactivated(void *data, calldata_t *params)
void OBSBasic::SourceRenamed(void *data, calldata_t *params)
{
obs_source_t *source = (obs_source_t*)calldata_ptr(params, "source");
const char *newName = calldata_string(params, "new_name");
const char *prevName = calldata_string(params, "prev_name");
QMetaObject::invokeMethod(static_cast<OBSBasic*>(data),
"RenameSources",
Q_ARG(OBSSource, source),
Q_ARG(QString, QT_UTF8(newName)),
Q_ARG(QString, QT_UTF8(prevName)));
......@@ -3457,6 +3525,7 @@ void OBSBasic::on_scenes_customContextMenuRequested(const QPoint &pos)
popup.addMenu(&order);
popup.addSeparator();
sceneProjectorMenu = new QMenu(QTStr("SceneProjector"));
AddProjectorMenuMonitors(sceneProjectorMenu, this,
SLOT(OpenSceneProjector()));
......@@ -3475,6 +3544,36 @@ void OBSBasic::on_scenes_customContextMenuRequested(const QPoint &pos)
QMenu *transitionMenu = CreatePerSceneTransitionMenu();
popup.addMenu(transitionMenu);
/* ---------------------- */
if (IsPreviewProgramMode()) {
QAction *multiviewAction = popup.addAction(
QTStr("ShowInMultiview"));
OBSSource source = GetCurrentSceneSource();
OBSData data = obs_source_get_private_settings(source);
obs_data_release(data);
obs_data_set_default_bool(data, "show_in_multiview",
true);
bool show = obs_data_get_bool(data, "show_in_multiview");
multiviewAction->setCheckable(true);
multiviewAction->setChecked(show);
auto showInMultiview = [this] (OBSData data)
{
bool show = obs_data_get_bool(data,
"show_in_multiview");
obs_data_set_bool(data, "show_in_multiview",
!show);
OBSProjector::UpdateMultiviewProjectors();
};
connect(multiviewAction, &QAction::triggered,
std::bind(showInMultiview, data));
}
}
popup.exec(QCursor::pos());
......@@ -3719,6 +3818,7 @@ void OBSBasic::CreateSourcePopupMenu(QListWidgetItem *item, bool preview)
QMenu popup(this);
QPointer<QMenu> previewProjector;
QPointer<QMenu> sourceProjector;
QPointer<QMenu> multiviewProjectorMenu;
if (preview) {
QAction *action = popup.addAction(
......@@ -3733,6 +3833,20 @@ void OBSBasic::CreateSourcePopupMenu(QListWidgetItem *item, bool preview)
popup.addAction(ui->actionLockPreview);
popup.addMenu(ui->scalingMenu);
if (IsPreviewProgramMode()) {
multiviewProjectorMenu = new QMenu(
"Multiview Projector");
AddProjectorMenuMonitors(multiviewProjectorMenu, this,
SLOT(OpenMultiviewProjector()));
popup.addMenu(multiviewProjectorMenu);
QAction *multiviewWindow = popup.addAction(
"Multiview Windowed",
this, SLOT(OpenMultiviewWindow()));
popup.addAction(multiviewWindow);
}
previewProjector = new QMenu(QTStr("PreviewProjector"));
AddProjectorMenuMonitors(previewProjector, this,
SLOT(OpenPreviewProjector()));
......@@ -5417,17 +5531,12 @@ void OBSBasic::NudgeLeft() {Nudge(1, MoveDir::Left);}
void OBSBasic::NudgeRight() {Nudge(1, MoveDir::Right);}
void OBSBasic::OpenProjector(obs_source_t *source, int monitor, bool window,
QString title, bool studioProgram)
QString title, ProjectorType type)
{
/* seriously? 10 monitors? */
if (monitor > 9 || monitor > QGuiApplication::screens().size() - 1)
return;
bool isPreview = false;
if (source == nullptr)
isPreview = true;
if (!window) {
delete projectors[monitor];
projectors[monitor].clear();
......@@ -5438,20 +5547,22 @@ void OBSBasic::OpenProjector(obs_source_t *source, int monitor, bool window,
const char *name = obs_source_get_name(source);
if (!window) {
if (studioProgram) {
if (type == ProjectorType::StudioProgram) {
studioProgramProjectorArray.at((size_t)monitor) = 1;
} else if (isPreview) {
} else if (type == ProjectorType::Preview) {
previewProjectorArray.at((size_t)monitor) = 1;
} else if (type == ProjectorType::Multiview) {
multiviewProjectorArray.at((size_t)monitor) = 1;
} else {
projectorArray.at((size_t)monitor) = name;
}
}
if (!window) {
projector->Init(monitor, false, nullptr, studioProgram);
projector->Init(monitor, false, nullptr, type);
projectors[monitor] = projector;
} else {
projector->Init(monitor, true, title, studioProgram);
projector->Init(monitor, true, title, type);
for (auto &projPtr : windowProjectors) {
if (!projPtr) {
......@@ -5468,13 +5579,14 @@ void OBSBasic::OpenProjector(obs_source_t *source, int monitor, bool window,
void OBSBasic::OpenStudioProgramProjector()
{
int monitor = sender()->property("monitor").toInt();
OpenProjector(nullptr, monitor, false, nullptr, true);
OpenProjector(nullptr, monitor, false, nullptr,
ProjectorType::StudioProgram);
}
void OBSBasic::OpenPreviewProjector()
{
int monitor = sender()->property("monitor").toInt();
OpenProjector(nullptr, monitor, false);
OpenProjector(nullptr, monitor, false, nullptr, ProjectorType::Preview);
}
void OBSBasic::OpenSourceProjector()
......@@ -5487,6 +5599,13 @@ void OBSBasic::OpenSourceProjector()
OpenProjector(obs_sceneitem_get_source(item), monitor, false);
}
void OBSBasic::OpenMultiviewProjector()
{
int monitor = sender()->property("monitor").toInt();
OpenProjector(nullptr, monitor, false, nullptr,
ProjectorType::Multiview);
}
void OBSBasic::OpenSceneProjector()
{
int monitor = sender()->property("monitor").toInt();
......@@ -5501,14 +5620,15 @@ void OBSBasic::OpenStudioProgramWindow()
{
int monitor = sender()->property("monitor").toInt();
QString title = QTStr("StudioProgramWindow");
OpenProjector(nullptr, monitor, true, title, true);
OpenProjector(nullptr, monitor, true, title,
ProjectorType::StudioProgram);
}
void OBSBasic::OpenPreviewWindow()
{
int monitor = sender()->property("monitor").toInt();
QString title = QTStr("PreviewWindow");
OpenProjector(nullptr, monitor, true, title);
OpenProjector(nullptr, monitor, true, nullptr, ProjectorType::Preview);
}
void OBSBasic::OpenSourceWindow()
......@@ -5526,6 +5646,13 @@ void OBSBasic::OpenSourceWindow()
OpenProjector(obs_sceneitem_get_source(item), monitor, true, title);
}
void OBSBasic::OpenMultiviewWindow()
{
int monitor = sender()->property("monitor").toInt();
OpenProjector(nullptr, monitor, true, "Multiview",
ProjectorType::Multiview);
}
void OBSBasic::OpenSceneWindow()
{
int monitor = sender()->property("monitor").toInt();
......@@ -5566,13 +5693,21 @@ void OBSBasic::OpenSavedProjectors()
for (size_t i = 0; i < studioProgramProjectorArray.size(); i++) {
if (studioProgramProjectorArray.at(i) == 1) {
OpenProjector(nullptr, (int)i, false, nullptr,
true);
ProjectorType::StudioProgram);
}
}
for (size_t i = 0; i < previewProjectorArray.size(); i++) {
if (previewProjectorArray.at(i) == 1) {
OpenProjector(nullptr, (int)i, false);
OpenProjector(nullptr, (int)i, false, nullptr,
ProjectorType::Preview);
}
}
for (size_t i = 0; i < multiviewProjectorArray.size(); i++) {
if (multiviewProjectorArray.at(i) == 1) {
OpenProjector(nullptr, (int)i, false, nullptr,
ProjectorType::Multiview);
}
}
}
......@@ -5581,6 +5716,7 @@ void OBSBasic::OpenSavedProjectors()
void OBSBasic::RemoveSavedProjectors(int monitor)
{
studioProgramProjectorArray.at((size_t)monitor) = 0;
multiviewProjectorArray.at((size_t)monitor) = 0;
previewProjectorArray.at((size_t)monitor) = 0;
projectorArray.at((size_t)monitor) = "";
}
......
......@@ -67,6 +67,13 @@ enum class QtDataRole {
OBSSignals,
};
enum class ProjectorType {
Source,
Preview,
StudioProgram,
Multiview
};
struct QuickTransition {
QPushButton *button = nullptr;
OBSSource source;
......@@ -115,6 +122,7 @@ private:
std::vector<std::string> projectorArray;
std::vector<int> studioProgramProjectorArray;
std::vector<int> multiviewProjectorArray;
std::vector<int> previewProjectorArray;
bool loaded = false;
......@@ -241,7 +249,8 @@ private:
void Nudge(int dist, MoveDir dir);
void OpenProjector(obs_source_t *source, int monitor, bool window,
QString title = nullptr, bool studioProgram = false);
QString title = nullptr,
ProjectorType type = ProjectorType::Source);
void GetAudioSourceFilters();
void GetAudioSourceProperties();
......@@ -361,6 +370,10 @@ private:
void LoadSavedStudioProgramProjectors(
obs_data_array_t *savedStudioProgramProjectors);
obs_data_array_t *SaveMultiviewProjectors();
void LoadSavedMultiviewProjectors(
obs_data_array_t *savedMultiviewProjectors);
public slots:
void StartStreaming();
void StopStreaming();
......@@ -404,7 +417,7 @@ private slots:
void RemoveSceneItem(OBSSceneItem item);
void AddScene(OBSSource source);
void RemoveScene(OBSSource source);
void RenameSources(QString newName, QString prevName);
void RenameSources(OBSSource source, QString newName, QString prevName);
void SelectSceneItem(OBSScene scene, OBSSceneItem item, bool select);
......@@ -477,6 +490,7 @@ private:
static void HotkeyTriggered(void *data, obs_hotkey_id id, bool pressed);
public:
OBSSource GetProgramSource();
OBSScene GetCurrentScene();
void SysTrayNotify(const QString &text, QSystemTrayIcon::MessageIcon n);
......@@ -689,11 +703,13 @@ private slots:
void OpenStudioProgramProjector();
void OpenPreviewProjector();
void OpenSourceProjector();
void OpenMultiviewProjector();
void OpenSceneProjector();
void OpenStudioProgramWindow();
void OpenPreviewWindow();
void OpenSourceWindow();
void OpenMultiviewWindow();
void OpenSceneWindow();
public slots:
......
......@@ -7,7 +7,9 @@
#include "display-helpers.hpp"
#include "qt-wrappers.hpp"
#include "platform.hpp"
#include "obs-app.hpp"
static QList<OBSProjector *> multiviewProjectors;
static bool updatingMultiview = false;
OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, bool window)
: OBSQTDisplay (widget,
......@@ -30,7 +32,10 @@ OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, bool window)
auto addDrawCallback = [this] ()
{
obs_display_add_draw_callback(GetDisplay(), OBSRender, this);
bool isMultiview = type == ProjectorType::Multiview;
obs_display_add_draw_callback(GetDisplay(),
isMultiview ? OBSRenderMultiview : OBSRender,
this);
obs_display_set_background_color(GetDisplay(), 0x000000);
};
......@@ -50,13 +55,73 @@ OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, bool window)
OBSProjector::~OBSProjector()
{
bool isMultiview = type == ProjectorType::Multiview;
obs_display_remove_draw_callback(GetDisplay(),
isMultiview ? OBSRenderMultiview : OBSRender, this);
if (source)
obs_source_dec_showing(source);
if (isMultiview) {
for (OBSWeakSource &weakSrc : multiviewScenes) {
OBSSource src = OBSGetStrongRef(weakSrc);
if (src)
obs_source_dec_showing(src);
}
obs_enter_graphics();
gs_vertexbuffer_destroy(outerBox);
gs_vertexbuffer_destroy(innerBox);
gs_vertexbuffer_destroy(leftVLine);
gs_vertexbuffer_destroy(rightVLine);
gs_vertexbuffer_destroy(leftLine);
gs_vertexbuffer_destroy(topLine);
gs_vertexbuffer_destroy(rightLine);
obs_leave_graphics();
}
if (type == ProjectorType::Multiview)
multiviewProjectors.removeAll(this);
App()->DecrementSleepInhibition();
}
static OBSSource CreateLabel(const char *name, size_t h)
{
obs_data_t *settings = obs_data_create();
obs_data_t *font = obs_data_create();
std::string text;
text += " ";
text += name;
text += " ";
#if defined(_WIN32)
obs_data_set_string(font, "face", "Arial");
#elif defined(__APPLE__)
obs_data_set_string(font, "face", "Helvetica");
#else
obs_data_set_string(font, "face", "Monospace");
#endif
obs_data_set_int(font, "flags", 0);
obs_data_set_int(font, "size", int(h / 9.81));
obs_data_set_obj(settings, "font", font);
obs_data_set_string(settings, "text", text.c_str());
obs_data_set_bool(settings, "outline", true);
OBSSource txtSource = obs_source_create_private("text_ft2_source", name,
settings);
obs_source_release(txtSource);
obs_data_release(font);
obs_data_release(settings);
return txtSource;
}
void OBSProjector::Init(int monitor, bool window, QString title,
bool studioProgram)
ProjectorType type_)
{
QScreen *screen = QGuiApplication::screens()[monitor];
......@@ -87,12 +152,341 @@ void OBSProjector::Init(int monitor, bool window, QString title,
savedMonitor = monitor;
isWindow = window;
useStudioProgram = studioProgram;
type = type_;
if (type == ProjectorType::Multiview) {
obs_enter_graphics();
gs_render_start(true);
gs_vertex2f(0.001f, 0.001f);
gs_vertex2f(0.001f, 0.997f);
gs_vertex2f(0.997f, 0.997f);
gs_vertex2f(0.997f, 0.001f);
gs_vertex2f(0.001f, 0.001f);
outerBox = gs_render_save();
gs_render_start(true);
gs_vertex2f(0.04f, 0.04f);
gs_vertex2f(0.04f, 0.96f);
gs_vertex2f(0.96f, 0.96f);
gs_vertex2f(0.96f, 0.04f);
gs_vertex2f(0.04f, 0.04f);
innerBox = gs_render_save();
gs_render_start(true);
gs_vertex2f(0.15f, 0.04f);
gs_vertex2f(0.15f, 0.96f);
leftVLine = gs_render_save();
gs_render_start(true);
gs_vertex2f(0.85f, 0.04f);
gs_vertex2f(0.85f, 0.96f);
rightVLine = gs_render_save();
gs_render_start(true);
gs_vertex2f(0.0f, 0.5f);
gs_vertex2f(0.075f, 0.5f);
leftLine = gs_render_save();
gs_render_start(true);
gs_vertex2f(0.5f, 0.0f);
gs_vertex2f(0.5f, 0.09f);
topLine = gs_render_save();
gs_render_start(true);
gs_vertex2f(0.925f, 0.5f);
gs_vertex2f(1.0f, 0.5f);
rightLine = gs_render_save();
obs_leave_graphics();
UpdateMultiview();
multiviewProjectors.push_back(this);
}
ready = true;
}
static inline void renderVB(gs_effect_t *effect, gs_vertbuffer_t *vb,
int cx, int cy)
{
if (!vb)
return;
matrix4 transform;
matrix4_identity(&transform);
transform.x.x = cx;
transform.y.y = cy;
gs_load_vertexbuffer(vb);
gs_matrix_push();
gs_matrix_mul(&transform);
while (gs_effect_loop(effect, "Solid"))
gs_draw(GS_LINESTRIP, 0, 0);
gs_matrix_pop();
}
static inline uint32_t labelOffset(obs_source_t *label, uint32_t cx)
{
uint32_t w = obs_source_get_width(label);
w = uint32_t(float(w) * 0.5f);
return (cx / 2) - w;
}
void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy)
{
OBSProjector *window = (OBSProjector *)data;
if (updatingMultiview || !window->ready)
return;
OBSBasic *main = (OBSBasic *)obs_frontend_get_main_window();
uint32_t targetCX, targetCY;
int x, y;
float fX, fY, halfCX, halfCY, sourceX, sourceY,
quarterCX, quarterCY, scale, targetCXF, targetCYF,
hiCX, hiCY, qiX, qiY, qiCX, qiCY,
hiScaleX, hiScaleY, qiScaleX, qiScaleY;
uint32_t offset;
gs_rect rect;
gs_effect_t *solid = obs_get_base_effect(OBS_EFFECT_SOLID);
gs_eparam_t *color = gs_effect_get_param_by_name(solid, "color");
struct obs_video_info ovi;
obs_get_video_info(&ovi);
targetCX = ovi.base_width;
targetCY = ovi.base_height;
GetScaleAndCenterPos(targetCX, targetCY, cx, cy, x, y, scale);
targetCXF = float(targetCX);
targetCYF = float(targetCY);
fX = float(x);
fY = float(y);
halfCX = (targetCXF + 1) / 2;
halfCY = (targetCYF + 1) / 2;
hiCX = (halfCX - 4.0);
hiCY = (halfCY - 4.0);
hiScaleX = hiCX / targetCXF;
hiScaleY = hiCY / targetCYF;
quarterCX = (halfCX + 1) / 2;
quarterCY = (halfCY + 1) / 2;
qiCX = (quarterCX - 8.0);
qiCY = (quarterCY - 8.0);
qiScaleX = qiCX / targetCXF;
qiScaleY = qiCY / targetCYF;
OBSSource previewSrc = main->GetCurrentSceneSource();
OBSSource programSrc = main->GetProgramSource();
bool studioMode = main->IsPreviewProgramMode();
auto drawBox = [solid, color] (float cx, float cy,
uint32_t colorVal)
{
gs_effect_set_color(color, colorVal);
while (gs_effect_loop(solid, "Solid"))
gs_draw_sprite(nullptr, 0, (uint32_t)cx, (uint32_t)cy);
};
/* ----------------------------- */
/* draw sources */
gs_projection_push();
gs_viewport_push();
gs_set_viewport(x, y, targetCX * scale, targetCY * scale);
gs_ortho(0.0f, targetCXF, 0.0f, targetCYF, -100.0f, 100.0f);
for (size_t i = 0; i < 8; i++) {
OBSSource src = OBSGetStrongRef(window->multiviewScenes[i]);
obs_source *label = window->multiviewLabels[i + 2];
if (!src)
continue;
if (!label)
continue;
if (i < 4) {
sourceX = (float(i) * quarterCX);
sourceY = halfCY;
} else {
sourceX = (float(i - 4) * quarterCX);
sourceY = halfCY + quarterCY;
}
qiX = sourceX + 4.0f;
qiY = sourceY + 4.0f;
rect.x = int(fX + qiX * scale);
rect.y = int(fY + qiY * scale);
rect.cx = int(qiCX * scale);
rect.cy = int(qiCY * scale);
/* ----------- */
if (src == previewSrc || src == programSrc) {
uint32_t colorVal = src == programSrc
? 0xFFFF0000
: 0xFF00FF00;
gs_matrix_push();
gs_matrix_translate3f(sourceX, sourceY, 0.0f);
drawBox(quarterCX, quarterCY, colorVal);
gs_matrix_pop();
gs_matrix_push();
gs_matrix_translate3f(qiX, qiY, 0.0f);
drawBox(qiCX, qiCY, 0xFF000000);
gs_matrix_pop();
}
/* ----------- */
gs_matrix_push();
gs_matrix_translate3f(qiX, qiY, 0.0f);
gs_matrix_scale3f(qiScaleX, qiScaleY, 1.0f);
gs_effect_set_color(color, 0xFF000000);
gs_set_scissor_rect(&rect);
obs_source_video_render(src);
gs_set_scissor_rect(nullptr);
gs_effect_set_color(color, 0xFFFFFFFF);
renderVB(solid, window->outerBox, targetCX, targetCY);
gs_matrix_pop();
/* ----------- */
offset = labelOffset(label, quarterCX);
cx = obs_source_get_width(label);
cy = obs_source_get_height(label);
gs_matrix_push();
gs_matrix_translate3f(sourceX + offset,
(quarterCY * 0.8f) + sourceY, 0.0f);
drawBox(cx, cy + int(quarterCX * 0.015f), 0xD91F1F1F);
obs_source_video_render(label);
gs_matrix_pop();
}
gs_effect_set_color(color, 0xFFFFFFFF);
/* ----------------------------- */
/* draw preview */
gs_matrix_push();
gs_matrix_translate3f(2.0f, 2.0f, 0.0f);
gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f);
rect.x = int(fX + 2.0f * scale);
rect.y = int(fY + 2.0f * scale);
rect.cx = int(hiCX * scale);
rect.cy = int(hiCY * scale);
gs_set_scissor_rect(&rect);
if (studioMode) {
obs_source_video_render(previewSrc);
} else {
obs_render_main_view();
}
gs_set_scissor_rect(nullptr);
gs_matrix_pop();
/* ----------- */
gs_matrix_push();
gs_matrix_scale3f(0.5f, 0.5f, 1.0f);
renderVB(solid, window->outerBox, targetCX, targetCY);
renderVB(solid, window->innerBox, targetCX, targetCY);
renderVB(solid, window->leftVLine, targetCX, targetCY);
renderVB(solid, window->rightVLine, targetCX, targetCY);
renderVB(solid, window->leftLine, targetCX, targetCY);
renderVB(solid, window->topLine, targetCX, targetCY);
renderVB(solid, window->rightLine, targetCX, targetCY);
gs_matrix_pop();
/* ----------- */
obs_source_t *previewLabel = window->multiviewLabels[0];
offset = labelOffset(previewLabel, halfCX);
cx = obs_source_get_width(previewLabel);
cy = obs_source_get_height(previewLabel);
gs_matrix_push();
gs_matrix_translate3f(offset, (halfCY * 0.8f), 0.0f);
drawBox(cx, cy + int(halfCX * 0.015f), 0xD91F1F1F);
obs_source_video_render(previewLabel);
gs_matrix_pop();
/* ----------------------------- */
/* draw program */
gs_matrix_push();
gs_matrix_translate3f(halfCX + 2.0, 2.0f, 0.0f);
gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f);
rect.x = int(fX + (halfCX + 2.0f) * scale);
rect.y = int(fY + 2.0f * scale);
gs_set_scissor_rect(&rect);
obs_render_main_view();
gs_set_scissor_rect(nullptr);
gs_matrix_pop();
/* ----------- */
gs_matrix_push();
gs_matrix_translate3f(halfCX, 0.0f, 0.0f);
gs_matrix_scale3f(0.5f, 0.5f, 1.0f);
renderVB(solid, window->outerBox, targetCX, targetCY);
gs_matrix_pop();
/* ----------- */
obs_source_t *programLabel = window->multiviewLabels[1];
offset = labelOffset(programLabel, halfCX);
cx = obs_source_get_width(programLabel);
cy = obs_source_get_height(programLabel);
gs_matrix_push();
gs_matrix_translate3f(halfCX + offset, (halfCY * 0.8f), 0.0f);
drawBox(cx, cy + int(halfCX * 0.015f), 0xD91F1F1F);
obs_source_video_render(programLabel);
gs_matrix_pop();
/* ----------------------------- */
gs_viewport_pop();
gs_projection_pop();
}
void OBSProjector::OBSRender(void *data, uint32_t cx, uint32_t cy)
{
OBSProjector *window = reinterpret_cast<OBSProjector*>(data);
if (!window->ready)
return;
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
uint32_t targetCX;
......@@ -123,7 +517,8 @@ void OBSProjector::OBSRender(void *data, uint32_t cx, uint32_t cy)
OBSSource source = window->source;
if (!window->useStudioProgram && main->IsPreviewProgramMode()) {
if (window->type == ProjectorType::Preview &&
main->IsPreviewProgramMode()) {
OBSSource curSource = main->GetCurrentSceneSource();
if (window->source != curSource) {
......@@ -166,11 +561,71 @@ void OBSProjector::mousePressEvent(QMouseEvent *event)
void OBSProjector::EscapeTriggered()
{
if (!isWindow) {
OBSBasic *main =
reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
OBSBasic *main = (OBSBasic*)obs_frontend_get_main_window();
main->RemoveSavedProjectors(savedMonitor);
}
deleteLater();
}
void OBSProjector::UpdateMultiview()
{
for (OBSWeakSource &val : multiviewScenes)
val = nullptr;
for (OBSSource &val : multiviewLabels)
val = nullptr;
struct obs_video_info ovi;
obs_get_video_info(&ovi);
uint32_t h = ovi.base_height;
struct obs_frontend_source_list scenes = {};
obs_frontend_get_scenes(&scenes);
int curIdx = 0;
multiviewLabels[0] = CreateLabel(Str("StudioMode.Preview"), h / 2);
multiviewLabels[1] = CreateLabel(Str("StudioMode.Program"), h / 2);
for (size_t i = 0; i < scenes.sources.num && curIdx < 8; i++) {
obs_source_t *src = scenes.sources.array[i];
OBSData data = obs_source_get_private_settings(src);
obs_data_release(data);
obs_data_set_default_bool(data, "show_in_multiview", true);
if (!obs_data_get_bool(data, "show_in_multiview"))
continue;
multiviewScenes[curIdx] = OBSGetWeakRef(src);
obs_source_inc_showing(src);
std::string name;
name += std::to_string(curIdx + 1);
name += " - ";
name += obs_source_get_name(src);
if (name.size() > 15)
name.resize(15);
multiviewLabels[curIdx + 2] = CreateLabel(name.c_str(), h / 4);
curIdx++;
}
obs_frontend_source_list_free(&scenes);
}
void OBSProjector::UpdateMultiviewProjectors()
{
obs_enter_graphics();
updatingMultiview = true;
obs_leave_graphics();
for (auto &projector : multiviewProjectors)
projector->UpdateMultiview();
obs_enter_graphics();
updatingMultiview = false;
obs_leave_graphics();
}
......@@ -13,6 +13,7 @@ private:
OBSSource source;
OBSSignal removedSignal;
static void OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy);
static void OBSRender(void *data, uint32_t cx, uint32_t cy);
static void OBSSourceRemoved(void *data, calldata_t *params);
......@@ -20,7 +21,19 @@ private:
int savedMonitor = 0;
bool isWindow = false;
bool useStudioProgram = false;
ProjectorType type = ProjectorType::Source;
OBSWeakSource multiviewScenes[8];
OBSSource multiviewLabels[10];
gs_vertbuffer_t *outerBox = nullptr;
gs_vertbuffer_t *innerBox = nullptr;
gs_vertbuffer_t *leftVLine = nullptr;
gs_vertbuffer_t *rightVLine = nullptr;
gs_vertbuffer_t *leftLine = nullptr;
gs_vertbuffer_t *topLine = nullptr;
gs_vertbuffer_t *rightLine = nullptr;
bool ready = false;
void UpdateMultiview();
private slots:
void EscapeTriggered();
......@@ -30,5 +43,7 @@ public:
~OBSProjector();
void Init(int monitor, bool window, QString title,
bool studioProgram = false);
ProjectorType type = ProjectorType::Source);
static void UpdateMultiviewProjectors();
};
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册