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
This commit is contained in:
parent
78411de75e
commit
721cb3dea5
@ -78,6 +78,9 @@ Defaults="Defaults"
|
|||||||
HideMixer="Hide in Mixer"
|
HideMixer="Hide in Mixer"
|
||||||
TransitionOverride="Transition Override"
|
TransitionOverride="Transition Override"
|
||||||
None="None"
|
None="None"
|
||||||
|
StudioMode.Preview="Preview"
|
||||||
|
StudioMode.Program="Program"
|
||||||
|
ShowInMultiview="Show in Multiview"
|
||||||
|
|
||||||
# warning if program already open
|
# warning if program already open
|
||||||
AlreadyRunning.Title="OBS is already running"
|
AlreadyRunning.Title="OBS is already running"
|
||||||
|
@ -139,6 +139,7 @@ OBSBasic::OBSBasic(QWidget *parent)
|
|||||||
|
|
||||||
projectorArray.resize(10, "");
|
projectorArray.resize(10, "");
|
||||||
previewProjectorArray.resize(10, 0);
|
previewProjectorArray.resize(10, 0);
|
||||||
|
multiviewProjectorArray.resize(10, 0);
|
||||||
studioProgramProjectorArray.resize(10, 0);
|
studioProgramProjectorArray.resize(10, 0);
|
||||||
|
|
||||||
setAcceptDrops(true);
|
setAcceptDrops(true);
|
||||||
@ -320,7 +321,8 @@ static obs_data_t *GenerateSaveData(obs_data_array_t *sceneOrder,
|
|||||||
OBSScene &scene, OBSSource &curProgramScene,
|
OBSScene &scene, OBSSource &curProgramScene,
|
||||||
obs_data_array_t *savedProjectorList,
|
obs_data_array_t *savedProjectorList,
|
||||||
obs_data_array_t *savedPreviewProjectorList,
|
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();
|
obs_data_t *saveData = obs_data_create();
|
||||||
|
|
||||||
@ -366,6 +368,8 @@ static obs_data_t *GenerateSaveData(obs_data_array_t *sceneOrder,
|
|||||||
savedPreviewProjectorList);
|
savedPreviewProjectorList);
|
||||||
obs_data_set_array(saveData, "saved_studio_preview_projectors",
|
obs_data_set_array(saveData, "saved_studio_preview_projectors",
|
||||||
savedStudioProgramProjectorList);
|
savedStudioProgramProjectorList);
|
||||||
|
obs_data_set_array(saveData, "saved_multiview_projectors",
|
||||||
|
savedMultiviewProjectorList);
|
||||||
obs_data_array_release(sourcesArray);
|
obs_data_array_release(sourcesArray);
|
||||||
|
|
||||||
obs_data_set_string(saveData, "current_transition",
|
obs_data_set_string(saveData, "current_transition",
|
||||||
@ -468,6 +472,21 @@ obs_data_array_t *OBSBasic::SaveStudioProgramProjectors()
|
|||||||
return saveProjector;
|
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)
|
void OBSBasic::Save(const char *file)
|
||||||
{
|
{
|
||||||
OBSScene scene = GetCurrentScene();
|
OBSScene scene = GetCurrentScene();
|
||||||
@ -482,11 +501,14 @@ void OBSBasic::Save(const char *file)
|
|||||||
obs_data_array_t *savedPreviewProjectorList = SavePreviewProjectors();
|
obs_data_array_t *savedPreviewProjectorList = SavePreviewProjectors();
|
||||||
obs_data_array_t *savedStudioProgramProjectorList =
|
obs_data_array_t *savedStudioProgramProjectorList =
|
||||||
SaveStudioProgramProjectors();
|
SaveStudioProgramProjectors();
|
||||||
|
obs_data_array_t *savedMultiviewProjectorList =
|
||||||
|
SaveMultiviewProjectors();
|
||||||
obs_data_t *saveData = GenerateSaveData(sceneOrder, quickTrData,
|
obs_data_t *saveData = GenerateSaveData(sceneOrder, quickTrData,
|
||||||
ui->transitionDuration->value(), transitions,
|
ui->transitionDuration->value(), transitions,
|
||||||
scene, curProgramScene, savedProjectorList,
|
scene, curProgramScene, savedProjectorList,
|
||||||
savedPreviewProjectorList,
|
savedPreviewProjectorList,
|
||||||
savedStudioProgramProjectorList);
|
savedStudioProgramProjectorList,
|
||||||
|
savedMultiviewProjectorList);
|
||||||
|
|
||||||
obs_data_set_bool(saveData, "preview_locked", ui->preview->Locked());
|
obs_data_set_bool(saveData, "preview_locked", ui->preview->Locked());
|
||||||
obs_data_set_bool(saveData, "scaling_enabled",
|
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(savedProjectorList);
|
||||||
obs_data_array_release(savedPreviewProjectorList);
|
obs_data_array_release(savedPreviewProjectorList);
|
||||||
obs_data_array_release(savedStudioProgramProjectorList);
|
obs_data_array_release(savedStudioProgramProjectorList);
|
||||||
|
obs_data_array_release(savedMultiviewProjectorList);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LoadAudioDevice(const char *name, int channel, obs_data_t *parent)
|
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)
|
static void LogFilter(obs_source_t*, obs_source_t *filter, void *v_val)
|
||||||
{
|
{
|
||||||
const char *name = obs_source_get_name(filter);
|
const char *name = obs_source_get_name(filter);
|
||||||
@ -784,6 +820,8 @@ void OBSBasic::Load(const char *file)
|
|||||||
ui->transitionDuration->setValue(newDuration);
|
ui->transitionDuration->setValue(newDuration);
|
||||||
SetTransition(curTransition);
|
SetTransition(curTransition);
|
||||||
|
|
||||||
|
/* ------------------- */
|
||||||
|
|
||||||
obs_data_array_t *savedProjectors = obs_data_get_array(data,
|
obs_data_array_t *savedProjectors = obs_data_get_array(data,
|
||||||
"saved_projectors");
|
"saved_projectors");
|
||||||
|
|
||||||
@ -792,6 +830,8 @@ void OBSBasic::Load(const char *file)
|
|||||||
|
|
||||||
obs_data_array_release(savedProjectors);
|
obs_data_array_release(savedProjectors);
|
||||||
|
|
||||||
|
/* ------------------- */
|
||||||
|
|
||||||
obs_data_array_t *savedPreviewProjectors = obs_data_get_array(data,
|
obs_data_array_t *savedPreviewProjectors = obs_data_get_array(data,
|
||||||
"saved_preview_projectors");
|
"saved_preview_projectors");
|
||||||
|
|
||||||
@ -800,6 +840,8 @@ void OBSBasic::Load(const char *file)
|
|||||||
|
|
||||||
obs_data_array_release(savedPreviewProjectors);
|
obs_data_array_release(savedPreviewProjectors);
|
||||||
|
|
||||||
|
/* ------------------- */
|
||||||
|
|
||||||
obs_data_array_t *savedStudioProgramProjectors = obs_data_get_array(data,
|
obs_data_array_t *savedStudioProgramProjectors = obs_data_get_array(data,
|
||||||
"saved_studio_preview_projectors");
|
"saved_studio_preview_projectors");
|
||||||
|
|
||||||
@ -808,6 +850,16 @@ void OBSBasic::Load(const char *file)
|
|||||||
|
|
||||||
obs_data_array_release(savedStudioProgramProjectors);
|
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:
|
retryScene:
|
||||||
curScene = obs_get_source_by_name(sceneName);
|
curScene = obs_get_source_by_name(sceneName);
|
||||||
@ -1927,6 +1979,11 @@ void OBSBasic::SaveProjectDeferred()
|
|||||||
Save(savePath);
|
Save(savePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OBSSource OBSBasic::GetProgramSource()
|
||||||
|
{
|
||||||
|
return OBSGetStrongRef(programScene);
|
||||||
|
}
|
||||||
|
|
||||||
OBSScene OBSBasic::GetCurrentScene()
|
OBSScene OBSBasic::GetCurrentScene()
|
||||||
{
|
{
|
||||||
QListWidgetItem *item = ui->scenes->currentItem();
|
QListWidgetItem *item = ui->scenes->currentItem();
|
||||||
@ -2088,6 +2145,8 @@ void OBSBasic::AddScene(OBSSource source)
|
|||||||
obs_source_t *source = obs_scene_get_source(scene);
|
obs_source_t *source = obs_scene_get_source(scene);
|
||||||
blog(LOG_INFO, "User added scene '%s'",
|
blog(LOG_INFO, "User added scene '%s'",
|
||||||
obs_source_get_name(source));
|
obs_source_get_name(source));
|
||||||
|
|
||||||
|
OBSProjector::UpdateMultiviewProjectors();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (api)
|
if (api)
|
||||||
@ -2122,6 +2181,8 @@ void OBSBasic::RemoveScene(OBSSource source)
|
|||||||
if (!disableSaving) {
|
if (!disableSaving) {
|
||||||
blog(LOG_INFO, "User Removed scene '%s'",
|
blog(LOG_INFO, "User Removed scene '%s'",
|
||||||
obs_source_get_name(source));
|
obs_source_get_name(source));
|
||||||
|
|
||||||
|
OBSProjector::UpdateMultiviewProjectors();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (api)
|
if (api)
|
||||||
@ -2203,7 +2264,8 @@ static void RenameListValues(QListWidget *listWidget, const QString &newName,
|
|||||||
items[i]->setText(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);
|
RenameListValues(ui->scenes, newName, prevName);
|
||||||
|
|
||||||
@ -2221,6 +2283,10 @@ void OBSBasic::RenameSources(QString newName, QString prevName)
|
|||||||
}
|
}
|
||||||
|
|
||||||
SaveProject();
|
SaveProject();
|
||||||
|
|
||||||
|
obs_scene_t *scene = obs_scene_from_source(source);
|
||||||
|
if (scene)
|
||||||
|
OBSProjector::UpdateMultiviewProjectors();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::SelectSceneItem(OBSScene scene, OBSSceneItem item, bool select)
|
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)
|
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 *newName = calldata_string(params, "new_name");
|
||||||
const char *prevName = calldata_string(params, "prev_name");
|
const char *prevName = calldata_string(params, "prev_name");
|
||||||
|
|
||||||
QMetaObject::invokeMethod(static_cast<OBSBasic*>(data),
|
QMetaObject::invokeMethod(static_cast<OBSBasic*>(data),
|
||||||
"RenameSources",
|
"RenameSources",
|
||||||
|
Q_ARG(OBSSource, source),
|
||||||
Q_ARG(QString, QT_UTF8(newName)),
|
Q_ARG(QString, QT_UTF8(newName)),
|
||||||
Q_ARG(QString, QT_UTF8(prevName)));
|
Q_ARG(QString, QT_UTF8(prevName)));
|
||||||
|
|
||||||
@ -3457,6 +3525,7 @@ void OBSBasic::on_scenes_customContextMenuRequested(const QPoint &pos)
|
|||||||
popup.addMenu(&order);
|
popup.addMenu(&order);
|
||||||
|
|
||||||
popup.addSeparator();
|
popup.addSeparator();
|
||||||
|
|
||||||
sceneProjectorMenu = new QMenu(QTStr("SceneProjector"));
|
sceneProjectorMenu = new QMenu(QTStr("SceneProjector"));
|
||||||
AddProjectorMenuMonitors(sceneProjectorMenu, this,
|
AddProjectorMenuMonitors(sceneProjectorMenu, this,
|
||||||
SLOT(OpenSceneProjector()));
|
SLOT(OpenSceneProjector()));
|
||||||
@ -3475,6 +3544,36 @@ void OBSBasic::on_scenes_customContextMenuRequested(const QPoint &pos)
|
|||||||
|
|
||||||
QMenu *transitionMenu = CreatePerSceneTransitionMenu();
|
QMenu *transitionMenu = CreatePerSceneTransitionMenu();
|
||||||
popup.addMenu(transitionMenu);
|
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());
|
popup.exec(QCursor::pos());
|
||||||
@ -3719,6 +3818,7 @@ void OBSBasic::CreateSourcePopupMenu(QListWidgetItem *item, bool preview)
|
|||||||
QMenu popup(this);
|
QMenu popup(this);
|
||||||
QPointer<QMenu> previewProjector;
|
QPointer<QMenu> previewProjector;
|
||||||
QPointer<QMenu> sourceProjector;
|
QPointer<QMenu> sourceProjector;
|
||||||
|
QPointer<QMenu> multiviewProjectorMenu;
|
||||||
|
|
||||||
if (preview) {
|
if (preview) {
|
||||||
QAction *action = popup.addAction(
|
QAction *action = popup.addAction(
|
||||||
@ -3733,6 +3833,20 @@ void OBSBasic::CreateSourcePopupMenu(QListWidgetItem *item, bool preview)
|
|||||||
popup.addAction(ui->actionLockPreview);
|
popup.addAction(ui->actionLockPreview);
|
||||||
popup.addMenu(ui->scalingMenu);
|
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"));
|
previewProjector = new QMenu(QTStr("PreviewProjector"));
|
||||||
AddProjectorMenuMonitors(previewProjector, this,
|
AddProjectorMenuMonitors(previewProjector, this,
|
||||||
SLOT(OpenPreviewProjector()));
|
SLOT(OpenPreviewProjector()));
|
||||||
@ -5417,17 +5531,12 @@ void OBSBasic::NudgeLeft() {Nudge(1, MoveDir::Left);}
|
|||||||
void OBSBasic::NudgeRight() {Nudge(1, MoveDir::Right);}
|
void OBSBasic::NudgeRight() {Nudge(1, MoveDir::Right);}
|
||||||
|
|
||||||
void OBSBasic::OpenProjector(obs_source_t *source, int monitor, bool window,
|
void OBSBasic::OpenProjector(obs_source_t *source, int monitor, bool window,
|
||||||
QString title, bool studioProgram)
|
QString title, ProjectorType type)
|
||||||
{
|
{
|
||||||
/* seriously? 10 monitors? */
|
/* seriously? 10 monitors? */
|
||||||
if (monitor > 9 || monitor > QGuiApplication::screens().size() - 1)
|
if (monitor > 9 || monitor > QGuiApplication::screens().size() - 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool isPreview = false;
|
|
||||||
|
|
||||||
if (source == nullptr)
|
|
||||||
isPreview = true;
|
|
||||||
|
|
||||||
if (!window) {
|
if (!window) {
|
||||||
delete projectors[monitor];
|
delete projectors[monitor];
|
||||||
projectors[monitor].clear();
|
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);
|
const char *name = obs_source_get_name(source);
|
||||||
|
|
||||||
if (!window) {
|
if (!window) {
|
||||||
if (studioProgram) {
|
if (type == ProjectorType::StudioProgram) {
|
||||||
studioProgramProjectorArray.at((size_t)monitor) = 1;
|
studioProgramProjectorArray.at((size_t)monitor) = 1;
|
||||||
} else if (isPreview) {
|
} else if (type == ProjectorType::Preview) {
|
||||||
previewProjectorArray.at((size_t)monitor) = 1;
|
previewProjectorArray.at((size_t)monitor) = 1;
|
||||||
|
} else if (type == ProjectorType::Multiview) {
|
||||||
|
multiviewProjectorArray.at((size_t)monitor) = 1;
|
||||||
} else {
|
} else {
|
||||||
projectorArray.at((size_t)monitor) = name;
|
projectorArray.at((size_t)monitor) = name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!window) {
|
if (!window) {
|
||||||
projector->Init(monitor, false, nullptr, studioProgram);
|
projector->Init(monitor, false, nullptr, type);
|
||||||
projectors[monitor] = projector;
|
projectors[monitor] = projector;
|
||||||
} else {
|
} else {
|
||||||
projector->Init(monitor, true, title, studioProgram);
|
projector->Init(monitor, true, title, type);
|
||||||
|
|
||||||
for (auto &projPtr : windowProjectors) {
|
for (auto &projPtr : windowProjectors) {
|
||||||
if (!projPtr) {
|
if (!projPtr) {
|
||||||
@ -5468,13 +5579,14 @@ void OBSBasic::OpenProjector(obs_source_t *source, int monitor, bool window,
|
|||||||
void OBSBasic::OpenStudioProgramProjector()
|
void OBSBasic::OpenStudioProgramProjector()
|
||||||
{
|
{
|
||||||
int monitor = sender()->property("monitor").toInt();
|
int monitor = sender()->property("monitor").toInt();
|
||||||
OpenProjector(nullptr, monitor, false, nullptr, true);
|
OpenProjector(nullptr, monitor, false, nullptr,
|
||||||
|
ProjectorType::StudioProgram);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::OpenPreviewProjector()
|
void OBSBasic::OpenPreviewProjector()
|
||||||
{
|
{
|
||||||
int monitor = sender()->property("monitor").toInt();
|
int monitor = sender()->property("monitor").toInt();
|
||||||
OpenProjector(nullptr, monitor, false);
|
OpenProjector(nullptr, monitor, false, nullptr, ProjectorType::Preview);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::OpenSourceProjector()
|
void OBSBasic::OpenSourceProjector()
|
||||||
@ -5487,6 +5599,13 @@ void OBSBasic::OpenSourceProjector()
|
|||||||
OpenProjector(obs_sceneitem_get_source(item), monitor, false);
|
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()
|
void OBSBasic::OpenSceneProjector()
|
||||||
{
|
{
|
||||||
int monitor = sender()->property("monitor").toInt();
|
int monitor = sender()->property("monitor").toInt();
|
||||||
@ -5501,14 +5620,15 @@ void OBSBasic::OpenStudioProgramWindow()
|
|||||||
{
|
{
|
||||||
int monitor = sender()->property("monitor").toInt();
|
int monitor = sender()->property("monitor").toInt();
|
||||||
QString title = QTStr("StudioProgramWindow");
|
QString title = QTStr("StudioProgramWindow");
|
||||||
OpenProjector(nullptr, monitor, true, title, true);
|
OpenProjector(nullptr, monitor, true, title,
|
||||||
|
ProjectorType::StudioProgram);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::OpenPreviewWindow()
|
void OBSBasic::OpenPreviewWindow()
|
||||||
{
|
{
|
||||||
int monitor = sender()->property("monitor").toInt();
|
int monitor = sender()->property("monitor").toInt();
|
||||||
QString title = QTStr("PreviewWindow");
|
QString title = QTStr("PreviewWindow");
|
||||||
OpenProjector(nullptr, monitor, true, title);
|
OpenProjector(nullptr, monitor, true, nullptr, ProjectorType::Preview);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::OpenSourceWindow()
|
void OBSBasic::OpenSourceWindow()
|
||||||
@ -5526,6 +5646,13 @@ void OBSBasic::OpenSourceWindow()
|
|||||||
OpenProjector(obs_sceneitem_get_source(item), monitor, true, title);
|
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()
|
void OBSBasic::OpenSceneWindow()
|
||||||
{
|
{
|
||||||
int monitor = sender()->property("monitor").toInt();
|
int monitor = sender()->property("monitor").toInt();
|
||||||
@ -5566,13 +5693,21 @@ void OBSBasic::OpenSavedProjectors()
|
|||||||
for (size_t i = 0; i < studioProgramProjectorArray.size(); i++) {
|
for (size_t i = 0; i < studioProgramProjectorArray.size(); i++) {
|
||||||
if (studioProgramProjectorArray.at(i) == 1) {
|
if (studioProgramProjectorArray.at(i) == 1) {
|
||||||
OpenProjector(nullptr, (int)i, false, nullptr,
|
OpenProjector(nullptr, (int)i, false, nullptr,
|
||||||
true);
|
ProjectorType::StudioProgram);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < previewProjectorArray.size(); i++) {
|
for (size_t i = 0; i < previewProjectorArray.size(); i++) {
|
||||||
if (previewProjectorArray.at(i) == 1) {
|
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)
|
void OBSBasic::RemoveSavedProjectors(int monitor)
|
||||||
{
|
{
|
||||||
studioProgramProjectorArray.at((size_t)monitor) = 0;
|
studioProgramProjectorArray.at((size_t)monitor) = 0;
|
||||||
|
multiviewProjectorArray.at((size_t)monitor) = 0;
|
||||||
previewProjectorArray.at((size_t)monitor) = 0;
|
previewProjectorArray.at((size_t)monitor) = 0;
|
||||||
projectorArray.at((size_t)monitor) = "";
|
projectorArray.at((size_t)monitor) = "";
|
||||||
}
|
}
|
||||||
|
@ -67,6 +67,13 @@ enum class QtDataRole {
|
|||||||
OBSSignals,
|
OBSSignals,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class ProjectorType {
|
||||||
|
Source,
|
||||||
|
Preview,
|
||||||
|
StudioProgram,
|
||||||
|
Multiview
|
||||||
|
};
|
||||||
|
|
||||||
struct QuickTransition {
|
struct QuickTransition {
|
||||||
QPushButton *button = nullptr;
|
QPushButton *button = nullptr;
|
||||||
OBSSource source;
|
OBSSource source;
|
||||||
@ -115,6 +122,7 @@ private:
|
|||||||
|
|
||||||
std::vector<std::string> projectorArray;
|
std::vector<std::string> projectorArray;
|
||||||
std::vector<int> studioProgramProjectorArray;
|
std::vector<int> studioProgramProjectorArray;
|
||||||
|
std::vector<int> multiviewProjectorArray;
|
||||||
std::vector<int> previewProjectorArray;
|
std::vector<int> previewProjectorArray;
|
||||||
|
|
||||||
bool loaded = false;
|
bool loaded = false;
|
||||||
@ -241,7 +249,8 @@ private:
|
|||||||
|
|
||||||
void Nudge(int dist, MoveDir dir);
|
void Nudge(int dist, MoveDir dir);
|
||||||
void OpenProjector(obs_source_t *source, int monitor, bool window,
|
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 GetAudioSourceFilters();
|
||||||
void GetAudioSourceProperties();
|
void GetAudioSourceProperties();
|
||||||
@ -361,6 +370,10 @@ private:
|
|||||||
void LoadSavedStudioProgramProjectors(
|
void LoadSavedStudioProgramProjectors(
|
||||||
obs_data_array_t *savedStudioProgramProjectors);
|
obs_data_array_t *savedStudioProgramProjectors);
|
||||||
|
|
||||||
|
obs_data_array_t *SaveMultiviewProjectors();
|
||||||
|
void LoadSavedMultiviewProjectors(
|
||||||
|
obs_data_array_t *savedMultiviewProjectors);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void StartStreaming();
|
void StartStreaming();
|
||||||
void StopStreaming();
|
void StopStreaming();
|
||||||
@ -404,7 +417,7 @@ private slots:
|
|||||||
void RemoveSceneItem(OBSSceneItem item);
|
void RemoveSceneItem(OBSSceneItem item);
|
||||||
void AddScene(OBSSource source);
|
void AddScene(OBSSource source);
|
||||||
void RemoveScene(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);
|
void SelectSceneItem(OBSScene scene, OBSSceneItem item, bool select);
|
||||||
|
|
||||||
@ -477,7 +490,8 @@ private:
|
|||||||
static void HotkeyTriggered(void *data, obs_hotkey_id id, bool pressed);
|
static void HotkeyTriggered(void *data, obs_hotkey_id id, bool pressed);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
OBSScene GetCurrentScene();
|
OBSSource GetProgramSource();
|
||||||
|
OBSScene GetCurrentScene();
|
||||||
|
|
||||||
void SysTrayNotify(const QString &text, QSystemTrayIcon::MessageIcon n);
|
void SysTrayNotify(const QString &text, QSystemTrayIcon::MessageIcon n);
|
||||||
|
|
||||||
@ -689,11 +703,13 @@ private slots:
|
|||||||
void OpenStudioProgramProjector();
|
void OpenStudioProgramProjector();
|
||||||
void OpenPreviewProjector();
|
void OpenPreviewProjector();
|
||||||
void OpenSourceProjector();
|
void OpenSourceProjector();
|
||||||
|
void OpenMultiviewProjector();
|
||||||
void OpenSceneProjector();
|
void OpenSceneProjector();
|
||||||
|
|
||||||
void OpenStudioProgramWindow();
|
void OpenStudioProgramWindow();
|
||||||
void OpenPreviewWindow();
|
void OpenPreviewWindow();
|
||||||
void OpenSourceWindow();
|
void OpenSourceWindow();
|
||||||
|
void OpenMultiviewWindow();
|
||||||
void OpenSceneWindow();
|
void OpenSceneWindow();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
@ -7,7 +7,9 @@
|
|||||||
#include "display-helpers.hpp"
|
#include "display-helpers.hpp"
|
||||||
#include "qt-wrappers.hpp"
|
#include "qt-wrappers.hpp"
|
||||||
#include "platform.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)
|
OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, bool window)
|
||||||
: OBSQTDisplay (widget,
|
: OBSQTDisplay (widget,
|
||||||
@ -30,7 +32,10 @@ OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, bool window)
|
|||||||
|
|
||||||
auto addDrawCallback = [this] ()
|
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);
|
obs_display_set_background_color(GetDisplay(), 0x000000);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -50,13 +55,73 @@ OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, bool window)
|
|||||||
|
|
||||||
OBSProjector::~OBSProjector()
|
OBSProjector::~OBSProjector()
|
||||||
{
|
{
|
||||||
|
bool isMultiview = type == ProjectorType::Multiview;
|
||||||
|
obs_display_remove_draw_callback(GetDisplay(),
|
||||||
|
isMultiview ? OBSRenderMultiview : OBSRender, this);
|
||||||
|
|
||||||
if (source)
|
if (source)
|
||||||
obs_source_dec_showing(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();
|
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,
|
void OBSProjector::Init(int monitor, bool window, QString title,
|
||||||
bool studioProgram)
|
ProjectorType type_)
|
||||||
{
|
{
|
||||||
QScreen *screen = QGuiApplication::screens()[monitor];
|
QScreen *screen = QGuiApplication::screens()[monitor];
|
||||||
|
|
||||||
@ -86,13 +151,342 @@ void OBSProjector::Init(int monitor, bool window, QString title,
|
|||||||
}
|
}
|
||||||
|
|
||||||
savedMonitor = monitor;
|
savedMonitor = monitor;
|
||||||
isWindow = window;
|
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)
|
void OBSProjector::OBSRender(void *data, uint32_t cx, uint32_t cy)
|
||||||
{
|
{
|
||||||
OBSProjector *window = reinterpret_cast<OBSProjector*>(data);
|
OBSProjector *window = reinterpret_cast<OBSProjector*>(data);
|
||||||
|
|
||||||
|
if (!window->ready)
|
||||||
|
return;
|
||||||
|
|
||||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||||
|
|
||||||
uint32_t targetCX;
|
uint32_t targetCX;
|
||||||
@ -123,7 +517,8 @@ void OBSProjector::OBSRender(void *data, uint32_t cx, uint32_t cy)
|
|||||||
|
|
||||||
OBSSource source = window->source;
|
OBSSource source = window->source;
|
||||||
|
|
||||||
if (!window->useStudioProgram && main->IsPreviewProgramMode()) {
|
if (window->type == ProjectorType::Preview &&
|
||||||
|
main->IsPreviewProgramMode()) {
|
||||||
OBSSource curSource = main->GetCurrentSceneSource();
|
OBSSource curSource = main->GetCurrentSceneSource();
|
||||||
|
|
||||||
if (window->source != curSource) {
|
if (window->source != curSource) {
|
||||||
@ -166,11 +561,71 @@ void OBSProjector::mousePressEvent(QMouseEvent *event)
|
|||||||
void OBSProjector::EscapeTriggered()
|
void OBSProjector::EscapeTriggered()
|
||||||
{
|
{
|
||||||
if (!isWindow) {
|
if (!isWindow) {
|
||||||
OBSBasic *main =
|
OBSBasic *main = (OBSBasic*)obs_frontend_get_main_window();
|
||||||
reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
|
||||||
|
|
||||||
main->RemoveSavedProjectors(savedMonitor);
|
main->RemoveSavedProjectors(savedMonitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteLater();
|
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;
|
OBSSource source;
|
||||||
OBSSignal removedSignal;
|
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 OBSRender(void *data, uint32_t cx, uint32_t cy);
|
||||||
static void OBSSourceRemoved(void *data, calldata_t *params);
|
static void OBSSourceRemoved(void *data, calldata_t *params);
|
||||||
|
|
||||||
@ -20,7 +21,19 @@ private:
|
|||||||
|
|
||||||
int savedMonitor = 0;
|
int savedMonitor = 0;
|
||||||
bool isWindow = false;
|
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:
|
private slots:
|
||||||
void EscapeTriggered();
|
void EscapeTriggered();
|
||||||
@ -30,5 +43,7 @@ public:
|
|||||||
~OBSProjector();
|
~OBSProjector();
|
||||||
|
|
||||||
void Init(int monitor, bool window, QString title,
|
void Init(int monitor, bool window, QString title,
|
||||||
bool studioProgram = false);
|
ProjectorType type = ProjectorType::Source);
|
||||||
|
|
||||||
|
static void UpdateMultiviewProjectors();
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user