From b0415621d64c247abe50712dd17a230ac51d0032 Mon Sep 17 00:00:00 2001 From: Shaolin Date: Wed, 7 Mar 2018 06:12:55 -0300 Subject: [PATCH 01/25] UI: Use enum for multiview layout --- UI/window-basic-settings.cpp | 26 ++++++++------------- UI/window-projector.cpp | 44 ++++++++++++------------------------ UI/window-projector.hpp | 7 ++++++ 3 files changed, 31 insertions(+), 46 deletions(-) diff --git a/UI/window-basic-settings.cpp b/UI/window-basic-settings.cpp index 4e54fbdd6..7ac557e7a 100644 --- a/UI/window-basic-settings.cpp +++ b/UI/window-basic-settings.cpp @@ -1102,28 +1102,20 @@ void OBSBasicSettings::LoadGeneralSettings() ui->multiviewLayout->addItem(QTStr( "Basic.Settings.General.MultiviewLayout.Horizontal.Top"), - QT_UTF8("horizontaltop")); + static_cast(MultiviewLayout::HORIZONTAL_TOP)); ui->multiviewLayout->addItem(QTStr( "Basic.Settings.General.MultiviewLayout.Horizontal.Bottom"), - QT_UTF8("horizontalbottom")); + static_cast(MultiviewLayout::HORIZONTAL_BOTTOM)); ui->multiviewLayout->addItem(QTStr( "Basic.Settings.General.MultiviewLayout.Vertical.Left"), - QT_UTF8("verticalleft")); + static_cast(MultiviewLayout::VERTICAL_LEFT)); ui->multiviewLayout->addItem(QTStr( "Basic.Settings.General.MultiviewLayout.Vertical.Right"), - QT_UTF8("verticalright")); + static_cast(MultiviewLayout::VERTICAL_RIGHT)); - const char *multiviewLayoutText = config_get_string(GetGlobalConfig(), - "BasicWindow", "MultiviewLayout"); - - if (astrcmpi(multiviewLayoutText, "horizontalbottom") == 0) - ui->multiviewLayout->setCurrentIndex(1); - else if (astrcmpi(multiviewLayoutText, "verticalleft") == 0) - ui->multiviewLayout->setCurrentIndex(2); - else if (astrcmpi(multiviewLayoutText, "verticalright") == 0) - ui->multiviewLayout->setCurrentIndex(3); - else - ui->multiviewLayout->setCurrentIndex(0); + ui->multiviewLayout->setCurrentIndex( + config_get_int(GetGlobalConfig(), "BasicWindow", + "MultiviewLayout")); loading = false; } @@ -2713,9 +2705,9 @@ void OBSBasicSettings::SaveGeneralSettings() } if (WidgetChanged(ui->multiviewLayout)) { - config_set_string(GetGlobalConfig(), "BasicWindow", + config_set_int(GetGlobalConfig(), "BasicWindow", "MultiviewLayout", - QT_TO_UTF8(GetComboData(ui->multiviewLayout))); + ui->multiviewLayout->currentData().toInt()); OBSProjector::UpdateMultiviewProjectors(); } diff --git a/UI/window-projector.cpp b/UI/window-projector.cpp index 20b9104f7..e4688c1cf 100644 --- a/UI/window-projector.cpp +++ b/UI/window-projector.cpp @@ -9,15 +9,10 @@ #include "qt-wrappers.hpp" #include "platform.hpp" -#define HORIZONTAL_TOP 0 -#define HORIZONTAL_BOTTOM 1 -#define VERTICAL_LEFT 2 -#define VERTICAL_RIGHT 3 - static QList windowedProjectors; static QList multiviewProjectors; static bool updatingMultiview = false; -static int multiviewLayout = HORIZONTAL_TOP; +static MultiviewLayout multiviewLayout; OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, int monitor, QString title, ProjectorType type_) @@ -338,19 +333,19 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) auto calcBaseSource = [&](size_t i) { switch (multiviewLayout) { - case VERTICAL_LEFT: + case MultiviewLayout::VERTICAL_LEFT: sourceX = halfCX; sourceY = (i / 2 ) * quarterCY; if (i % 2 != 0) sourceX = halfCX + quarterCX; break; - case VERTICAL_RIGHT: + case MultiviewLayout::VERTICAL_RIGHT: sourceX = 0; sourceY = (i / 2 ) * quarterCY; if (i % 2 != 0) sourceX = quarterCX; break; - case HORIZONTAL_BOTTOM: + case MultiviewLayout::HORIZONTAL_BOTTOM: if (i < 4) { sourceX = (float(i) * quarterCX); sourceY = 0; @@ -359,7 +354,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) sourceY = quarterCY; } break; - default: //HORIZONTAL_TOP: + default: // MultiviewLayout::HORIZONTAL_TOP: if (i < 4) { sourceX = (float(i) * quarterCX); sourceY = halfCY; @@ -373,7 +368,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) auto calcPreviewProgram = [&](bool program) { switch (multiviewLayout) { - case VERTICAL_LEFT: + case MultiviewLayout::VERTICAL_LEFT: sourceX = 2.0f; sourceY = halfCY + 2.0f; labelX = offset; @@ -383,7 +378,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) labelY = halfCY * 0.8f; } break; - case VERTICAL_RIGHT: + case MultiviewLayout::VERTICAL_RIGHT: sourceX = halfCX + 2.0f; sourceY = halfCY + 2.0f; labelX = halfCX + offset; @@ -393,7 +388,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) labelY = halfCY * 0.8f; } break; - case HORIZONTAL_BOTTOM: + case MultiviewLayout::HORIZONTAL_BOTTOM: sourceX = 2.0f; sourceY = halfCY + 2.0f; labelX = offset; @@ -403,7 +398,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) labelX = halfCX + offset; } break; - default: //HORIZONTAL_TOP: + default: // MultiviewLayout::HORIZONTAL_TOP: sourceX = 2.0f; sourceY = 2.0f; labelX = offset; @@ -670,7 +665,7 @@ static int getSourceByPosition(int x, int y) int pos = -1; switch (multiviewLayout) { - case VERTICAL_LEFT: + case MultiviewLayout::VERTICAL_LEFT: if (float(cx) / float(cy) > ratio) { int validX = cy * ratio; maxX = halfX + (validX / 2); @@ -689,7 +684,7 @@ static int getSourceByPosition(int x, int y) if (x > minX + ((maxX - minX) / 2)) pos++; break; - case VERTICAL_RIGHT: + case MultiviewLayout::VERTICAL_RIGHT: if (float(cx) / float(cy) > ratio) { int validX = cy * ratio; minX = halfX - (validX / 2); @@ -708,7 +703,7 @@ static int getSourceByPosition(int x, int y) if (x > minX + ((maxX - minX) / 2)) pos++; break; - case HORIZONTAL_BOTTOM: + case MultiviewLayout::HORIZONTAL_BOTTOM: if (float(cx) / float(cy) > ratio) { int validX = cy * ratio; minX = halfX - (validX / 2); @@ -727,7 +722,7 @@ static int getSourceByPosition(int x, int y) if (y > minY + ((maxY - minY) / 2)) pos += 4; break; - default: // HORIZONTAL_TOP + default: // MultiviewLayout::HORIZONTAL_TOP if (float(cx) / float(cy) > ratio) { int validX = cy * ratio; minX = halfX - (validX / 2); @@ -848,17 +843,8 @@ void OBSProjector::UpdateMultiview() obs_frontend_source_list_free(&scenes); - const char *multiviewLayoutText = config_get_string(GetGlobalConfig(), - "BasicWindow", "MultiviewLayout"); - - if (astrcmpi(multiviewLayoutText, "horizontalbottom") == 0) - multiviewLayout = HORIZONTAL_BOTTOM; - else if (astrcmpi(multiviewLayoutText, "verticalleft") == 0) - multiviewLayout = VERTICAL_LEFT; - else if (astrcmpi(multiviewLayoutText, "verticalright") == 0) - multiviewLayout = VERTICAL_RIGHT; - else - multiviewLayout = HORIZONTAL_TOP; + multiviewLayout = static_cast(config_get_int( + GetGlobalConfig(), "BasicWindow", "MultiviewLayout")); } void OBSProjector::UpdateProjectorTitle(QString name) diff --git a/UI/window-projector.hpp b/UI/window-projector.hpp index 35badccee..3552b4708 100644 --- a/UI/window-projector.hpp +++ b/UI/window-projector.hpp @@ -13,6 +13,13 @@ enum class ProjectorType { class QMouseEvent; +enum class MultiviewLayout : uint8_t { + HORIZONTAL_TOP = 0, + HORIZONTAL_BOTTOM = 1, + VERTICAL_LEFT = 2, + VERTICAL_RIGHT = 3 +}; + class OBSProjector : public OBSQTDisplay { Q_OBJECT From b8a901c870a0a1a93e2acab20c028500c8e4957c Mon Sep 17 00:00:00 2001 From: Shaolin Date: Wed, 9 May 2018 05:52:56 -0300 Subject: [PATCH 02/25] UI: Convert multiview layout string profiles to int This commit series changes the ini user configuration multiview layout so that string values were converted to int. In order to prevent past user saves to break we verify if the ini still have string values and convert that to int on obs init. This will make the code easier to maintain in clearer to read the multiview layout settings, also, makes the addition of new layouts easier. --- UI/obs-app.cpp | 39 +++++++++++++++++++++++++++++++++++++++ UI/obs-app.hpp | 2 ++ 2 files changed, 41 insertions(+) diff --git a/UI/obs-app.cpp b/UI/obs-app.cpp index f8f76755c..fa106152e 100644 --- a/UI/obs-app.cpp +++ b/UI/obs-app.cpp @@ -591,6 +591,38 @@ static string GetSceneCollectionFileFromName(const char *name) return outputPath; } +bool OBSApp::UpdatePre22MultiviewLayout(const char *layout) +{ + if (!layout) + return false; + + if (astrcmpi(layout, "horizontaltop") == 0) { + config_set_int(globalConfig, "BasicWindow", "MultiviewLayout", + static_cast(MultiviewLayout::HORIZONTAL_TOP)); + return true; + } + + if (astrcmpi(layout, "horizontalbottom") == 0) { + config_set_int(globalConfig, "BasicWindow", "MultiviewLayout", + static_cast(MultiviewLayout::HORIZONTAL_BOTTOM)); + return true; + } + + if (astrcmpi(layout, "verticalleft") == 0) { + config_set_int(globalConfig, "BasicWindow", "MultiviewLayout", + static_cast(MultiviewLayout::VERTICAL_LEFT)); + return true; + } + + if (astrcmpi(layout, "verticalright") == 0) { + config_set_int(globalConfig, "BasicWindow", "MultiviewLayout", + static_cast(MultiviewLayout::VERTICAL_RIGHT)); + return true; + } + + return false; +} + bool OBSApp::InitGlobalConfig() { char path[512]; @@ -656,6 +688,13 @@ bool OBSApp::InitGlobalConfig() changed = true; } + if (config_has_user_value(globalConfig, "BasicWindow", + "MultiviewLayout")) { + const char *layout = config_get_string(globalConfig, + "BasicWindow", "MultiviewLayout"); + changed |= UpdatePre22MultiviewLayout(layout); + } + if (changed) config_save_safe(globalConfig, "tmp", nullptr); diff --git a/UI/obs-app.hpp b/UI/obs-app.hpp index c32896129..4a17e4971 100644 --- a/UI/obs-app.hpp +++ b/UI/obs-app.hpp @@ -78,6 +78,8 @@ private: std::deque translatorHooks; + bool UpdatePre22MultiviewLayout(const char *layout); + bool InitGlobalConfig(); bool InitGlobalConfigDefaults(); bool InitLocale(); From a142261edde8c1a1ce01acd81e66c857802abb45 Mon Sep 17 00:00:00 2001 From: Shaolin Date: Tue, 20 Mar 2018 21:41:39 -0300 Subject: [PATCH 03/25] UI: Clarify multiview layout names --- UI/data/locale/en-US.ini | 8 ++++---- UI/obs-app.cpp | 12 ++++++++---- UI/window-basic-settings.cpp | 8 ++++---- UI/window-projector.cpp | 24 ++++++++++++------------ UI/window-projector.hpp | 8 ++++---- 5 files changed, 32 insertions(+), 28 deletions(-) diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini index 5c0941479..28d2105d6 100644 --- a/UI/data/locale/en-US.ini +++ b/UI/data/locale/en-US.ini @@ -572,10 +572,10 @@ Basic.Settings.General.SaveProjectors="Save projectors on exit" Basic.Settings.General.SwitchOnDoubleClick="Transition to scene when double-clicked" Basic.Settings.General.StudioPortraitLayout="Enable portrait/vertical layout" Basic.Settings.General.MultiviewLayout="Multiview Layout" -Basic.Settings.General.MultiviewLayout.Horizontal.Top="Horizontal, Top" -Basic.Settings.General.MultiviewLayout.Horizontal.Bottom="Horizontal, Bottom" -Basic.Settings.General.MultiviewLayout.Vertical.Left="Vertical, Left" -Basic.Settings.General.MultiviewLayout.Vertical.Right="Vertical, Right" +Basic.Settings.General.MultiviewLayout.Horizontal.Top="Horizontal, Top (8 Scenes)" +Basic.Settings.General.MultiviewLayout.Horizontal.Bottom="Horizontal, Bottom (8 Scenes)" +Basic.Settings.General.MultiviewLayout.Vertical.Left="Vertical, Left (8 Scenes)" +Basic.Settings.General.MultiviewLayout.Vertical.Right="Vertical, Right (8 Scenes)" # basic mode 'stream' settings Basic.Settings.Stream="Stream" diff --git a/UI/obs-app.cpp b/UI/obs-app.cpp index fa106152e..3eb576057 100644 --- a/UI/obs-app.cpp +++ b/UI/obs-app.cpp @@ -598,25 +598,29 @@ bool OBSApp::UpdatePre22MultiviewLayout(const char *layout) if (astrcmpi(layout, "horizontaltop") == 0) { config_set_int(globalConfig, "BasicWindow", "MultiviewLayout", - static_cast(MultiviewLayout::HORIZONTAL_TOP)); + static_cast( + MultiviewLayout::HORIZONTAL_TOP_8_SCENES)); return true; } if (astrcmpi(layout, "horizontalbottom") == 0) { config_set_int(globalConfig, "BasicWindow", "MultiviewLayout", - static_cast(MultiviewLayout::HORIZONTAL_BOTTOM)); + static_cast( + MultiviewLayout::HORIZONTAL_BOTTOM_8_SCENES)); return true; } if (astrcmpi(layout, "verticalleft") == 0) { config_set_int(globalConfig, "BasicWindow", "MultiviewLayout", - static_cast(MultiviewLayout::VERTICAL_LEFT)); + static_cast( + MultiviewLayout::VERTICAL_LEFT_8_SCENES)); return true; } if (astrcmpi(layout, "verticalright") == 0) { config_set_int(globalConfig, "BasicWindow", "MultiviewLayout", - static_cast(MultiviewLayout::VERTICAL_RIGHT)); + static_cast( + MultiviewLayout::VERTICAL_RIGHT_8_SCENES)); return true; } diff --git a/UI/window-basic-settings.cpp b/UI/window-basic-settings.cpp index 7ac557e7a..3a0d626a3 100644 --- a/UI/window-basic-settings.cpp +++ b/UI/window-basic-settings.cpp @@ -1102,16 +1102,16 @@ void OBSBasicSettings::LoadGeneralSettings() ui->multiviewLayout->addItem(QTStr( "Basic.Settings.General.MultiviewLayout.Horizontal.Top"), - static_cast(MultiviewLayout::HORIZONTAL_TOP)); + static_cast(MultiviewLayout::HORIZONTAL_TOP_8_SCENES)); ui->multiviewLayout->addItem(QTStr( "Basic.Settings.General.MultiviewLayout.Horizontal.Bottom"), - static_cast(MultiviewLayout::HORIZONTAL_BOTTOM)); + static_cast(MultiviewLayout::HORIZONTAL_BOTTOM_8_SCENES)); ui->multiviewLayout->addItem(QTStr( "Basic.Settings.General.MultiviewLayout.Vertical.Left"), - static_cast(MultiviewLayout::VERTICAL_LEFT)); + static_cast(MultiviewLayout::VERTICAL_LEFT_8_SCENES)); ui->multiviewLayout->addItem(QTStr( "Basic.Settings.General.MultiviewLayout.Vertical.Right"), - static_cast(MultiviewLayout::VERTICAL_RIGHT)); + static_cast(MultiviewLayout::VERTICAL_RIGHT_8_SCENES)); ui->multiviewLayout->setCurrentIndex( config_get_int(GetGlobalConfig(), "BasicWindow", diff --git a/UI/window-projector.cpp b/UI/window-projector.cpp index e4688c1cf..af3d8b4db 100644 --- a/UI/window-projector.cpp +++ b/UI/window-projector.cpp @@ -333,19 +333,19 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) auto calcBaseSource = [&](size_t i) { switch (multiviewLayout) { - case MultiviewLayout::VERTICAL_LEFT: + case MultiviewLayout::VERTICAL_LEFT_8_SCENES: sourceX = halfCX; sourceY = (i / 2 ) * quarterCY; if (i % 2 != 0) sourceX = halfCX + quarterCX; break; - case MultiviewLayout::VERTICAL_RIGHT: + case MultiviewLayout::VERTICAL_RIGHT_8_SCENES: sourceX = 0; sourceY = (i / 2 ) * quarterCY; if (i % 2 != 0) sourceX = quarterCX; break; - case MultiviewLayout::HORIZONTAL_BOTTOM: + case MultiviewLayout::HORIZONTAL_BOTTOM_8_SCENES: if (i < 4) { sourceX = (float(i) * quarterCX); sourceY = 0; @@ -354,7 +354,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) sourceY = quarterCY; } break; - default: // MultiviewLayout::HORIZONTAL_TOP: + default: // MultiviewLayout::HORIZONTAL_TOP_8_SCENES: if (i < 4) { sourceX = (float(i) * quarterCX); sourceY = halfCY; @@ -368,7 +368,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) auto calcPreviewProgram = [&](bool program) { switch (multiviewLayout) { - case MultiviewLayout::VERTICAL_LEFT: + case MultiviewLayout::VERTICAL_LEFT_8_SCENES: sourceX = 2.0f; sourceY = halfCY + 2.0f; labelX = offset; @@ -378,7 +378,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) labelY = halfCY * 0.8f; } break; - case MultiviewLayout::VERTICAL_RIGHT: + case MultiviewLayout::VERTICAL_RIGHT_8_SCENES: sourceX = halfCX + 2.0f; sourceY = halfCY + 2.0f; labelX = halfCX + offset; @@ -388,7 +388,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) labelY = halfCY * 0.8f; } break; - case MultiviewLayout::HORIZONTAL_BOTTOM: + case MultiviewLayout::HORIZONTAL_BOTTOM_8_SCENES: sourceX = 2.0f; sourceY = halfCY + 2.0f; labelX = offset; @@ -398,7 +398,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) labelX = halfCX + offset; } break; - default: // MultiviewLayout::HORIZONTAL_TOP: + default: // MultiviewLayout::HORIZONTAL_TOP_8_SCENES: sourceX = 2.0f; sourceY = 2.0f; labelX = offset; @@ -665,7 +665,7 @@ static int getSourceByPosition(int x, int y) int pos = -1; switch (multiviewLayout) { - case MultiviewLayout::VERTICAL_LEFT: + case MultiviewLayout::VERTICAL_LEFT_8_SCENES: if (float(cx) / float(cy) > ratio) { int validX = cy * ratio; maxX = halfX + (validX / 2); @@ -684,7 +684,7 @@ static int getSourceByPosition(int x, int y) if (x > minX + ((maxX - minX) / 2)) pos++; break; - case MultiviewLayout::VERTICAL_RIGHT: + case MultiviewLayout::VERTICAL_RIGHT_8_SCENES: if (float(cx) / float(cy) > ratio) { int validX = cy * ratio; minX = halfX - (validX / 2); @@ -703,7 +703,7 @@ static int getSourceByPosition(int x, int y) if (x > minX + ((maxX - minX) / 2)) pos++; break; - case MultiviewLayout::HORIZONTAL_BOTTOM: + case MultiviewLayout::HORIZONTAL_BOTTOM_8_SCENES: if (float(cx) / float(cy) > ratio) { int validX = cy * ratio; minX = halfX - (validX / 2); @@ -722,7 +722,7 @@ static int getSourceByPosition(int x, int y) if (y > minY + ((maxY - minY) / 2)) pos += 4; break; - default: // MultiviewLayout::HORIZONTAL_TOP + default: // MultiviewLayout::HORIZONTAL_TOP_8_SCENES if (float(cx) / float(cy) > ratio) { int validX = cy * ratio; minX = halfX - (validX / 2); diff --git a/UI/window-projector.hpp b/UI/window-projector.hpp index 3552b4708..b64ee01d3 100644 --- a/UI/window-projector.hpp +++ b/UI/window-projector.hpp @@ -14,10 +14,10 @@ enum class ProjectorType { class QMouseEvent; enum class MultiviewLayout : uint8_t { - HORIZONTAL_TOP = 0, - HORIZONTAL_BOTTOM = 1, - VERTICAL_LEFT = 2, - VERTICAL_RIGHT = 3 + HORIZONTAL_TOP_8_SCENES = 0, + HORIZONTAL_BOTTOM_8_SCENES = 1, + VERTICAL_LEFT_8_SCENES = 2, + VERTICAL_RIGHT_8_SCENES = 3 }; class OBSProjector : public OBSQTDisplay { From fc3e85a59897664de58cd06e5417d12bf129dd10 Mon Sep 17 00:00:00 2001 From: Shaolin Date: Thu, 8 Mar 2018 16:04:22 -0300 Subject: [PATCH 04/25] UI: Make multiview colors easier to manage --- UI/window-projector.cpp | 17 ++++++++--------- UI/window-projector.hpp | 7 +++++++ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/UI/window-projector.cpp b/UI/window-projector.cpp index af3d8b4db..3217bb357 100644 --- a/UI/window-projector.cpp +++ b/UI/window-projector.cpp @@ -435,9 +435,8 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) /* ----------- */ if (src == previewSrc || src == programSrc) { - uint32_t colorVal = src == programSrc - ? 0xFFFF0000 - : 0xFF00FF00; + uint32_t colorVal = src == programSrc ? programColor + : previewColor; gs_matrix_push(); gs_matrix_translate3f(sourceX, sourceY, 0.0f); @@ -446,7 +445,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) gs_matrix_push(); gs_matrix_translate3f(qiX, qiY, 0.0f); - drawBox(qiCX, qiCY, 0xFF000000); + drawBox(qiCX, qiCY, backgroundColor); gs_matrix_pop(); } @@ -460,7 +459,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) obs_source_video_render(src); resetRegion(); - gs_effect_set_color(color, 0xFFFFFFFF); + gs_effect_set_color(color, outerColor); renderVB(solid, window->outerBox, targetCX, targetCY); gs_matrix_pop(); @@ -475,13 +474,13 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) gs_matrix_translate3f(sourceX + offset, (quarterCY * 0.8f) + sourceY, 0.0f); - drawBox(cx, cy + int(quarterCX * 0.015f), 0xD91F1F1F); + drawBox(cx, cy + int(quarterCX * 0.015f), labelColor); obs_source_video_render(label); gs_matrix_pop(); } - gs_effect_set_color(color, 0xFFFFFFFF); + gs_effect_set_color(color, outerColor); /* ----------------------------- */ /* draw preview */ @@ -530,7 +529,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) gs_matrix_push(); gs_matrix_translate3f(labelX, labelY, 0.0f); - drawBox(cx, cy + int(halfCX * 0.015f), 0xD91F1F1F); + drawBox(cx, cy + int(halfCX * 0.015f), labelColor); obs_source_video_render(previewLabel); gs_matrix_pop(); @@ -570,7 +569,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) gs_matrix_push(); gs_matrix_translate3f(labelX, labelY, 0.0f); - drawBox(cx, cy + int(halfCX * 0.015f), 0xD91F1F1F); + drawBox(cx, cy + int(halfCX * 0.015f), labelColor); obs_source_video_render(programLabel); gs_matrix_pop(); diff --git a/UI/window-projector.hpp b/UI/window-projector.hpp index b64ee01d3..49bcf8b01 100644 --- a/UI/window-projector.hpp +++ b/UI/window-projector.hpp @@ -49,6 +49,13 @@ private: gs_vertbuffer_t *rightLine = nullptr; bool ready = false; + // argb colors + static const uint32_t outerColor = 0xFFD0D0D0; + static const uint32_t labelColor = 0xD91F1F1F; + static const uint32_t backgroundColor = 0xFF000000; + static const uint32_t previewColor = 0xFF00FF00; + static const uint32_t programColor = 0xFFFF0000; + void UpdateMultiview(); void UpdateProjectorTitle(QString name); From 22a18873400cff65456c0bd1ce630697a74db840 Mon Sep 17 00:00:00 2001 From: Shaolin Date: Thu, 8 Mar 2018 20:27:15 -0300 Subject: [PATCH 05/25] UI: Clean up projector's render regions creation --- UI/window-projector.cpp | 62 +++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/UI/window-projector.cpp b/UI/window-projector.cpp index 3217bb357..3820ee1a8 100644 --- a/UI/window-projector.cpp +++ b/UI/window-projector.cpp @@ -248,6 +248,21 @@ static inline uint32_t labelOffset(obs_source_t *label, uint32_t cx) return (cx / 2) - w; } +static inline void startRegion(int vX, int vY, int vCX, int vCY, float oL, + float oR, float oT, float oB) +{ + gs_projection_push(); + gs_viewport_push(); + gs_set_viewport(vX, vY, vCX, vCY); + gs_ortho(oL, oR, oT, oB, -100.0f, 100.0f); +} + +static inline void endRegion() +{ + gs_viewport_pop(); + gs_projection_pop(); +} + void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) { OBSProjector *window = (OBSProjector *)data; @@ -318,16 +333,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) float oR = (x + cx); float oB = (y + cy); - gs_projection_push(); - gs_viewport_push(); - gs_set_viewport(vX, vY, vCX, vCY); - gs_ortho(oL, oR, oT, oB, -100.0f, 100.0f); - }; - - auto resetRegion = [] () - { - gs_viewport_pop(); - gs_projection_pop(); + startRegion(vX, vY, vCX, vCY, oL, oR, oT, oB); }; auto calcBaseSource = [&](size_t i) @@ -413,10 +419,8 @@ void OBSProjector::OBSRenderMultiview(void *data, 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); + startRegion(x, y, targetCX * scale, targetCY * scale, 0.0f, targetCXF, + 0.0f, targetCYF); for (size_t i = 0; i < 8; i++) { OBSSource src = OBSGetStrongRef(window->multiviewScenes[i]); @@ -457,7 +461,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) setRegion(qiX, qiY, qiCX, qiCY); obs_source_video_render(src); - resetRegion(); + endRegion(); gs_effect_set_color(color, outerColor); renderVB(solid, window->outerBox, targetCX, targetCY); @@ -494,14 +498,11 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f); setRegion(sourceX, sourceY, hiCX, hiCY); - - if (studioMode) { + if (studioMode) obs_source_video_render(previewSrc); - } else { + else obs_render_main_texture(); - } - - resetRegion(); + endRegion(); gs_matrix_pop(); @@ -547,7 +548,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) setRegion(sourceX, sourceY, hiCX, hiCY); obs_render_main_texture(); - resetRegion(); + endRegion(); gs_matrix_pop(); @@ -576,8 +577,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) /* ----------------------------- */ - gs_viewport_pop(); - gs_projection_pop(); + endRegion(); } void OBSProjector::OBSRender(void *data, uint32_t cx, uint32_t cy) @@ -611,10 +611,8 @@ void OBSProjector::OBSRender(void *data, uint32_t cx, uint32_t cy) newCX = int(scale * float(targetCX)); newCY = int(scale * float(targetCY)); - gs_viewport_push(); - gs_projection_push(); - gs_ortho(0.0f, float(targetCX), 0.0f, float(targetCY), -100.0f, 100.0f); - gs_set_viewport(x, y, newCX, newCY); + startRegion(x, y, newCX, newCY, 0.0f, float(targetCX), 0.0f, + float(targetCY)); if (window->type == ProjectorType::Preview && main->IsPreviewProgramMode()) { @@ -627,14 +625,12 @@ void OBSProjector::OBSRender(void *data, uint32_t cx, uint32_t cy) } } - if (source) { + if (source) obs_source_video_render(source); - } else { + else obs_render_main_texture(); - } - gs_projection_pop(); - gs_viewport_pop(); + endRegion(); } void OBSProjector::OBSSourceRemoved(void *data, calldata_t *params) From 32ee7ee4e250e30bec2b08ed4ec047235eff19d0 Mon Sep 17 00:00:00 2001 From: Shaolin Date: Sun, 29 Apr 2018 09:29:53 -0300 Subject: [PATCH 06/25] UI: Clean up Projector Creation The Init function were only called on projector creation so this isn't needed to be on a separate function. Its clearer to read the code. --- UI/window-basic-main.cpp | 1 - UI/window-projector.cpp | 63 ++++++++++++++++++++-------------------- UI/window-projector.hpp | 2 -- 3 files changed, 31 insertions(+), 35 deletions(-) diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp index 50c1ecb9b..8a85cd17d 100644 --- a/UI/window-basic-main.cpp +++ b/UI/window-basic-main.cpp @@ -5672,7 +5672,6 @@ OBSProjector *OBSBasic::OpenProjector(obs_source_t *source, int monitor, projectors[monitor] = projector; } - projector->Init(); return projector; } diff --git a/UI/window-projector.cpp b/UI/window-projector.cpp index 3820ee1a8..97ea378ba 100644 --- a/UI/window-projector.cpp +++ b/UI/window-projector.cpp @@ -22,16 +22,30 @@ OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, int monitor, removedSignal (obs_source_get_signal_handler(source), "remove", OBSSourceRemoved, this) { - projectorTitle = title; + projectorTitle = std::move(title); savedMonitor = monitor; isWindow = savedMonitor < 0; type = type_; if (isWindow) { setWindowIcon(QIcon(":/res/images/obs.png")); + + UpdateProjectorTitle(projectorTitle); + windowedProjectors.push_back(this); + + resize(480, 270); } else { setWindowFlags(Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint); + + QScreen *screen = QGuiApplication::screens()[savedMonitor]; + setGeometry(screen->geometry()); + + QAction *action = new QAction(this); + action->setShortcut(Qt::Key_Escape); + addAction(action); + connect(action, SIGNAL(triggered()), this, + SLOT(EscapeTriggered())); } setAttribute(Qt::WA_DeleteOnClose, true); @@ -52,6 +66,11 @@ OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, int monitor, connect(this, &OBSQTDisplay::DisplayCreated, addDrawCallback); + bool alwaysOnTop = config_get_bool(GetGlobalConfig(), "BasicWindow", + "ProjectorAlwaysOnTop"); + if (alwaysOnTop && !isWindow) + SetAlwaysOnTop(this, true); + bool hideCursor = config_get_bool(GetGlobalConfig(), "BasicWindow", "HideProjectorCursor"); if (hideCursor && !isWindow) { @@ -110,7 +129,17 @@ OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, int monitor, } App()->IncrementSleepInhibition(); - resize(480, 270); + + if (source) + obs_source_inc_showing(source); + + ready = true; + + show(); + + // We need it here to allow keyboard input in X11 to listen to Escape + if (!isWindow) + activateWindow(); } OBSProjector::~OBSProjector() @@ -189,36 +218,6 @@ static OBSSource CreateLabel(const char *name, size_t h) return txtSource; } -void OBSProjector::Init() -{ - bool alwaysOnTop = config_get_bool(GetGlobalConfig(), - "BasicWindow", "ProjectorAlwaysOnTop"); - if (alwaysOnTop && !isWindow) - SetAlwaysOnTop(this, true); - - show(); - - if (isWindow) { - UpdateProjectorTitle(projectorTitle); - windowedProjectors.push_back(this); - } else { - QScreen *screen = QGuiApplication::screens()[savedMonitor]; - setGeometry(screen->geometry()); - - QAction *action = new QAction(this); - action->setShortcut(Qt::Key_Escape); - addAction(action); - connect(action, SIGNAL(triggered()), this, - SLOT(EscapeTriggered())); - activateWindow(); - } - - if (source) - obs_source_inc_showing(source); - - ready = true; -} - static inline void renderVB(gs_effect_t *effect, gs_vertbuffer_t *vb, int cx, int cy) { diff --git a/UI/window-projector.hpp b/UI/window-projector.hpp index 49bcf8b01..562e9dc9f 100644 --- a/UI/window-projector.hpp +++ b/UI/window-projector.hpp @@ -67,8 +67,6 @@ public: QString title, ProjectorType type_); ~OBSProjector(); - void Init(); - OBSSource GetSource(); ProjectorType GetProjectorType(); int GetMonitor(); From 4ed9d020525821d76a1e50e54f7ca1aecb973c33 Mon Sep 17 00:00:00 2001 From: Shaolin Date: Mon, 12 Mar 2018 00:34:02 -0300 Subject: [PATCH 07/25] UI: Make the sources border color a little darker --- UI/window-projector.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/UI/window-projector.hpp b/UI/window-projector.hpp index 562e9dc9f..91b022ed7 100644 --- a/UI/window-projector.hpp +++ b/UI/window-projector.hpp @@ -53,8 +53,8 @@ private: static const uint32_t outerColor = 0xFFD0D0D0; static const uint32_t labelColor = 0xD91F1F1F; static const uint32_t backgroundColor = 0xFF000000; - static const uint32_t previewColor = 0xFF00FF00; - static const uint32_t programColor = 0xFFFF0000; + static const uint32_t previewColor = 0xFF00D000; + static const uint32_t programColor = 0xFFD00000; void UpdateMultiview(); void UpdateProjectorTitle(QString name); From 40f8d4cfb2fada75bd4ec35a6743f92ef5a961bb Mon Sep 17 00:00:00 2001 From: Shaolin Date: Mon, 12 Mar 2018 02:29:00 -0300 Subject: [PATCH 08/25] UI: Make the multiview lines use the same color --- UI/window-projector.cpp | 44 ++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/UI/window-projector.cpp b/UI/window-projector.cpp index 97ea378ba..e5843d3be 100644 --- a/UI/window-projector.cpp +++ b/UI/window-projector.cpp @@ -312,6 +312,29 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) bool studioMode = main->IsPreviewProgramMode(); + auto renderVB = [solid, color](gs_vertbuffer_t *vb, int cx, int cy, + uint32_t colorVal) + { + 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); + + gs_effect_set_color(color, colorVal); + while (gs_effect_loop(solid, "Solid")) + gs_draw(GS_LINESTRIP, 0, 0); + + gs_matrix_pop(); + }; + auto drawBox = [solid, color] (float cx, float cy, uint32_t colorVal) { @@ -462,8 +485,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) obs_source_video_render(src); endRegion(); - gs_effect_set_color(color, outerColor); - renderVB(solid, window->outerBox, targetCX, targetCY); + renderVB(window->outerBox, targetCX, targetCY, outerColor); gs_matrix_pop(); @@ -483,8 +505,6 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) gs_matrix_pop(); } - gs_effect_set_color(color, outerColor); - /* ----------------------------- */ /* draw preview */ @@ -511,13 +531,13 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) gs_matrix_translate3f(sourceX, sourceY, 0.0f); gs_matrix_scale3f(hiScaleX, hiScaleY, 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); + renderVB(window->outerBox, targetCX, targetCY, outerColor); + renderVB(window->innerBox, targetCX, targetCY, outerColor); + renderVB(window->leftVLine, targetCX, targetCY, outerColor); + renderVB(window->rightVLine, targetCX, targetCY, outerColor); + renderVB(window->leftLine, targetCX, targetCY, outerColor); + renderVB(window->topLine, targetCX, targetCY, outerColor); + renderVB(window->rightLine, targetCX, targetCY, outerColor); gs_matrix_pop(); @@ -557,7 +577,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) gs_matrix_translate3f(sourceX, sourceY, 0.0f); gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f); - renderVB(solid, window->outerBox, targetCX, targetCY); + renderVB(window->outerBox, targetCX, targetCY, outerColor); gs_matrix_pop(); From 3d189484f9ba58e7cf444b013120b7d99f1839c3 Mon Sep 17 00:00:00 2001 From: Shaolin Date: Tue, 13 Mar 2018 14:33:14 -0300 Subject: [PATCH 09/25] UI: Remove the outerbox markers in multiview The same effect is achieved by painting the whole canvas with the outerColor --- UI/window-projector.cpp | 45 ++++++++++++++++++----------------------- UI/window-projector.hpp | 1 - 2 files changed, 20 insertions(+), 26 deletions(-) diff --git a/UI/window-projector.cpp b/UI/window-projector.cpp index e5843d3be..e22624831 100644 --- a/UI/window-projector.cpp +++ b/UI/window-projector.cpp @@ -81,13 +81,6 @@ OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, int monitor, 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); @@ -159,7 +152,6 @@ OBSProjector::~OBSProjector() } obs_enter_graphics(); - gs_vertexbuffer_destroy(outerBox); gs_vertexbuffer_destroy(innerBox); gs_vertexbuffer_destroy(leftVLine); gs_vertexbuffer_destroy(rightVLine); @@ -335,8 +327,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) gs_matrix_pop(); }; - auto drawBox = [solid, color] (float cx, float cy, - uint32_t colorVal) + auto drawBox = [solid, color](float cx, float cy, uint32_t colorVal) { gs_effect_set_color(color, colorVal); while (gs_effect_loop(solid, "Solid")) @@ -438,12 +429,16 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) } }; - /* ----------------------------- */ - /* draw sources */ - + // Define the whole usable region for the multiview startRegion(x, y, targetCX * scale, targetCY * scale, 0.0f, targetCXF, 0.0f, targetCYF); + // Change the background color to highlight all sources + drawBox(targetCXF, targetCYF, outerColor); + + /* ----------------------------- */ + /* draw sources */ + for (size_t i = 0; i < 8; i++) { OBSSource src = OBSGetStrongRef(window->multiviewScenes[i]); obs_source *label = window->multiviewLabels[i + 2]; @@ -468,15 +463,17 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) 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, backgroundColor); - gs_matrix_pop(); } + // Change the background back of the source region + gs_matrix_push(); + gs_matrix_translate3f(qiX, qiY, 0.0f); + drawBox(qiCX, qiCY, backgroundColor); + gs_matrix_pop(); + /* ----------- */ + // Draw the actual source gs_matrix_push(); gs_matrix_translate3f(qiX, qiY, 0.0f); gs_matrix_scale3f(qiScaleX, qiScaleY, 1.0f); @@ -485,8 +482,6 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) obs_source_video_render(src); endRegion(); - renderVB(window->outerBox, targetCX, targetCY, outerColor); - gs_matrix_pop(); /* ----------- */ @@ -517,10 +512,13 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f); setRegion(sourceX, sourceY, hiCX, hiCY); - if (studioMode) + if (studioMode) { + // Change the background back of the source region + drawBox(targetCXF, targetCYF, backgroundColor); obs_source_video_render(previewSrc); - else + } else { obs_render_main_texture(); + } endRegion(); gs_matrix_pop(); @@ -531,7 +529,6 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) gs_matrix_translate3f(sourceX, sourceY, 0.0f); gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f); - renderVB(window->outerBox, targetCX, targetCY, outerColor); renderVB(window->innerBox, targetCX, targetCY, outerColor); renderVB(window->leftVLine, targetCX, targetCY, outerColor); renderVB(window->rightVLine, targetCX, targetCY, outerColor); @@ -577,8 +574,6 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) gs_matrix_translate3f(sourceX, sourceY, 0.0f); gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f); - renderVB(window->outerBox, targetCX, targetCY, outerColor); - gs_matrix_pop(); /* ----------- */ diff --git a/UI/window-projector.hpp b/UI/window-projector.hpp index 91b022ed7..9f932e266 100644 --- a/UI/window-projector.hpp +++ b/UI/window-projector.hpp @@ -40,7 +40,6 @@ private: 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; From 1b357d3b12a046d410cea67b19063c9a99a8f93a Mon Sep 17 00:00:00 2001 From: Shaolin Date: Tue, 13 Mar 2018 16:38:30 -0300 Subject: [PATCH 10/25] UI: Change multiview non-studio selection color When not in studio mode the preview and program sources are the same but the checks will be made against GetCurrentSceneSource which were resulting in the multiview source highlight to give the previewColor where in this case we want the programColor. --- UI/window-projector.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/UI/window-projector.cpp b/UI/window-projector.cpp index e22624831..0b223b750 100644 --- a/UI/window-projector.cpp +++ b/UI/window-projector.cpp @@ -455,15 +455,17 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) /* ----------- */ - if (src == previewSrc || src == programSrc) { - uint32_t colorVal = src == programSrc ? programColor - : previewColor; + uint32_t colorVal = outerColor; + if (src == programSrc) + colorVal = programColor; + else if (src == previewSrc) + colorVal = studioMode ? previewColor : programColor; - gs_matrix_push(); - gs_matrix_translate3f(sourceX, sourceY, 0.0f); - drawBox(quarterCX, quarterCY, colorVal); - gs_matrix_pop(); - } + // Highlight preview/program sources with a proper color + gs_matrix_push(); + gs_matrix_translate3f(sourceX, sourceY, 0.0f); + drawBox(quarterCX, quarterCY, colorVal); + gs_matrix_pop(); // Change the background back of the source region gs_matrix_push(); From 98839524f7ae2def6c4351126ac90abf31e0486f Mon Sep 17 00:00:00 2001 From: Shaolin Date: Tue, 13 Mar 2018 18:46:18 -0300 Subject: [PATCH 11/25] UI: Simplify multiview draw code --- UI/window-projector.cpp | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/UI/window-projector.cpp b/UI/window-projector.cpp index 0b223b750..5d5b87107 100644 --- a/UI/window-projector.cpp +++ b/UI/window-projector.cpp @@ -523,14 +523,6 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) } endRegion(); - gs_matrix_pop(); - - /* ----------- */ - - gs_matrix_push(); - gs_matrix_translate3f(sourceX, sourceY, 0.0f); - gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f); - renderVB(window->innerBox, targetCX, targetCY, outerColor); renderVB(window->leftVLine, targetCX, targetCY, outerColor); renderVB(window->rightVLine, targetCX, targetCY, outerColor); @@ -572,27 +564,14 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) /* ----------- */ - gs_matrix_push(); - gs_matrix_translate3f(sourceX, sourceY, 0.0f); - gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f); - - gs_matrix_pop(); - - /* ----------- */ - cx = obs_source_get_width(programLabel); cy = obs_source_get_height(programLabel); gs_matrix_push(); gs_matrix_translate3f(labelX, labelY, 0.0f); - drawBox(cx, cy + int(halfCX * 0.015f), labelColor); obs_source_video_render(programLabel); - gs_matrix_pop(); - - /* ----------------------------- */ - endRegion(); } From b4d2d5d9c453e42035d4e4df7ddc283daf8fe592 Mon Sep 17 00:00:00 2001 From: Shaolin Date: Tue, 13 Mar 2018 23:52:32 -0300 Subject: [PATCH 12/25] UI: Add proper source markers to multiview This ensures the pixel correctness of the sources selection highlight boxes when on a fullscreen projector. When on a windowed projector due to the nature of int<->float conversions and also due to the limited space, some source boxes might be like 'off-by-one' and barely noticeable. --- UI/window-projector.cpp | 197 ++++++++++++++++++++-------------------- 1 file changed, 99 insertions(+), 98 deletions(-) diff --git a/UI/window-projector.cpp b/UI/window-projector.cpp index 5d5b87107..7ce7a2de8 100644 --- a/UI/window-projector.cpp +++ b/UI/window-projector.cpp @@ -262,13 +262,13 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) return; OBSBasic *main = (OBSBasic *)obs_frontend_get_main_window(); - uint32_t targetCX, targetCY; + uint32_t thickness = 4; + uint32_t targetCX, targetCY, offset, thicknessx2 = thickness * 2; int x, y; float fX, fY, halfCX, halfCY, sourceX, sourceY, labelX, labelY, quarterCX, quarterCY, scale, targetCXF, targetCYF, hiCX, hiCY, qiX, qiY, qiCX, qiCY, hiScaleX, hiScaleY, qiScaleX, qiScaleY; - uint32_t offset; gs_effect_t *solid = obs_get_base_effect(OBS_EFFECT_SOLID); gs_eparam_t *color = gs_effect_get_param_by_name(solid, "color"); @@ -285,19 +285,19 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) 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; + halfCX = targetCXF / 2; + halfCY = targetCYF / 2; + hiCX = halfCX - thicknessx2; + hiCY = halfCY - thicknessx2; + hiScaleX = (halfCX - thicknessx2) / targetCXF; + hiScaleY = (halfCY - thicknessx2) / targetCYF; - quarterCX = (halfCX + 1) / 2; - quarterCY = (halfCY + 1) / 2; - qiCX = (quarterCX - 8.0); - qiCY = (quarterCY - 8.0); - qiScaleX = qiCX / targetCXF; - qiScaleY = qiCY / targetCYF; + quarterCX = halfCX / 2; + quarterCY = halfCY / 2; + qiCX = quarterCX - thicknessx2; + qiCY = quarterCY - thicknessx2; + qiScaleX = (quarterCX - thicknessx2) / targetCXF; + qiScaleY = (quarterCY - thicknessx2) / targetCYF; OBSSource previewSrc = main->GetCurrentSceneSource(); OBSSource programSrc = main->GetProgramSource(); @@ -356,7 +356,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) sourceX = halfCX; sourceY = (i / 2 ) * quarterCY; if (i % 2 != 0) - sourceX = halfCX + quarterCX; + sourceX += quarterCX; break; case MultiviewLayout::VERTICAL_RIGHT_8_SCENES: sourceX = 0; @@ -382,53 +382,64 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) sourceY = halfCY + quarterCY; } } + qiX = sourceX + thickness; + qiY = sourceY + thickness; }; auto calcPreviewProgram = [&](bool program) { switch (multiviewLayout) { case MultiviewLayout::VERTICAL_LEFT_8_SCENES: - sourceX = 2.0f; - sourceY = halfCY + 2.0f; + sourceX = thickness; + sourceY = halfCY + thickness; labelX = offset; labelY = halfCY * 1.8f; if (program) { - sourceY = 2.0f; + sourceY = thickness; labelY = halfCY * 0.8f; } break; case MultiviewLayout::VERTICAL_RIGHT_8_SCENES: - sourceX = halfCX + 2.0f; - sourceY = halfCY + 2.0f; + sourceX = halfCX + thickness; + sourceY = halfCY + thickness; labelX = halfCX + offset; labelY = halfCY * 1.8f; if (program) { - sourceY = 2.0f; + sourceY = thickness; labelY = halfCY * 0.8f; } break; case MultiviewLayout::HORIZONTAL_BOTTOM_8_SCENES: - sourceX = 2.0f; - sourceY = halfCY + 2.0f; + sourceX = thickness; + sourceY = halfCY + thickness; labelX = offset; labelY = halfCY * 1.8f; if (program) { - sourceX = halfCX + 2.0f; - labelX = halfCX + offset; + sourceX += halfCX; + labelX += halfCX; } break; default: // MultiviewLayout::HORIZONTAL_TOP_8_SCENES: - sourceX = 2.0f; - sourceY = 2.0f; + sourceX = thickness; + sourceY = thickness; labelX = offset; labelY = halfCY * 0.8f; if (program) { - sourceX = halfCX + 2.0f; - labelX = halfCX + offset; + sourceX += halfCX; + labelX += halfCX; } } }; + auto paintAreaWithColor = [&](float tx, float ty, float cx, float cy, + uint32_t color) + { + gs_matrix_push(); + gs_matrix_translate3f(tx, ty, 0.0f); + drawBox(cx, cy, color); + gs_matrix_pop(); + }; + // Define the whole usable region for the multiview startRegion(x, y, targetCX * scale, targetCY * scale, 0.0f, targetCXF, 0.0f, targetCYF); @@ -443,63 +454,58 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) OBSSource src = OBSGetStrongRef(window->multiviewScenes[i]); obs_source *label = window->multiviewLabels[i + 2]; - if (!src) - continue; - if (!label) - continue; - + // Handle all the offsets calcBaseSource(i); - qiX = sourceX + 4.0f; - qiY = sourceY + 4.0f; + if (src) { + // Chose the proper highlight color + uint32_t colorVal = outerColor; + if (src == programSrc) + colorVal = programColor; + else if (src == previewSrc) + colorVal = studioMode ? previewColor + : programColor; - /* ----------- */ + // Paint the background + paintAreaWithColor(sourceX, sourceY, quarterCX, + quarterCY, colorVal); + paintAreaWithColor(qiX, qiY, qiCX, qiCY, + backgroundColor); - uint32_t colorVal = outerColor; - if (src == programSrc) - colorVal = programColor; - else if (src == previewSrc) - colorVal = studioMode ? previewColor : programColor; + /* ----------- */ - // Highlight preview/program sources with a proper color - gs_matrix_push(); - gs_matrix_translate3f(sourceX, sourceY, 0.0f); - drawBox(quarterCX, quarterCY, colorVal); - gs_matrix_pop(); + // Render the source + gs_matrix_push(); + gs_matrix_translate3f(qiX, qiY, 0.0f); + gs_matrix_scale3f(qiScaleX, qiScaleY, 1.0f); + setRegion(qiX, qiY, qiCX, qiCY); + obs_source_video_render(src); + endRegion(); + gs_matrix_pop(); - // Change the background back of the source region - gs_matrix_push(); - gs_matrix_translate3f(qiX, qiY, 0.0f); - drawBox(qiCX, qiCY, backgroundColor); - gs_matrix_pop(); + /* ----------- */ - /* ----------- */ + // Render the label + if (!label) + continue; - // Draw the actual source - gs_matrix_push(); - gs_matrix_translate3f(qiX, qiY, 0.0f); - gs_matrix_scale3f(qiScaleX, qiScaleY, 1.0f); + offset = labelOffset(label, quarterCX); + cx = obs_source_get_width(label); + cy = obs_source_get_height(label); - setRegion(qiX, qiY, qiCX, qiCY); - obs_source_video_render(src); - endRegion(); - - 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), labelColor); - obs_source_video_render(label); - - gs_matrix_pop(); + gs_matrix_push(); + gs_matrix_translate3f(sourceX + offset, + (quarterCY * 0.8f) + sourceY, 0.0f); + drawBox(cx, cy + int(quarterCX * 0.015f), labelColor); + obs_source_video_render(label); + gs_matrix_pop(); + } else { + // Paint the background + paintAreaWithColor(sourceX, sourceY, quarterCX, + quarterCY, outerColor); + paintAreaWithColor(qiX, qiY, qiCX, qiCY, + backgroundColor); + } } /* ----------------------------- */ @@ -509,40 +515,36 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) offset = labelOffset(previewLabel, halfCX); calcPreviewProgram(false); + // Paint the background + paintAreaWithColor(sourceX, sourceY, hiCX, hiCY, backgroundColor); + + // Scale and Draw the preview gs_matrix_push(); gs_matrix_translate3f(sourceX, sourceY, 0.0f); gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f); - setRegion(sourceX, sourceY, hiCX, hiCY); - if (studioMode) { - // Change the background back of the source region - drawBox(targetCXF, targetCYF, backgroundColor); + if (studioMode) obs_source_video_render(previewSrc); - } else { + else obs_render_main_texture(); - } - endRegion(); - renderVB(window->innerBox, targetCX, targetCY, outerColor); renderVB(window->leftVLine, targetCX, targetCY, outerColor); renderVB(window->rightVLine, targetCX, targetCY, outerColor); renderVB(window->leftLine, targetCX, targetCY, outerColor); renderVB(window->topLine, targetCX, targetCY, outerColor); renderVB(window->rightLine, targetCX, targetCY, outerColor); - + endRegion(); gs_matrix_pop(); /* ----------- */ - cx = obs_source_get_width(previewLabel); - cy = obs_source_get_height(previewLabel); - + // Draw the Label gs_matrix_push(); gs_matrix_translate3f(labelX, labelY, 0.0f); - - drawBox(cx, cy + int(halfCX * 0.015f), labelColor); + drawBox(obs_source_get_width(previewLabel), + obs_source_get_height(previewLabel) + + int(halfCX * 0.015f), labelColor); obs_source_video_render(previewLabel); - gs_matrix_pop(); /* ----------------------------- */ @@ -552,24 +554,23 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) offset = labelOffset(programLabel, halfCX); calcPreviewProgram(true); + // Scale and Draw the program gs_matrix_push(); gs_matrix_translate3f(sourceX, sourceY, 0.0f); gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f); - setRegion(sourceX, sourceY, hiCX, hiCY); obs_render_main_texture(); endRegion(); - gs_matrix_pop(); /* ----------- */ - cx = obs_source_get_width(programLabel); - cy = obs_source_get_height(programLabel); - + // Draw the Label gs_matrix_push(); gs_matrix_translate3f(labelX, labelY, 0.0f); - drawBox(cx, cy + int(halfCX * 0.015f), labelColor); + drawBox(obs_source_get_width(programLabel), + obs_source_get_height(programLabel) + + int(halfCX * 0.015f), labelColor); obs_source_video_render(programLabel); gs_matrix_pop(); endRegion(); From 959bdda48c06b22e1667391f98e74225b34ae6eb Mon Sep 17 00:00:00 2001 From: Shaolin Date: Wed, 14 Mar 2018 05:27:03 -0300 Subject: [PATCH 13/25] UI: Adjust multiview label size --- UI/window-projector.cpp | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/UI/window-projector.cpp b/UI/window-projector.cpp index 7ce7a2de8..dc89f2543 100644 --- a/UI/window-projector.cpp +++ b/UI/window-projector.cpp @@ -235,7 +235,15 @@ static inline void renderVB(gs_effect_t *effect, gs_vertbuffer_t *vb, 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); + + int n; // Number of scenes per row + switch (multiviewLayout) { + default: + n = 4; + break; + } + + w = uint32_t(w * ((1.0f) / n)); return (cx / 2) - w; } @@ -393,27 +401,27 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) sourceX = thickness; sourceY = halfCY + thickness; labelX = offset; - labelY = halfCY * 1.8f; + labelY = halfCY * 1.85f; if (program) { sourceY = thickness; - labelY = halfCY * 0.8f; + labelY = halfCY * 0.85f; } break; case MultiviewLayout::VERTICAL_RIGHT_8_SCENES: sourceX = halfCX + thickness; sourceY = halfCY + thickness; labelX = halfCX + offset; - labelY = halfCY * 1.8f; + labelY = halfCY * 1.85f; if (program) { sourceY = thickness; - labelY = halfCY * 0.8f; + labelY = halfCY * 0.85f; } break; case MultiviewLayout::HORIZONTAL_BOTTOM_8_SCENES: sourceX = thickness; sourceY = halfCY + thickness; labelX = offset; - labelY = halfCY * 1.8f; + labelY = halfCY * 1.85f; if (program) { sourceX += halfCX; labelX += halfCX; @@ -423,7 +431,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) sourceX = thickness; sourceY = thickness; labelX = offset; - labelY = halfCY * 0.8f; + labelY = halfCY * 0.85f; if (program) { sourceX += halfCX; labelX += halfCX; @@ -490,13 +498,14 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) continue; 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), labelColor); + (quarterCY * 0.85f) + sourceY, 0.0f); + gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f); + drawBox(obs_source_get_width(label), + obs_source_get_height(label) + + int(quarterCX * 0.015f), labelColor); obs_source_video_render(label); gs_matrix_pop(); } else { @@ -541,6 +550,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) // Draw the Label gs_matrix_push(); gs_matrix_translate3f(labelX, labelY, 0.0f); + gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f); drawBox(obs_source_get_width(previewLabel), obs_source_get_height(previewLabel) + int(halfCX * 0.015f), labelColor); @@ -568,6 +578,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) // Draw the Label gs_matrix_push(); gs_matrix_translate3f(labelX, labelY, 0.0f); + gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f); drawBox(obs_source_get_width(programLabel), obs_source_get_height(programLabel) + int(halfCX * 0.015f), labelColor); From 09135d69172e1fe520405bf6718d1f76421d8137 Mon Sep 17 00:00:00 2001 From: Shaolin Date: Wed, 14 Mar 2018 06:05:13 -0300 Subject: [PATCH 14/25] UI: Update multiview on resolution change --- UI/window-basic-main.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp index 8a85cd17d..a2a5ab99b 100644 --- a/UI/window-basic-main.cpp +++ b/UI/window-basic-main.cpp @@ -3251,8 +3251,10 @@ int OBSBasic::ResetVideo() ResizeProgram(ovi.base_width, ovi.base_height); } - if (ret == OBS_VIDEO_SUCCESS) + if (ret == OBS_VIDEO_SUCCESS) { OBSBasicStats::InitializeValues(); + OBSProjector::UpdateMultiviewProjectors(); + } return ret; } From 177ce136553b47560a8808c6e4ca4ead91f593f0 Mon Sep 17 00:00:00 2001 From: Shaolin Date: Sun, 20 May 2018 23:15:26 -0300 Subject: [PATCH 15/25] UI: Update multiview on scene list reorder --- UI/window-basic-main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp index a2a5ab99b..74a88b3b5 100644 --- a/UI/window-basic-main.cpp +++ b/UI/window-basic-main.cpp @@ -3775,6 +3775,8 @@ void OBSBasic::ChangeSceneIndex(bool relative, int offset, int invalidIdx) item->setSelected(true); sceneChanging = false; + + OBSProjector::UpdateMultiviewProjectors(); } void OBSBasic::on_actionSceneUp_triggered() From 2420d4d31d9989606703e4bbe9954bfdb9411b9e Mon Sep 17 00:00:00 2001 From: Shaolin Date: Fri, 16 Mar 2018 16:20:18 -0300 Subject: [PATCH 16/25] UI: Move multiview settings to its own groupbox --- UI/data/locale/en-US.ini | 1 + UI/forms/OBSBasicSettings.ui | 38 ++++++++++++++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini index 28d2105d6..a048abf91 100644 --- a/UI/data/locale/en-US.ini +++ b/UI/data/locale/en-US.ini @@ -571,6 +571,7 @@ Basic.Settings.General.SystemTrayHideMinimize="Always minimize to system tray in Basic.Settings.General.SaveProjectors="Save projectors on exit" Basic.Settings.General.SwitchOnDoubleClick="Transition to scene when double-clicked" Basic.Settings.General.StudioPortraitLayout="Enable portrait/vertical layout" +Basic.Settings.General.Multiview="Multiview" Basic.Settings.General.MultiviewLayout="Multiview Layout" Basic.Settings.General.MultiviewLayout.Horizontal.Top="Horizontal, Top (8 Scenes)" Basic.Settings.General.MultiviewLayout.Horizontal.Bottom="Horizontal, Bottom (8 Scenes)" diff --git a/UI/forms/OBSBasicSettings.ui b/UI/forms/OBSBasicSettings.ui index df0cc5bba..5a87b51bb 100644 --- a/UI/forms/OBSBasicSettings.ui +++ b/UI/forms/OBSBasicSettings.ui @@ -582,10 +582,44 @@ - + + + + + + + Basic.Settings.General.Multiview + + + + QFormLayout::AllNonFixedFieldsGrow + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 2 + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 170 + 5 + + + + + - + Basic.Settings.General.MultiviewLayout From e0e2cc57a0a775163705a274b059453abcf6b263 Mon Sep 17 00:00:00 2001 From: Shaolin Date: Fri, 16 Mar 2018 18:55:56 -0300 Subject: [PATCH 17/25] UI: Add option to toggle multiview mouse switching --- UI/data/locale/en-US.ini | 1 + UI/forms/OBSBasicSettings.ui | 10 ++++++++++ UI/obs-app.cpp | 3 +++ UI/window-basic-settings.cpp | 10 ++++++++++ UI/window-projector.cpp | 8 ++++++++ 5 files changed, 32 insertions(+) diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini index a048abf91..10f0bd03f 100644 --- a/UI/data/locale/en-US.ini +++ b/UI/data/locale/en-US.ini @@ -572,6 +572,7 @@ Basic.Settings.General.SaveProjectors="Save projectors on exit" Basic.Settings.General.SwitchOnDoubleClick="Transition to scene when double-clicked" Basic.Settings.General.StudioPortraitLayout="Enable portrait/vertical layout" Basic.Settings.General.Multiview="Multiview" +Basic.Settings.General.Multiview.MouseSwitch="Click to switch between scenes" Basic.Settings.General.MultiviewLayout="Multiview Layout" Basic.Settings.General.MultiviewLayout.Horizontal.Top="Horizontal, Top (8 Scenes)" Basic.Settings.General.MultiviewLayout.Horizontal.Bottom="Horizontal, Bottom (8 Scenes)" diff --git a/UI/forms/OBSBasicSettings.ui b/UI/forms/OBSBasicSettings.ui index 5a87b51bb..1406b29b9 100644 --- a/UI/forms/OBSBasicSettings.ui +++ b/UI/forms/OBSBasicSettings.ui @@ -616,6 +616,16 @@ + + + + Basic.Settings.General.Multiview.MouseSwitch + + + true + + + diff --git a/UI/obs-app.cpp b/UI/obs-app.cpp index 3eb576057..5a318e0c3 100644 --- a/UI/obs-app.cpp +++ b/UI/obs-app.cpp @@ -421,6 +421,9 @@ bool OBSApp::InitGlobalConfigDefaults() config_set_default_bool(globalConfig, "BasicWindow", "VerticalVolControl", false); + config_set_default_bool(globalConfig, "BasicWindow", + "MultiviewMouseSwitch", true); + #ifdef _WIN32 config_set_default_bool(globalConfig, "Audio", "DisableAudioDucking", true); diff --git a/UI/window-basic-settings.cpp b/UI/window-basic-settings.cpp index 3a0d626a3..506e74be0 100644 --- a/UI/window-basic-settings.cpp +++ b/UI/window-basic-settings.cpp @@ -318,6 +318,7 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent) HookWidget(ui->snapDistance, DSCROLL_CHANGED,GENERAL_CHANGED); HookWidget(ui->doubleClickSwitch, CHECK_CHANGED, GENERAL_CHANGED); HookWidget(ui->studioPortraitLayout, CHECK_CHANGED, GENERAL_CHANGED); + HookWidget(ui->multiviewMouseSwitch, CHECK_CHANGED, GENERAL_CHANGED); HookWidget(ui->multiviewLayout, COMBO_CHANGED, GENERAL_CHANGED); HookWidget(ui->outputMode, COMBO_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->streamType, COMBO_CHANGED, STREAM1_CHANGED); @@ -1100,6 +1101,10 @@ void OBSBasicSettings::LoadGeneralSettings() "BasicWindow", "StudioPortraitLayout"); ui->studioPortraitLayout->setChecked(studioPortraitLayout); + bool multiviewMouseSwitch = config_get_bool(GetGlobalConfig(), + "BasicWindow", "MultiviewMouseSwitch"); + ui->multiviewMouseSwitch->setChecked(multiviewMouseSwitch); + ui->multiviewLayout->addItem(QTStr( "Basic.Settings.General.MultiviewLayout.Horizontal.Top"), static_cast(MultiviewLayout::HORIZONTAL_TOP_8_SCENES)); @@ -2704,6 +2709,11 @@ void OBSBasicSettings::SaveGeneralSettings() main->ResetUI(); } + if (WidgetChanged(ui->multiviewMouseSwitch)) + config_set_bool(GetGlobalConfig(), "BasicWindow", + "MultiviewMouseSwitch", + ui->multiviewMouseSwitch->isChecked()); + if (WidgetChanged(ui->multiviewLayout)) { config_set_int(GetGlobalConfig(), "BasicWindow", "MultiviewLayout", diff --git a/UI/window-projector.cpp b/UI/window-projector.cpp index dc89f2543..9c3fad50f 100644 --- a/UI/window-projector.cpp +++ b/UI/window-projector.cpp @@ -751,6 +751,10 @@ void OBSProjector::mouseDoubleClickEvent(QMouseEvent *event) { OBSQTDisplay::mouseDoubleClickEvent(event); + if (!config_get_bool(GetGlobalConfig(), "BasicWindow", + "MultiviewMouseSwitch")) + return; + if (!config_get_bool(GetGlobalConfig(), "BasicWindow", "TransitionOnDoubleClick")) return; @@ -783,6 +787,10 @@ void OBSProjector::mousePressEvent(QMouseEvent *event) } if (event->button() == Qt::LeftButton) { + if (!config_get_bool(GetGlobalConfig(), "BasicWindow", + "MultiviewMouseSwitch")) + return; + int pos = getSourceByPosition(event->x(), event->y()); if (pos < 0) return; From 4649783b1e89c1b8be434b373ef76b4aab52e1c7 Mon Sep 17 00:00:00 2001 From: Shaolin Date: Fri, 16 Mar 2018 23:00:32 -0300 Subject: [PATCH 18/25] UI: Add option to toggle multiview scene names --- UI/data/locale/en-US.ini | 1 + UI/forms/OBSBasicSettings.ui | 12 ++++++++++- UI/obs-app.cpp | 3 +++ UI/window-basic-settings.cpp | 10 +++++++++ UI/window-projector.cpp | 42 +++++++++++++++++++++--------------- 5 files changed, 50 insertions(+), 18 deletions(-) diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini index 10f0bd03f..b46f1e686 100644 --- a/UI/data/locale/en-US.ini +++ b/UI/data/locale/en-US.ini @@ -573,6 +573,7 @@ Basic.Settings.General.SwitchOnDoubleClick="Transition to scene when double-clic Basic.Settings.General.StudioPortraitLayout="Enable portrait/vertical layout" Basic.Settings.General.Multiview="Multiview" Basic.Settings.General.Multiview.MouseSwitch="Click to switch between scenes" +Basic.Settings.General.Multiview.DrawSourceNames="Show scene names" Basic.Settings.General.MultiviewLayout="Multiview Layout" Basic.Settings.General.MultiviewLayout.Horizontal.Top="Horizontal, Top (8 Scenes)" Basic.Settings.General.MultiviewLayout.Horizontal.Bottom="Horizontal, Bottom (8 Scenes)" diff --git a/UI/forms/OBSBasicSettings.ui b/UI/forms/OBSBasicSettings.ui index 1406b29b9..6fbfe2a5f 100644 --- a/UI/forms/OBSBasicSettings.ui +++ b/UI/forms/OBSBasicSettings.ui @@ -627,9 +627,19 @@ + + + Basic.Settings.General.Multiview.DrawSourceNames + + + true + + + + - + Basic.Settings.General.MultiviewLayout diff --git a/UI/obs-app.cpp b/UI/obs-app.cpp index 5a318e0c3..22e6088b0 100644 --- a/UI/obs-app.cpp +++ b/UI/obs-app.cpp @@ -424,6 +424,9 @@ bool OBSApp::InitGlobalConfigDefaults() config_set_default_bool(globalConfig, "BasicWindow", "MultiviewMouseSwitch", true); + config_set_default_bool(globalConfig, "BasicWindow", + "MultiviewDrawNames", true); + #ifdef _WIN32 config_set_default_bool(globalConfig, "Audio", "DisableAudioDucking", true); diff --git a/UI/window-basic-settings.cpp b/UI/window-basic-settings.cpp index 506e74be0..639df4ae9 100644 --- a/UI/window-basic-settings.cpp +++ b/UI/window-basic-settings.cpp @@ -319,6 +319,7 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent) HookWidget(ui->doubleClickSwitch, CHECK_CHANGED, GENERAL_CHANGED); HookWidget(ui->studioPortraitLayout, CHECK_CHANGED, GENERAL_CHANGED); HookWidget(ui->multiviewMouseSwitch, CHECK_CHANGED, GENERAL_CHANGED); + HookWidget(ui->multiviewDrawNames, CHECK_CHANGED, GENERAL_CHANGED); HookWidget(ui->multiviewLayout, COMBO_CHANGED, GENERAL_CHANGED); HookWidget(ui->outputMode, COMBO_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->streamType, COMBO_CHANGED, STREAM1_CHANGED); @@ -1105,6 +1106,10 @@ void OBSBasicSettings::LoadGeneralSettings() "BasicWindow", "MultiviewMouseSwitch"); ui->multiviewMouseSwitch->setChecked(multiviewMouseSwitch); + bool multiviewDrawNames = config_get_bool(GetGlobalConfig(), + "BasicWindow", "MultiviewDrawNames"); + ui->multiviewDrawNames->setChecked(multiviewDrawNames); + ui->multiviewLayout->addItem(QTStr( "Basic.Settings.General.MultiviewLayout.Horizontal.Top"), static_cast(MultiviewLayout::HORIZONTAL_TOP_8_SCENES)); @@ -2714,6 +2719,11 @@ void OBSBasicSettings::SaveGeneralSettings() "MultiviewMouseSwitch", ui->multiviewMouseSwitch->isChecked()); + if (WidgetChanged(ui->multiviewDrawNames)) + config_set_bool(GetGlobalConfig(), "BasicWindow", + "MultiviewDrawNames", + ui->multiviewDrawNames->isChecked()); + if (WidgetChanged(ui->multiviewLayout)) { config_set_int(GetGlobalConfig(), "BasicWindow", "MultiviewLayout", diff --git a/UI/window-projector.cpp b/UI/window-projector.cpp index 9c3fad50f..94b89aa1e 100644 --- a/UI/window-projector.cpp +++ b/UI/window-projector.cpp @@ -494,7 +494,8 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) /* ----------- */ // Render the label - if (!label) + if (!label || !config_get_bool(GetGlobalConfig(), + "BasicWindow", "MultiviewDrawNames")) continue; offset = labelOffset(label, quarterCX); @@ -548,14 +549,17 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) /* ----------- */ // Draw the Label - gs_matrix_push(); - gs_matrix_translate3f(labelX, labelY, 0.0f); - gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f); - drawBox(obs_source_get_width(previewLabel), - obs_source_get_height(previewLabel) + - int(halfCX * 0.015f), labelColor); - obs_source_video_render(previewLabel); - gs_matrix_pop(); + if (config_get_bool(GetGlobalConfig(), "BasicWindow", + "MultiviewDrawNames")) { + gs_matrix_push(); + gs_matrix_translate3f(labelX, labelY, 0.0f); + gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f); + drawBox(obs_source_get_width(previewLabel), + obs_source_get_height(previewLabel) + + int(halfCX * 0.015f), labelColor); + obs_source_video_render(previewLabel); + gs_matrix_pop(); + } /* ----------------------------- */ /* draw program */ @@ -576,14 +580,18 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) /* ----------- */ // Draw the Label - gs_matrix_push(); - gs_matrix_translate3f(labelX, labelY, 0.0f); - gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f); - drawBox(obs_source_get_width(programLabel), - obs_source_get_height(programLabel) + - int(halfCX * 0.015f), labelColor); - obs_source_video_render(programLabel); - gs_matrix_pop(); + if (config_get_bool(GetGlobalConfig(), "BasicWindow", + "MultiviewDrawNames")) { + gs_matrix_push(); + gs_matrix_translate3f(labelX, labelY, 0.0f); + gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f); + drawBox(obs_source_get_width(programLabel), + obs_source_get_height(programLabel) + + int(halfCX * 0.015f), labelColor); + obs_source_video_render(programLabel); + gs_matrix_pop(); + } + endRegion(); } From 03de558af1946784cf74aa85a34ff05a26423b56 Mon Sep 17 00:00:00 2001 From: Shaolin Date: Sun, 18 Mar 2018 22:00:18 -0300 Subject: [PATCH 19/25] UI: Update multiview safe areas Make the safe areas respect the EBU R 95 and Rec. ITU-R BT.1848-1 standards for 16:9 content. Links: https://tech.ebu.ch/docs/r/r095rev1_March2016.pdf and https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.1848-1-201510-I!!PDF-E.pdf --- UI/window-projector.cpp | 55 +++++++++++++++++++++++++---------------- UI/window-projector.hpp | 17 ++++++++----- 2 files changed, 45 insertions(+), 27 deletions(-) diff --git a/UI/window-projector.cpp b/UI/window-projector.cpp index 94b89aa1e..f5febb479 100644 --- a/UI/window-projector.cpp +++ b/UI/window-projector.cpp @@ -82,37 +82,50 @@ OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, int monitor, if (type == ProjectorType::Multiview) { obs_enter_graphics(); + // All essential action should be placed inside this area 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_vertex2f(actionSafePercentage, actionSafePercentage); + gs_vertex2f(actionSafePercentage, 1 - actionSafePercentage); + gs_vertex2f(1 - actionSafePercentage, 1 - actionSafePercentage); + gs_vertex2f(1 - actionSafePercentage, actionSafePercentage); + gs_vertex2f(actionSafePercentage, actionSafePercentage); + actionSafeMargin = gs_render_save(); + // All graphics should be placed inside this area gs_render_start(true); - gs_vertex2f(0.15f, 0.04f); - gs_vertex2f(0.15f, 0.96f); - leftVLine = gs_render_save(); + gs_vertex2f(graphicsSafePercentage, graphicsSafePercentage); + gs_vertex2f(graphicsSafePercentage, 1 - graphicsSafePercentage); + gs_vertex2f(1 - graphicsSafePercentage, + 1 - graphicsSafePercentage); + gs_vertex2f(1 - graphicsSafePercentage, graphicsSafePercentage); + gs_vertex2f(graphicsSafePercentage, graphicsSafePercentage); + graphicsSafeMargin = gs_render_save(); + // 4:3 safe area for widescreen gs_render_start(true); - gs_vertex2f(0.85f, 0.04f); - gs_vertex2f(0.85f, 0.96f); - rightVLine = gs_render_save(); + gs_vertex2f(fourByThreeSafePercentage, graphicsSafePercentage); + gs_vertex2f(1 - fourByThreeSafePercentage, + graphicsSafePercentage); + gs_vertex2f(1 - fourByThreeSafePercentage, 1 - + graphicsSafePercentage); + gs_vertex2f(fourByThreeSafePercentage, + 1 - graphicsSafePercentage); + gs_vertex2f(fourByThreeSafePercentage, graphicsSafePercentage); + fourByThreeSafeMargin = gs_render_save(); gs_render_start(true); gs_vertex2f(0.0f, 0.5f); - gs_vertex2f(0.075f, 0.5f); + gs_vertex2f(lineLength, 0.5f); leftLine = gs_render_save(); gs_render_start(true); gs_vertex2f(0.5f, 0.0f); - gs_vertex2f(0.5f, 0.09f); + gs_vertex2f(0.5f, lineLength); topLine = gs_render_save(); gs_render_start(true); - gs_vertex2f(0.925f, 0.5f); gs_vertex2f(1.0f, 0.5f); + gs_vertex2f(1 - lineLength, 0.5f); rightLine = gs_render_save(); obs_leave_graphics(); @@ -152,9 +165,9 @@ OBSProjector::~OBSProjector() } obs_enter_graphics(); - gs_vertexbuffer_destroy(innerBox); - gs_vertexbuffer_destroy(leftVLine); - gs_vertexbuffer_destroy(rightVLine); + gs_vertexbuffer_destroy(actionSafeMargin); + gs_vertexbuffer_destroy(graphicsSafeMargin); + gs_vertexbuffer_destroy(fourByThreeSafeMargin); gs_vertexbuffer_destroy(leftLine); gs_vertexbuffer_destroy(topLine); gs_vertexbuffer_destroy(rightLine); @@ -537,9 +550,9 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) obs_source_video_render(previewSrc); else obs_render_main_texture(); - renderVB(window->innerBox, targetCX, targetCY, outerColor); - renderVB(window->leftVLine, targetCX, targetCY, outerColor); - renderVB(window->rightVLine, targetCX, targetCY, outerColor); + renderVB(window->actionSafeMargin, targetCX, targetCY, outerColor); + renderVB(window->graphicsSafeMargin, targetCX, targetCY, outerColor); + renderVB(window->fourByThreeSafeMargin, targetCX, targetCY, outerColor); renderVB(window->leftLine, targetCX, targetCY, outerColor); renderVB(window->topLine, targetCX, targetCY, outerColor); renderVB(window->rightLine, targetCX, targetCY, outerColor); diff --git a/UI/window-projector.hpp b/UI/window-projector.hpp index 9f932e266..46e5f1997 100644 --- a/UI/window-projector.hpp +++ b/UI/window-projector.hpp @@ -40,12 +40,17 @@ private: ProjectorType type = ProjectorType::Source; OBSWeakSource multiviewScenes[8]; OBSSource multiviewLabels[10]; - 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; + gs_vertbuffer_t *actionSafeMargin = nullptr; + gs_vertbuffer_t *graphicsSafeMargin = nullptr; + gs_vertbuffer_t *fourByThreeSafeMargin = nullptr; + gs_vertbuffer_t *leftLine = nullptr; + gs_vertbuffer_t *topLine = nullptr; + gs_vertbuffer_t *rightLine = nullptr; + float lineLength = 0.1f; + // Rec. ITU-R BT.1848-1 / EBU R 95 + float actionSafePercentage = 0.035f; // 3.5% + float graphicsSafePercentage = 0.05f; // 5.0% + float fourByThreeSafePercentage = 0.1625f; // 16.25% bool ready = false; // argb colors From b8966802efd97d084d35981086b8f6472f49b676 Mon Sep 17 00:00:00 2001 From: Shaolin Date: Sun, 18 Mar 2018 23:02:27 -0300 Subject: [PATCH 20/25] UI: Add option to toggle multiview draw safe area --- UI/data/locale/en-US.ini | 1 + UI/forms/OBSBasicSettings.ui | 12 +++++++++++- UI/obs-app.cpp | 3 +++ UI/window-basic-settings.cpp | 10 ++++++++++ UI/window-projector.cpp | 18 ++++++++++++------ 5 files changed, 37 insertions(+), 7 deletions(-) diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini index b46f1e686..0a2056640 100644 --- a/UI/data/locale/en-US.ini +++ b/UI/data/locale/en-US.ini @@ -574,6 +574,7 @@ Basic.Settings.General.StudioPortraitLayout="Enable portrait/vertical layout" Basic.Settings.General.Multiview="Multiview" Basic.Settings.General.Multiview.MouseSwitch="Click to switch between scenes" Basic.Settings.General.Multiview.DrawSourceNames="Show scene names" +Basic.Settings.General.Multiview.DrawSafeAreas="Draw safe areas (EBU R 95)" Basic.Settings.General.MultiviewLayout="Multiview Layout" Basic.Settings.General.MultiviewLayout.Horizontal.Top="Horizontal, Top (8 Scenes)" Basic.Settings.General.MultiviewLayout.Horizontal.Bottom="Horizontal, Bottom (8 Scenes)" diff --git a/UI/forms/OBSBasicSettings.ui b/UI/forms/OBSBasicSettings.ui index 6fbfe2a5f..8144f7ec4 100644 --- a/UI/forms/OBSBasicSettings.ui +++ b/UI/forms/OBSBasicSettings.ui @@ -637,9 +637,19 @@ + + + Basic.Settings.General.Multiview.DrawSafeAreas + + + true + + + + - + Basic.Settings.General.MultiviewLayout diff --git a/UI/obs-app.cpp b/UI/obs-app.cpp index 22e6088b0..2db37b583 100644 --- a/UI/obs-app.cpp +++ b/UI/obs-app.cpp @@ -427,6 +427,9 @@ bool OBSApp::InitGlobalConfigDefaults() config_set_default_bool(globalConfig, "BasicWindow", "MultiviewDrawNames", true); + config_set_default_bool(globalConfig, "BasicWindow", + "MultiviewDrawAreas", true); + #ifdef _WIN32 config_set_default_bool(globalConfig, "Audio", "DisableAudioDucking", true); diff --git a/UI/window-basic-settings.cpp b/UI/window-basic-settings.cpp index 639df4ae9..b433e47b1 100644 --- a/UI/window-basic-settings.cpp +++ b/UI/window-basic-settings.cpp @@ -320,6 +320,7 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent) HookWidget(ui->studioPortraitLayout, CHECK_CHANGED, GENERAL_CHANGED); HookWidget(ui->multiviewMouseSwitch, CHECK_CHANGED, GENERAL_CHANGED); HookWidget(ui->multiviewDrawNames, CHECK_CHANGED, GENERAL_CHANGED); + HookWidget(ui->multiviewDrawAreas, CHECK_CHANGED, GENERAL_CHANGED); HookWidget(ui->multiviewLayout, COMBO_CHANGED, GENERAL_CHANGED); HookWidget(ui->outputMode, COMBO_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->streamType, COMBO_CHANGED, STREAM1_CHANGED); @@ -1110,6 +1111,10 @@ void OBSBasicSettings::LoadGeneralSettings() "BasicWindow", "MultiviewDrawNames"); ui->multiviewDrawNames->setChecked(multiviewDrawNames); + bool multiviewDrawAreas = config_get_bool(GetGlobalConfig(), + "BasicWindow", "MultiviewDrawAreas"); + ui->multiviewDrawAreas->setChecked(multiviewDrawAreas); + ui->multiviewLayout->addItem(QTStr( "Basic.Settings.General.MultiviewLayout.Horizontal.Top"), static_cast(MultiviewLayout::HORIZONTAL_TOP_8_SCENES)); @@ -2724,6 +2729,11 @@ void OBSBasicSettings::SaveGeneralSettings() "MultiviewDrawNames", ui->multiviewDrawNames->isChecked()); + if (WidgetChanged(ui->multiviewDrawAreas)) + config_set_bool(GetGlobalConfig(), "BasicWindow", + "MultiviewDrawAreas", + ui->multiviewDrawAreas->isChecked()); + if (WidgetChanged(ui->multiviewLayout)) { config_set_int(GetGlobalConfig(), "BasicWindow", "MultiviewLayout", diff --git a/UI/window-projector.cpp b/UI/window-projector.cpp index f5febb479..2fa6dd606 100644 --- a/UI/window-projector.cpp +++ b/UI/window-projector.cpp @@ -550,12 +550,18 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) obs_source_video_render(previewSrc); else obs_render_main_texture(); - renderVB(window->actionSafeMargin, targetCX, targetCY, outerColor); - renderVB(window->graphicsSafeMargin, targetCX, targetCY, outerColor); - renderVB(window->fourByThreeSafeMargin, targetCX, targetCY, outerColor); - renderVB(window->leftLine, targetCX, targetCY, outerColor); - renderVB(window->topLine, targetCX, targetCY, outerColor); - renderVB(window->rightLine, targetCX, targetCY, outerColor); + if (config_get_bool(GetGlobalConfig(), "BasicWindow", + "MultiviewDrawAreas")) { + renderVB(window->actionSafeMargin, targetCX, targetCY, + outerColor); + renderVB(window->graphicsSafeMargin, targetCX, targetCY, + outerColor); + renderVB(window->fourByThreeSafeMargin, targetCX, targetCY, + outerColor); + renderVB(window->leftLine, targetCX, targetCY, outerColor); + renderVB(window->topLine, targetCX, targetCY, outerColor); + renderVB(window->rightLine, targetCX, targetCY, outerColor); + } endRegion(); gs_matrix_pop(); From 5b642c14def590282d42c2b4f8a0c6cbd9c6a04f Mon Sep 17 00:00:00 2001 From: Shaolin Date: Mon, 19 Mar 2018 23:27:44 -0300 Subject: [PATCH 21/25] UI: Move multiview setting checks from draw path --- UI/window-basic-settings.cpp | 19 +++++++++++---- UI/window-projector.cpp | 45 +++++++++++++++++++++--------------- 2 files changed, 41 insertions(+), 23 deletions(-) diff --git a/UI/window-basic-settings.cpp b/UI/window-basic-settings.cpp index b433e47b1..62ce43a66 100644 --- a/UI/window-basic-settings.cpp +++ b/UI/window-basic-settings.cpp @@ -2719,28 +2719,37 @@ void OBSBasicSettings::SaveGeneralSettings() main->ResetUI(); } - if (WidgetChanged(ui->multiviewMouseSwitch)) + bool multiviewChanged = false; + if (WidgetChanged(ui->multiviewMouseSwitch)) { config_set_bool(GetGlobalConfig(), "BasicWindow", "MultiviewMouseSwitch", ui->multiviewMouseSwitch->isChecked()); + multiviewChanged = true; + } - if (WidgetChanged(ui->multiviewDrawNames)) + if (WidgetChanged(ui->multiviewDrawNames)) { config_set_bool(GetGlobalConfig(), "BasicWindow", "MultiviewDrawNames", ui->multiviewDrawNames->isChecked()); + multiviewChanged = true; + } - if (WidgetChanged(ui->multiviewDrawAreas)) + if (WidgetChanged(ui->multiviewDrawAreas)) { config_set_bool(GetGlobalConfig(), "BasicWindow", "MultiviewDrawAreas", ui->multiviewDrawAreas->isChecked()); + multiviewChanged = true; + } if (WidgetChanged(ui->multiviewLayout)) { config_set_int(GetGlobalConfig(), "BasicWindow", "MultiviewLayout", ui->multiviewLayout->currentData().toInt()); - - OBSProjector::UpdateMultiviewProjectors(); + multiviewChanged = true; } + + if (multiviewChanged) + OBSProjector::UpdateMultiviewProjectors(); } void OBSBasicSettings::SaveStream1Settings() diff --git a/UI/window-projector.cpp b/UI/window-projector.cpp index 2fa6dd606..e3cb5df7e 100644 --- a/UI/window-projector.cpp +++ b/UI/window-projector.cpp @@ -11,7 +11,8 @@ static QList windowedProjectors; static QList multiviewProjectors; -static bool updatingMultiview = false; +static bool updatingMultiview = false, drawLabel, drawSafeArea, mouseSwitching, + transitionOnDoubleClick; static MultiviewLayout multiviewLayout; OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, int monitor, @@ -473,7 +474,6 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) for (size_t i = 0; i < 8; i++) { OBSSource src = OBSGetStrongRef(window->multiviewScenes[i]); - obs_source *label = window->multiviewLabels[i + 2]; // Handle all the offsets calcBaseSource(i); @@ -507,8 +507,11 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) /* ----------- */ // Render the label - if (!label || !config_get_bool(GetGlobalConfig(), - "BasicWindow", "MultiviewDrawNames")) + if (!drawLabel) + continue; + + obs_source *label = window->multiviewLabels[i + 2]; + if (!label) continue; offset = labelOffset(label, quarterCX); @@ -550,8 +553,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) obs_source_video_render(previewSrc); else obs_render_main_texture(); - if (config_get_bool(GetGlobalConfig(), "BasicWindow", - "MultiviewDrawAreas")) { + if (drawSafeArea) { renderVB(window->actionSafeMargin, targetCX, targetCY, outerColor); renderVB(window->graphicsSafeMargin, targetCX, targetCY, @@ -568,8 +570,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) /* ----------- */ // Draw the Label - if (config_get_bool(GetGlobalConfig(), "BasicWindow", - "MultiviewDrawNames")) { + if (drawLabel) { gs_matrix_push(); gs_matrix_translate3f(labelX, labelY, 0.0f); gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f); @@ -599,8 +600,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) /* ----------- */ // Draw the Label - if (config_get_bool(GetGlobalConfig(), "BasicWindow", - "MultiviewDrawNames")) { + if (drawLabel) { gs_matrix_push(); gs_matrix_translate3f(labelX, labelY, 0.0f); gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f); @@ -778,12 +778,10 @@ void OBSProjector::mouseDoubleClickEvent(QMouseEvent *event) { OBSQTDisplay::mouseDoubleClickEvent(event); - if (!config_get_bool(GetGlobalConfig(), "BasicWindow", - "MultiviewMouseSwitch")) + if (!mouseSwitching) return; - if (!config_get_bool(GetGlobalConfig(), "BasicWindow", - "TransitionOnDoubleClick")) + if (!transitionOnDoubleClick) return; OBSBasic *main = (OBSBasic*)obs_frontend_get_main_window(); @@ -813,11 +811,10 @@ void OBSProjector::mousePressEvent(QMouseEvent *event) popup.exec(QCursor::pos()); } - if (event->button() == Qt::LeftButton) { - if (!config_get_bool(GetGlobalConfig(), "BasicWindow", - "MultiviewMouseSwitch")) - return; + if (!mouseSwitching) + return; + if (event->button() == Qt::LeftButton) { int pos = getSourceByPosition(event->x(), event->y()); if (pos < 0) return; @@ -882,6 +879,18 @@ void OBSProjector::UpdateMultiview() multiviewLayout = static_cast(config_get_int( GetGlobalConfig(), "BasicWindow", "MultiviewLayout")); + + drawLabel = config_get_bool(GetGlobalConfig(), + "BasicWindow", "MultiviewDrawNames"); + + drawSafeArea = config_get_bool(GetGlobalConfig(), "BasicWindow", + "MultiviewDrawAreas"); + + mouseSwitching = config_get_bool(GetGlobalConfig(), "BasicWindow", + "MultiviewMouseSwitch"); + + transitionOnDoubleClick = config_get_bool(GetGlobalConfig(), + "BasicWindow", "TransitionOnDoubleClick"); } void OBSProjector::UpdateProjectorTitle(QString name) From abb929c0d1d3b441aa413bb97b2da2452cf340ff Mon Sep 17 00:00:00 2001 From: Shaolin Date: Tue, 20 Mar 2018 03:20:45 -0300 Subject: [PATCH 22/25] UI: Calculate fixed values of the Multiview once --- UI/window-projector.cpp | 300 ++++++++++++++++++++-------------------- UI/window-projector.hpp | 8 ++ 2 files changed, 158 insertions(+), 150 deletions(-) diff --git a/UI/window-projector.cpp b/UI/window-projector.cpp index e3cb5df7e..7b8dc0f48 100644 --- a/UI/window-projector.cpp +++ b/UI/window-projector.cpp @@ -130,6 +130,9 @@ OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, int monitor, rightLine = gs_render_save(); obs_leave_graphics(); + solid = obs_get_base_effect(OBS_EFFECT_SOLID); + color = gs_effect_get_param_by_name(solid, "color"); + UpdateMultiview(); multiviewProjectors.push_back(this); @@ -284,49 +287,24 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) return; OBSBasic *main = (OBSBasic *)obs_frontend_get_main_window(); - uint32_t thickness = 4; - uint32_t targetCX, targetCY, offset, thicknessx2 = thickness * 2; + uint32_t targetCX, targetCY; int x, y; - float fX, fY, halfCX, halfCY, sourceX, sourceY, labelX, labelY, - quarterCX, quarterCY, scale, targetCXF, targetCYF, - hiCX, hiCY, qiX, qiY, qiCX, qiCY, hiScaleX, hiScaleY, - qiScaleX, qiScaleY; - - gs_effect_t *solid = obs_get_base_effect(OBS_EFFECT_SOLID); - gs_eparam_t *color = gs_effect_get_param_by_name(solid, "color"); + float targetCXF, targetCYF, scale; struct obs_video_info ovi; obs_get_video_info(&ovi); targetCX = ovi.base_width; targetCY = ovi.base_height; + targetCXF = float(targetCX); + targetCYF = float(targetCY); GetScaleAndCenterPos(targetCX, targetCY, cx, cy, x, y, scale); - targetCXF = float(targetCX); - targetCYF = float(targetCY); - fX = float(x); - fY = float(y); - - halfCX = targetCXF / 2; - halfCY = targetCYF / 2; - hiCX = halfCX - thicknessx2; - hiCY = halfCY - thicknessx2; - hiScaleX = (halfCX - thicknessx2) / targetCXF; - hiScaleY = (halfCY - thicknessx2) / targetCYF; - - quarterCX = halfCX / 2; - quarterCY = halfCY / 2; - qiCX = quarterCX - thicknessx2; - qiCY = quarterCY - thicknessx2; - qiScaleX = (quarterCX - thicknessx2) / targetCXF; - qiScaleY = (quarterCY - thicknessx2) / targetCYF; - OBSSource previewSrc = main->GetCurrentSceneSource(); OBSSource programSrc = main->GetProgramSource(); - bool studioMode = main->IsPreviewProgramMode(); - auto renderVB = [solid, color](gs_vertbuffer_t *vb, int cx, int cy, + auto renderVB = [&](gs_vertbuffer_t *vb, int cx, int cy, uint32_t colorVal) { if (!vb) @@ -342,31 +320,32 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) gs_matrix_push(); gs_matrix_mul(&transform); - gs_effect_set_color(color, colorVal); - while (gs_effect_loop(solid, "Solid")) + gs_effect_set_color(window->color, colorVal); + while (gs_effect_loop(window->solid, "Solid")) gs_draw(GS_LINESTRIP, 0, 0); gs_matrix_pop(); }; - auto drawBox = [solid, color](float cx, float cy, uint32_t colorVal) + auto drawBox = [&](float cx, float cy, uint32_t colorVal) { - gs_effect_set_color(color, colorVal); - while (gs_effect_loop(solid, "Solid")) + gs_effect_set_color(window->color, colorVal); + while (gs_effect_loop(window->solid, "Solid")) gs_draw_sprite(nullptr, 0, (uint32_t)cx, (uint32_t)cy); }; - auto setRegion = [fX, fY, scale] (float x, float y, float cx, float cy) + auto setRegion = [&](float bx, float by, float cx, + float cy) { - float vX = int(fX + x * scale); - float vY = int(fY + y * scale); + float vX = int(x + bx * scale); + float vY = int(y + by * scale); float vCX = int(cx * scale); float vCY = int(cy * scale); - float oL = x; - float oT = y; - float oR = (x + cx); - float oB = (y + cy); + float oL = bx; + float oT = by; + float oR = (bx + cx); + float oB = (by + cy); startRegion(vX, vY, vCX, vCY, oL, oR, oT, oB); }; @@ -375,80 +354,81 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) { switch (multiviewLayout) { case MultiviewLayout::VERTICAL_LEFT_8_SCENES: - sourceX = halfCX; - sourceY = (i / 2 ) * quarterCY; + window->sourceX = window->halfCX; + window->sourceY = (i / 2 ) * window->quarterCY; if (i % 2 != 0) - sourceX += quarterCX; + window->sourceX += window->quarterCX; break; case MultiviewLayout::VERTICAL_RIGHT_8_SCENES: - sourceX = 0; - sourceY = (i / 2 ) * quarterCY; + window->sourceX = 0; + window->sourceY = (i / 2 ) * window->quarterCY; if (i % 2 != 0) - sourceX = quarterCX; + window->sourceX = window->quarterCX; break; case MultiviewLayout::HORIZONTAL_BOTTOM_8_SCENES: if (i < 4) { - sourceX = (float(i) * quarterCX); - sourceY = 0; + window->sourceX = (float(i) * window->quarterCX); + window->sourceY = 0; } else { - sourceX = (float(i - 4) * quarterCX); - sourceY = quarterCY; + window->sourceX = (float(i - 4) * window->quarterCX); + window->sourceY = window->quarterCY; } break; default: // MultiviewLayout::HORIZONTAL_TOP_8_SCENES: if (i < 4) { - sourceX = (float(i) * quarterCX); - sourceY = halfCY; + window->sourceX = (float(i) * window->quarterCX); + window->sourceY = window->halfCY; } else { - sourceX = (float(i - 4) * quarterCX); - sourceY = halfCY + quarterCY; + window->sourceX = (float(i - 4) * window->quarterCX); + window->sourceY = window->halfCY + + window->quarterCY; } } - qiX = sourceX + thickness; - qiY = sourceY + thickness; + window->qiX = window->sourceX + window->thickness; + window->qiY = window->sourceY + window->thickness; }; auto calcPreviewProgram = [&](bool program) { switch (multiviewLayout) { case MultiviewLayout::VERTICAL_LEFT_8_SCENES: - sourceX = thickness; - sourceY = halfCY + thickness; - labelX = offset; - labelY = halfCY * 1.85f; + window->sourceX = window->thickness; + window->sourceY = window->halfCY + window->thickness; + window->labelX = window->offset; + window->labelY = window->halfCY * 1.85f; if (program) { - sourceY = thickness; - labelY = halfCY * 0.85f; + window->sourceY = window->thickness; + window->labelY = window->halfCY * 0.85f; } break; case MultiviewLayout::VERTICAL_RIGHT_8_SCENES: - sourceX = halfCX + thickness; - sourceY = halfCY + thickness; - labelX = halfCX + offset; - labelY = halfCY * 1.85f; + window->sourceX = window->halfCX + window->thickness; + window->sourceY = window->halfCY + window->thickness; + window->labelX = window->halfCX + window->offset; + window->labelY = window->halfCY * 1.85f; if (program) { - sourceY = thickness; - labelY = halfCY * 0.85f; + window->sourceY = window->thickness; + window->labelY = window->halfCY * 0.85f; } break; case MultiviewLayout::HORIZONTAL_BOTTOM_8_SCENES: - sourceX = thickness; - sourceY = halfCY + thickness; - labelX = offset; - labelY = halfCY * 1.85f; + window->sourceX = window->thickness; + window->sourceY = window->halfCY + window->thickness; + window->labelX = window->offset; + window->labelY = window->halfCY * 1.85f; if (program) { - sourceX += halfCX; - labelX += halfCX; + window->sourceX += window->halfCX; + window->labelX += window->halfCX; } break; default: // MultiviewLayout::HORIZONTAL_TOP_8_SCENES: - sourceX = thickness; - sourceY = thickness; - labelX = offset; - labelY = halfCY * 0.85f; + window->sourceX = window->thickness; + window->sourceY = window->thickness; + window->labelX = window->offset; + window->labelY = window->halfCY * 0.85f; if (program) { - sourceX += halfCX; - labelX += halfCX; + window->sourceX += window->halfCX; + window->labelX += window->halfCX; } } }; @@ -478,77 +458,81 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) // Handle all the offsets calcBaseSource(i); - if (src) { - // Chose the proper highlight color - uint32_t colorVal = outerColor; - if (src == programSrc) - colorVal = programColor; - else if (src == previewSrc) - colorVal = studioMode ? previewColor - : programColor; - - // Paint the background - paintAreaWithColor(sourceX, sourceY, quarterCX, - quarterCY, colorVal); - paintAreaWithColor(qiX, qiY, qiCX, qiCY, - backgroundColor); - - /* ----------- */ - - // Render the source - gs_matrix_push(); - gs_matrix_translate3f(qiX, qiY, 0.0f); - gs_matrix_scale3f(qiScaleX, qiScaleY, 1.0f); - setRegion(qiX, qiY, qiCX, qiCY); - obs_source_video_render(src); - endRegion(); - gs_matrix_pop(); - - /* ----------- */ - - // Render the label - if (!drawLabel) - continue; - - obs_source *label = window->multiviewLabels[i + 2]; - if (!label) - continue; - - offset = labelOffset(label, quarterCX); - - gs_matrix_push(); - gs_matrix_translate3f(sourceX + offset, - (quarterCY * 0.85f) + sourceY, 0.0f); - gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f); - drawBox(obs_source_get_width(label), - obs_source_get_height(label) + - int(quarterCX * 0.015f), labelColor); - obs_source_video_render(label); - gs_matrix_pop(); - } else { - // Paint the background - paintAreaWithColor(sourceX, sourceY, quarterCX, - quarterCY, outerColor); - paintAreaWithColor(qiX, qiY, qiCX, qiCY, + if (!src) { + // Just paint the background and continue + paintAreaWithColor(window->sourceX, window->sourceY, + window->quarterCX, window->quarterCY, + outerColor); + paintAreaWithColor(window->qiX, window->qiY, + window->qiCX, window->qiCY, backgroundColor); + continue; } + + // We have a source. Now chose the proper highlight color + uint32_t colorVal = outerColor; + if (src == programSrc) + colorVal = programColor; + else if (src == previewSrc) + colorVal = studioMode ? previewColor : programColor; + + // Paint the background + paintAreaWithColor(window->sourceX, window->sourceY, + window->quarterCX, window->quarterCY, colorVal); + paintAreaWithColor(window->qiX, window->qiY, window->qiCX, + window->qiCY, backgroundColor); + + /* ----------- */ + + // Render the source + gs_matrix_push(); + gs_matrix_translate3f(window->qiX, window->qiY, 0.0f); + gs_matrix_scale3f(window->qiScaleX, window->qiScaleY, 1.0f); + setRegion(window->qiX, window->qiY, window->qiCX, window->qiCY); + obs_source_video_render(src); + endRegion(); + gs_matrix_pop(); + + /* ----------- */ + + // Render the label + if (!drawLabel) + continue; + + obs_source *label = window->multiviewLabels[i + 2]; + if (!label) + continue; + + window->offset = labelOffset(label, window->quarterCX); + + gs_matrix_push(); + gs_matrix_translate3f(window->sourceX + window->offset, + (window->quarterCY * 0.85f) + window->sourceY, + 0.0f); + gs_matrix_scale3f(window->hiScaleX, window->hiScaleY, 1.0f); + drawBox(obs_source_get_width(label), + obs_source_get_height(label) + + int(window->sourceY * 0.015f), labelColor); + obs_source_video_render(label); + gs_matrix_pop(); } /* ----------------------------- */ /* draw preview */ obs_source_t *previewLabel = window->multiviewLabels[0]; - offset = labelOffset(previewLabel, halfCX); + window->offset = labelOffset(previewLabel, window->halfCX); calcPreviewProgram(false); // Paint the background - paintAreaWithColor(sourceX, sourceY, hiCX, hiCY, backgroundColor); + paintAreaWithColor(window->sourceX, window->sourceY, window->hiCX, + window->hiCY, backgroundColor); // Scale and Draw the preview gs_matrix_push(); - gs_matrix_translate3f(sourceX, sourceY, 0.0f); - gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f); - setRegion(sourceX, sourceY, hiCX, hiCY); + gs_matrix_translate3f(window->sourceX, window->sourceY, 0.0f); + gs_matrix_scale3f(window->hiScaleX, window->hiScaleY, 1.0f); + setRegion(window->sourceX, window->sourceY, window->hiCX, window->hiCY); if (studioMode) obs_source_video_render(previewSrc); else @@ -572,11 +556,11 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) // Draw the Label if (drawLabel) { gs_matrix_push(); - gs_matrix_translate3f(labelX, labelY, 0.0f); - gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f); + gs_matrix_translate3f(window->labelX, window->labelY, 0.0f); + gs_matrix_scale3f(window->hiScaleX, window->hiScaleY, 1.0f); drawBox(obs_source_get_width(previewLabel), obs_source_get_height(previewLabel) + - int(halfCX * 0.015f), labelColor); + int(window->halfCX * 0.015f), labelColor); obs_source_video_render(previewLabel); gs_matrix_pop(); } @@ -585,14 +569,14 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) /* draw program */ obs_source_t *programLabel = window->multiviewLabels[1]; - offset = labelOffset(programLabel, halfCX); + window->offset = labelOffset(programLabel, window->halfCX); calcPreviewProgram(true); // Scale and Draw the program gs_matrix_push(); - gs_matrix_translate3f(sourceX, sourceY, 0.0f); - gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f); - setRegion(sourceX, sourceY, hiCX, hiCY); + gs_matrix_translate3f(window->sourceX, window->sourceY, 0.0f); + gs_matrix_scale3f(window->hiScaleX, window->hiScaleY, 1.0f); + setRegion(window->sourceX, window->sourceY, window->hiCX, window->hiCY); obs_render_main_texture(); endRegion(); gs_matrix_pop(); @@ -602,11 +586,11 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) // Draw the Label if (drawLabel) { gs_matrix_push(); - gs_matrix_translate3f(labelX, labelY, 0.0f); - gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f); + gs_matrix_translate3f(window->labelX, window->labelY, 0.0f); + gs_matrix_scale3f(window->hiScaleX, window->hiScaleY, 1.0f); drawBox(obs_source_get_width(programLabel), obs_source_get_height(programLabel) + - int(halfCX * 0.015f), labelColor); + int(window->halfCX * 0.015f), labelColor); obs_source_video_render(programLabel); gs_matrix_pop(); } @@ -843,7 +827,23 @@ void OBSProjector::UpdateMultiview() struct obs_video_info ovi; obs_get_video_info(&ovi); - uint32_t h = ovi.base_height; + uint32_t w = ovi.base_width; + uint32_t h = ovi.base_height; + float fw = float(w); + float fh = float(h); + halfCX = fw / 2; + halfCY = fh / 2; + hiCX = halfCX - thicknessx2; + hiCY = halfCY - thicknessx2; + hiScaleX = (halfCX - thicknessx2) / fw; + hiScaleY = (halfCY - thicknessx2) / fh; + + quarterCX = halfCX / 2; + quarterCY = halfCY / 2; + qiCX = quarterCX - thicknessx2; + qiCY = quarterCY - thicknessx2; + qiScaleX = (quarterCX - thicknessx2) / fw; + qiScaleY = (quarterCY - thicknessx2) / fh; struct obs_frontend_source_list scenes = {}; obs_frontend_get_scenes(&scenes); diff --git a/UI/window-projector.hpp b/UI/window-projector.hpp index 46e5f1997..58124412b 100644 --- a/UI/window-projector.hpp +++ b/UI/window-projector.hpp @@ -46,6 +46,14 @@ private: gs_vertbuffer_t *leftLine = nullptr; gs_vertbuffer_t *topLine = nullptr; gs_vertbuffer_t *rightLine = nullptr; + gs_effect_t *solid = nullptr; + gs_eparam_t *color = nullptr; + float thickness = 4; + float offset, thicknessx2 = thickness * 2, halfCX, + halfCY, sourceX, sourceY, labelX, labelY, quarterCX, quarterCY, + hiCX, hiCY, qiX, qiY, qiCX, qiCY, hiScaleX, hiScaleY, qiScaleX, + qiScaleY; + float lineLength = 0.1f; // Rec. ITU-R BT.1848-1 / EBU R 95 float actionSafePercentage = 0.035f; // 3.5% From 5921558548159be2e2dff8076f415be3a64d5910 Mon Sep 17 00:00:00 2001 From: Shaolin Date: Wed, 21 Mar 2018 00:16:42 -0300 Subject: [PATCH 23/25] UI: Adjust the multiview num sources by the layout The variable name changes were done with the intent to ease the abstraction of the scene, preview and program width/height size so its not related with the canvas size but directly related with our concept of scenes. --- UI/window-projector.cpp | 79 ++++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 36 deletions(-) diff --git a/UI/window-projector.cpp b/UI/window-projector.cpp index 7b8dc0f48..600a49ae3 100644 --- a/UI/window-projector.cpp +++ b/UI/window-projector.cpp @@ -14,6 +14,7 @@ static QList multiviewProjectors; static bool updatingMultiview = false, drawLabel, drawSafeArea, mouseSwitching, transitionOnDoubleClick; static MultiviewLayout multiviewLayout; +static size_t maxSrcs, numSrcs; OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, int monitor, QString title, ProjectorType type_) @@ -452,7 +453,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) /* ----------------------------- */ /* draw sources */ - for (size_t i = 0; i < 8; i++) { + for (size_t i = 0; i < numSrcs; i++) { OBSSource src = OBSGetStrongRef(window->multiviewScenes[i]); // Handle all the offsets @@ -673,22 +674,22 @@ static int getSourceByPosition(int x, int y) int minY = 0; int maxX = cx; int maxY = cy; - int halfX = cx / 2; - int halfY = cy / 2; + int pvwpgmX = cx / 2; + int pvwpgmY = cy / 2; int pos = -1; switch (multiviewLayout) { case MultiviewLayout::VERTICAL_LEFT_8_SCENES: if (float(cx) / float(cy) > ratio) { int validX = cy * ratio; - maxX = halfX + (validX / 2); + maxX = pvwpgmX + (validX / 2); } else { int validY = cx / ratio; - minY = halfY - (validY / 2); - maxY = halfY + (validY / 2); + minY = pvwpgmY - (validY / 2); + maxY = pvwpgmY + (validY / 2); } - minX = halfX; + minX = pvwpgmX; if (x < minX || x > maxX || y < minY || y > maxY) break; @@ -700,14 +701,14 @@ static int getSourceByPosition(int x, int y) case MultiviewLayout::VERTICAL_RIGHT_8_SCENES: if (float(cx) / float(cy) > ratio) { int validX = cy * ratio; - minX = halfX - (validX / 2); + minX = pvwpgmX - (validX / 2); } else { int validY = cx / ratio; - minY = halfY - (validY / 2); - maxY = halfY + (validY / 2); + minY = pvwpgmY - (validY / 2); + maxY = pvwpgmY + (validY / 2); } - maxX = halfX; + maxX = pvwpgmX; if (x < minX || x > maxX || y < minY || y > maxY) break; @@ -719,14 +720,14 @@ static int getSourceByPosition(int x, int y) case MultiviewLayout::HORIZONTAL_BOTTOM_8_SCENES: if (float(cx) / float(cy) > ratio) { int validX = cy * ratio; - minX = halfX - (validX / 2); - maxX = halfX + (validX / 2); + minX = pvwpgmX - (validX / 2); + maxX = pvwpgmX + (validX / 2); } else { int validY = cx / ratio; - minY = halfY - (validY / 2); + minY = pvwpgmY - (validY / 2); } - maxY = halfY; + maxY = pvwpgmY; if (x < minX || x > maxX || y < minY || y > maxY) break; @@ -738,14 +739,14 @@ static int getSourceByPosition(int x, int y) default: // MultiviewLayout::HORIZONTAL_TOP_8_SCENES if (float(cx) / float(cy) > ratio) { int validX = cy * ratio; - minX = halfX - (validX / 2); - maxX = halfX + (validX / 2); + minX = pvwpgmX - (validX / 2); + maxX = pvwpgmX + (validX / 2); } else { int validY = cx / ratio; - maxY = halfY + (validY / 2); + maxY = pvwpgmY + (validY / 2); } - minY = halfY; + minY = pvwpgmY; if (x < minX || x > maxX || y < minY || y > maxY) break; @@ -848,12 +849,32 @@ void OBSProjector::UpdateMultiview() struct obs_frontend_source_list scenes = {}; obs_frontend_get_scenes(&scenes); - int curIdx = 0; + size_t 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++) { + multiviewLayout = static_cast(config_get_int( + GetGlobalConfig(), "BasicWindow", "MultiviewLayout")); + + drawLabel = config_get_bool(GetGlobalConfig(), + "BasicWindow", "MultiviewDrawNames"); + + drawSafeArea = config_get_bool(GetGlobalConfig(), "BasicWindow", + "MultiviewDrawAreas"); + + mouseSwitching = config_get_bool(GetGlobalConfig(), "BasicWindow", + "MultiviewMouseSwitch"); + + transitionOnDoubleClick = config_get_bool(GetGlobalConfig(), + "BasicWindow", "TransitionOnDoubleClick"); + + switch(multiviewLayout) { + default: + maxSrcs = 8; + } + + for (size_t i = 0; i < scenes.sources.num && curIdx < maxSrcs; i++) { obs_source_t *src = scenes.sources.array[i]; OBSData data = obs_source_get_private_settings(src); obs_data_release(data); @@ -874,23 +895,9 @@ void OBSProjector::UpdateMultiview() curIdx++; } + numSrcs = curIdx; obs_frontend_source_list_free(&scenes); - - multiviewLayout = static_cast(config_get_int( - GetGlobalConfig(), "BasicWindow", "MultiviewLayout")); - - drawLabel = config_get_bool(GetGlobalConfig(), - "BasicWindow", "MultiviewDrawNames"); - - drawSafeArea = config_get_bool(GetGlobalConfig(), "BasicWindow", - "MultiviewDrawAreas"); - - mouseSwitching = config_get_bool(GetGlobalConfig(), "BasicWindow", - "MultiviewMouseSwitch"); - - transitionOnDoubleClick = config_get_bool(GetGlobalConfig(), - "BasicWindow", "TransitionOnDoubleClick"); } void OBSProjector::UpdateProjectorTitle(QString name) From b3a4051530ca4a553e35a9d324e79170595d7da8 Mon Sep 17 00:00:00 2001 From: Shaolin Date: Thu, 22 Mar 2018 22:07:59 -0300 Subject: [PATCH 24/25] UI: Move more fixed values to multiview update --- UI/window-projector.cpp | 31 ++++++++++++------------------- UI/window-projector.hpp | 3 ++- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/UI/window-projector.cpp b/UI/window-projector.cpp index 600a49ae3..66e14f2ad 100644 --- a/UI/window-projector.cpp +++ b/UI/window-projector.cpp @@ -290,14 +290,10 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) OBSBasic *main = (OBSBasic *)obs_frontend_get_main_window(); uint32_t targetCX, targetCY; int x, y; - float targetCXF, targetCYF, scale; + float scale; - struct obs_video_info ovi; - obs_get_video_info(&ovi); - targetCX = ovi.base_width; - targetCY = ovi.base_height; - targetCXF = float(targetCX); - targetCYF = float(targetCY); + targetCX = (uint32_t)window->fw; + targetCY = (uint32_t)window->fh; GetScaleAndCenterPos(targetCX, targetCY, cx, cy, x, y, scale); @@ -444,11 +440,11 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) }; // Define the whole usable region for the multiview - startRegion(x, y, targetCX * scale, targetCY * scale, 0.0f, targetCXF, - 0.0f, targetCYF); + startRegion(x, y, targetCX * scale, targetCY * scale, 0.0f, window->fw, + 0.0f, window->fh); // Change the background color to highlight all sources - drawBox(targetCXF, targetCYF, outerColor); + drawBox(window->fw, window->fh, outerColor); /* ----------------------------- */ /* draw sources */ @@ -661,12 +657,8 @@ void OBSProjector::OBSSourceRemoved(void *data, calldata_t *params) UNUSED_PARAMETER(params); } -static int getSourceByPosition(int x, int y) +static int getSourceByPosition(int x, int y, float ratio) { - struct obs_video_info ovi; - obs_get_video_info(&ovi); - float ratio = float(ovi.base_width) / float(ovi.base_height); - QWidget *rec = QApplication::activeWindow(); int cx = rec->width(); int cy = rec->height(); @@ -774,7 +766,7 @@ void OBSProjector::mouseDoubleClickEvent(QMouseEvent *event) return; if (event->button() == Qt::LeftButton) { - int pos = getSourceByPosition(event->x(), event->y()); + int pos = getSourceByPosition(event->x(), event->y(), ratio); if (pos < 0) return; OBSSource src = OBSGetStrongRef(multiviewScenes[pos]); @@ -800,7 +792,7 @@ void OBSProjector::mousePressEvent(QMouseEvent *event) return; if (event->button() == Qt::LeftButton) { - int pos = getSourceByPosition(event->x(), event->y()); + int pos = getSourceByPosition(event->x(), event->y(), ratio); if (pos < 0) return; OBSSource src = OBSGetStrongRef(multiviewScenes[pos]); @@ -830,8 +822,9 @@ void OBSProjector::UpdateMultiview() uint32_t w = ovi.base_width; uint32_t h = ovi.base_height; - float fw = float(w); - float fh = float(h); + fw = float(w); + fh = float(h); + ratio = fw / fh; halfCX = fw / 2; halfCY = fh / 2; hiCX = halfCX - thicknessx2; diff --git a/UI/window-projector.hpp b/UI/window-projector.hpp index 58124412b..4560cac13 100644 --- a/UI/window-projector.hpp +++ b/UI/window-projector.hpp @@ -48,11 +48,12 @@ private: gs_vertbuffer_t *rightLine = nullptr; gs_effect_t *solid = nullptr; gs_eparam_t *color = nullptr; + // Multiview position helpers float thickness = 4; float offset, thicknessx2 = thickness * 2, halfCX, halfCY, sourceX, sourceY, labelX, labelY, quarterCX, quarterCY, hiCX, hiCY, qiX, qiY, qiCX, qiCY, hiScaleX, hiScaleY, qiScaleX, - qiScaleY; + qiScaleY, fw, fh, ratio; float lineLength = 0.1f; // Rec. ITU-R BT.1848-1 / EBU R 95 From c145b129f33736dd81b9a67f1d52d52de6c58449 Mon Sep 17 00:00:00 2001 From: Shaolin Date: Fri, 23 Mar 2018 00:57:15 -0300 Subject: [PATCH 25/25] UI: Add new Multiview Layout for up to 24 scenes The variable name changes were done with the intent to ease the abstraction of the scene, preview and program width/height size so its not related with the canvas size but directly related with our concept of scenes. --- UI/data/locale/en-US.ini | 1 + UI/window-basic-settings.cpp | 3 + UI/window-projector.cpp | 289 +++++++++++++++++++++-------------- UI/window-projector.hpp | 15 +- 4 files changed, 185 insertions(+), 123 deletions(-) diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini index 0a2056640..162a09085 100644 --- a/UI/data/locale/en-US.ini +++ b/UI/data/locale/en-US.ini @@ -580,6 +580,7 @@ Basic.Settings.General.MultiviewLayout.Horizontal.Top="Horizontal, Top (8 Scenes Basic.Settings.General.MultiviewLayout.Horizontal.Bottom="Horizontal, Bottom (8 Scenes)" Basic.Settings.General.MultiviewLayout.Vertical.Left="Vertical, Left (8 Scenes)" Basic.Settings.General.MultiviewLayout.Vertical.Right="Vertical, Right (8 Scenes)" +Basic.Settings.General.MultiviewLayout.Horizontal.Extended.Top="Horizontal, Top (24 Scenes)" # basic mode 'stream' settings Basic.Settings.Stream="Stream" diff --git a/UI/window-basic-settings.cpp b/UI/window-basic-settings.cpp index 62ce43a66..e9cfc00f6 100644 --- a/UI/window-basic-settings.cpp +++ b/UI/window-basic-settings.cpp @@ -1127,6 +1127,9 @@ void OBSBasicSettings::LoadGeneralSettings() ui->multiviewLayout->addItem(QTStr( "Basic.Settings.General.MultiviewLayout.Vertical.Right"), static_cast(MultiviewLayout::VERTICAL_RIGHT_8_SCENES)); + ui->multiviewLayout->addItem(QTStr( + "Basic.Settings.General.MultiviewLayout.Horizontal.Extended.Top"), + static_cast(MultiviewLayout::HORIZONTAL_TOP_24_SCENES)); ui->multiviewLayout->setCurrentIndex( config_get_int(GetGlobalConfig(), "BasicWindow", diff --git a/UI/window-projector.cpp b/UI/window-projector.cpp index 66e14f2ad..ec46449b7 100644 --- a/UI/window-projector.cpp +++ b/UI/window-projector.cpp @@ -256,6 +256,9 @@ static inline uint32_t labelOffset(obs_source_t *label, uint32_t cx) int n; // Number of scenes per row switch (multiviewLayout) { + case MultiviewLayout::HORIZONTAL_TOP_24_SCENES: + n = 6; + break; default: n = 4; break; @@ -350,82 +353,100 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) auto calcBaseSource = [&](size_t i) { switch (multiviewLayout) { + case MultiviewLayout::HORIZONTAL_TOP_24_SCENES: + window->sourceX = (i % 6) * window->scenesCX; + window->sourceY = window->pvwprgCY + + (i / 6) * window->scenesCY; + break; case MultiviewLayout::VERTICAL_LEFT_8_SCENES: - window->sourceX = window->halfCX; - window->sourceY = (i / 2 ) * window->quarterCY; + window->sourceX = window->pvwprgCX; + window->sourceY = (i / 2 ) * window->scenesCY; if (i % 2 != 0) - window->sourceX += window->quarterCX; + window->sourceX += window->scenesCX; break; case MultiviewLayout::VERTICAL_RIGHT_8_SCENES: window->sourceX = 0; - window->sourceY = (i / 2 ) * window->quarterCY; + window->sourceY = (i / 2 ) * window->scenesCY; if (i % 2 != 0) - window->sourceX = window->quarterCX; + window->sourceX = window->scenesCX; break; case MultiviewLayout::HORIZONTAL_BOTTOM_8_SCENES: if (i < 4) { - window->sourceX = (float(i) * window->quarterCX); + window->sourceX = (float(i) * window->scenesCX); window->sourceY = 0; } else { - window->sourceX = (float(i - 4) * window->quarterCX); - window->sourceY = window->quarterCY; + window->sourceX = (float(i - 4) * + window->scenesCX); + window->sourceY = window->scenesCY; } break; default: // MultiviewLayout::HORIZONTAL_TOP_8_SCENES: if (i < 4) { - window->sourceX = (float(i) * window->quarterCX); - window->sourceY = window->halfCY; + window->sourceX = (float(i) * window->scenesCX); + window->sourceY = window->pvwprgCY; } else { - window->sourceX = (float(i - 4) * window->quarterCX); - window->sourceY = window->halfCY + - window->quarterCY; + window->sourceX = (float(i - 4) * + window->scenesCX); + window->sourceY = window->pvwprgCY + + window->scenesCY; } } - window->qiX = window->sourceX + window->thickness; - window->qiY = window->sourceY + window->thickness; + window->siX = window->sourceX + window->thickness; + window->siY = window->sourceY + window->thickness; }; auto calcPreviewProgram = [&](bool program) { switch (multiviewLayout) { + case MultiviewLayout::HORIZONTAL_TOP_24_SCENES: + window->sourceX = window->thickness + + window->pvwprgCX / 2; + window->sourceY = window->thickness; + window->labelX = window->offset + window->pvwprgCX / 2; + window->labelY = window->pvwprgCY * 0.85f; + if (program) { + window->sourceX += window->pvwprgCX; + window->labelX += window->pvwprgCX; + } + break; case MultiviewLayout::VERTICAL_LEFT_8_SCENES: window->sourceX = window->thickness; - window->sourceY = window->halfCY + window->thickness; + window->sourceY = window->pvwprgCY + window->thickness; window->labelX = window->offset; - window->labelY = window->halfCY * 1.85f; + window->labelY = window->pvwprgCY * 1.85f; if (program) { window->sourceY = window->thickness; - window->labelY = window->halfCY * 0.85f; + window->labelY = window->pvwprgCY * 0.85f; } break; case MultiviewLayout::VERTICAL_RIGHT_8_SCENES: - window->sourceX = window->halfCX + window->thickness; - window->sourceY = window->halfCY + window->thickness; - window->labelX = window->halfCX + window->offset; - window->labelY = window->halfCY * 1.85f; + window->sourceX = window->pvwprgCX + window->thickness; + window->sourceY = window->pvwprgCY + window->thickness; + window->labelX = window->pvwprgCX + window->offset; + window->labelY = window->pvwprgCY * 1.85f; if (program) { window->sourceY = window->thickness; - window->labelY = window->halfCY * 0.85f; + window->labelY = window->pvwprgCY * 0.85f; } break; case MultiviewLayout::HORIZONTAL_BOTTOM_8_SCENES: window->sourceX = window->thickness; - window->sourceY = window->halfCY + window->thickness; + window->sourceY = window->pvwprgCY + window->thickness; window->labelX = window->offset; - window->labelY = window->halfCY * 1.85f; + window->labelY = window->pvwprgCY * 1.85f; if (program) { - window->sourceX += window->halfCX; - window->labelX += window->halfCX; + window->sourceX += window->pvwprgCX; + window->labelX += window->pvwprgCX; } break; default: // MultiviewLayout::HORIZONTAL_TOP_8_SCENES: window->sourceX = window->thickness; window->sourceY = window->thickness; window->labelX = window->offset; - window->labelY = window->halfCY * 0.85f; + window->labelY = window->pvwprgCY * 0.85f; if (program) { - window->sourceX += window->halfCX; - window->labelX += window->halfCX; + window->sourceX += window->pvwprgCX; + window->labelX += window->pvwprgCX; } } }; @@ -449,23 +470,23 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) /* ----------------------------- */ /* draw sources */ - for (size_t i = 0; i < numSrcs; i++) { - OBSSource src = OBSGetStrongRef(window->multiviewScenes[i]); - + for (size_t i = 0; i < maxSrcs; i++) { // Handle all the offsets calcBaseSource(i); - if (!src) { + if (i >= numSrcs) { // Just paint the background and continue paintAreaWithColor(window->sourceX, window->sourceY, - window->quarterCX, window->quarterCY, + window->scenesCX, window->scenesCY, outerColor); - paintAreaWithColor(window->qiX, window->qiY, - window->qiCX, window->qiCY, + paintAreaWithColor(window->siX, window->siY, + window->siCX, window->siCY, backgroundColor); continue; } + OBSSource src = OBSGetStrongRef(window->multiviewScenes[i]); + // We have a source. Now chose the proper highlight color uint32_t colorVal = outerColor; if (src == programSrc) @@ -475,17 +496,17 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) // Paint the background paintAreaWithColor(window->sourceX, window->sourceY, - window->quarterCX, window->quarterCY, colorVal); - paintAreaWithColor(window->qiX, window->qiY, window->qiCX, - window->qiCY, backgroundColor); + window->scenesCX, window->scenesCY, colorVal); + paintAreaWithColor(window->siX, window->siY, window->siCX, + window->siCY, backgroundColor); /* ----------- */ // Render the source gs_matrix_push(); - gs_matrix_translate3f(window->qiX, window->qiY, 0.0f); - gs_matrix_scale3f(window->qiScaleX, window->qiScaleY, 1.0f); - setRegion(window->qiX, window->qiY, window->qiCX, window->qiCY); + gs_matrix_translate3f(window->siX, window->siY, 0.0f); + gs_matrix_scale3f(window->siScaleX, window->siScaleY, 1.0f); + setRegion(window->siX, window->siY, window->siCX, window->siCY); obs_source_video_render(src); endRegion(); gs_matrix_pop(); @@ -500,13 +521,13 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) if (!label) continue; - window->offset = labelOffset(label, window->quarterCX); + window->offset = labelOffset(label, window->scenesCX); gs_matrix_push(); gs_matrix_translate3f(window->sourceX + window->offset, - (window->quarterCY * 0.85f) + window->sourceY, + (window->scenesCY * 0.85f) + window->sourceY, 0.0f); - gs_matrix_scale3f(window->hiScaleX, window->hiScaleY, 1.0f); + gs_matrix_scale3f(window->ppiScaleX, window->ppiScaleY, 1.0f); drawBox(obs_source_get_width(label), obs_source_get_height(label) + int(window->sourceY * 0.015f), labelColor); @@ -518,18 +539,19 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) /* draw preview */ obs_source_t *previewLabel = window->multiviewLabels[0]; - window->offset = labelOffset(previewLabel, window->halfCX); + window->offset = labelOffset(previewLabel, window->pvwprgCX); calcPreviewProgram(false); // Paint the background - paintAreaWithColor(window->sourceX, window->sourceY, window->hiCX, - window->hiCY, backgroundColor); + paintAreaWithColor(window->sourceX, window->sourceY, window->ppiCX, + window->ppiCY, backgroundColor); // Scale and Draw the preview gs_matrix_push(); gs_matrix_translate3f(window->sourceX, window->sourceY, 0.0f); - gs_matrix_scale3f(window->hiScaleX, window->hiScaleY, 1.0f); - setRegion(window->sourceX, window->sourceY, window->hiCX, window->hiCY); + gs_matrix_scale3f(window->ppiScaleX, window->ppiScaleY, 1.0f); + setRegion(window->sourceX, window->sourceY, window->ppiCX, + window->ppiCY); if (studioMode) obs_source_video_render(previewSrc); else @@ -554,10 +576,10 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) if (drawLabel) { gs_matrix_push(); gs_matrix_translate3f(window->labelX, window->labelY, 0.0f); - gs_matrix_scale3f(window->hiScaleX, window->hiScaleY, 1.0f); + gs_matrix_scale3f(window->ppiScaleX, window->ppiScaleY, 1.0f); drawBox(obs_source_get_width(previewLabel), obs_source_get_height(previewLabel) + - int(window->halfCX * 0.015f), labelColor); + int(window->pvwprgCX * 0.015f), labelColor); obs_source_video_render(previewLabel); gs_matrix_pop(); } @@ -566,14 +588,15 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) /* draw program */ obs_source_t *programLabel = window->multiviewLabels[1]; - window->offset = labelOffset(programLabel, window->halfCX); + window->offset = labelOffset(programLabel, window->pvwprgCX); calcPreviewProgram(true); // Scale and Draw the program gs_matrix_push(); gs_matrix_translate3f(window->sourceX, window->sourceY, 0.0f); - gs_matrix_scale3f(window->hiScaleX, window->hiScaleY, 1.0f); - setRegion(window->sourceX, window->sourceY, window->hiCX, window->hiCY); + gs_matrix_scale3f(window->ppiScaleX, window->ppiScaleY, 1.0f); + setRegion(window->sourceX, window->sourceY, window->ppiCX, + window->ppiCY); obs_render_main_texture(); endRegion(); gs_matrix_pop(); @@ -584,14 +607,27 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy) if (drawLabel) { gs_matrix_push(); gs_matrix_translate3f(window->labelX, window->labelY, 0.0f); - gs_matrix_scale3f(window->hiScaleX, window->hiScaleY, 1.0f); + gs_matrix_scale3f(window->ppiScaleX, window->ppiScaleY, 1.0f); drawBox(obs_source_get_width(programLabel), obs_source_get_height(programLabel) + - int(window->halfCX * 0.015f), labelColor); + int(window->pvwprgCX * 0.015f), labelColor); obs_source_video_render(programLabel); gs_matrix_pop(); } + // Region for future usage with aditional info. + if (multiviewLayout == MultiviewLayout::HORIZONTAL_TOP_24_SCENES) { + // Just paint the background for now + paintAreaWithColor(window->thickness, window->thickness, + window->siCX, window->siCY * 2 + + window->thicknessx2, backgroundColor); + paintAreaWithColor(window->thickness + 2.5 * ( + window->thicknessx2 + window->ppiCX), + window->thickness, window->siCX, + window->siCY * 2 + window->thicknessx2, + backgroundColor); + } + endRegion(); } @@ -666,22 +702,39 @@ static int getSourceByPosition(int x, int y, float ratio) int minY = 0; int maxX = cx; int maxY = cy; - int pvwpgmX = cx / 2; - int pvwpgmY = cy / 2; int pos = -1; switch (multiviewLayout) { + case MultiviewLayout::HORIZONTAL_TOP_24_SCENES: + if (float(cx) / float(cy) > ratio) { + int validX = cy * ratio; + minX = (cx / 2) - (validX / 2); + maxX = (cx / 2) + (validX / 2); + minY = cy / 3; + } else { + int validY = cx / ratio; + maxY = (cy / 2) + (validY / 2); + minY = (cy / 2) - (validY / 6); + } + + if (x < minX || x > maxX || y < minY || y > maxY) + break; + + pos = (x - minX) / ((maxX - minX) / 6); + pos += ((y - minY) / ((maxY - minY) / 4)) * 6; + + break; case MultiviewLayout::VERTICAL_LEFT_8_SCENES: if (float(cx) / float(cy) > ratio) { int validX = cy * ratio; - maxX = pvwpgmX + (validX / 2); + maxX = (cx / 2) + (validX / 2); } else { int validY = cx / ratio; - minY = pvwpgmY - (validY / 2); - maxY = pvwpgmY + (validY / 2); + minY = (cy / 2) - (validY / 2); + maxY = (cy / 2) + (validY / 2); } - minX = pvwpgmX; + minX = cx / 2; if (x < minX || x > maxX || y < minY || y > maxY) break; @@ -693,14 +746,14 @@ static int getSourceByPosition(int x, int y, float ratio) case MultiviewLayout::VERTICAL_RIGHT_8_SCENES: if (float(cx) / float(cy) > ratio) { int validX = cy * ratio; - minX = pvwpgmX - (validX / 2); + minX = (cx / 2) - (validX / 2); } else { int validY = cx / ratio; - minY = pvwpgmY - (validY / 2); - maxY = pvwpgmY + (validY / 2); + minY = (cy / 2) - (validY / 2); + maxY = (cy / 2) + (validY / 2); } - maxX = pvwpgmX; + maxX = (cx / 2); if (x < minX || x > maxX || y < minY || y > maxY) break; @@ -712,14 +765,14 @@ static int getSourceByPosition(int x, int y, float ratio) case MultiviewLayout::HORIZONTAL_BOTTOM_8_SCENES: if (float(cx) / float(cy) > ratio) { int validX = cy * ratio; - minX = pvwpgmX - (validX / 2); - maxX = pvwpgmX + (validX / 2); + minX = (cx / 2) - (validX / 2); + maxX = (cx / 2) + (validX / 2); } else { int validY = cx / ratio; - minY = pvwpgmY - (validY / 2); + minY = (cy / 2) - (validY / 2); } - maxY = pvwpgmY; + maxY = (cy / 2); if (x < minX || x > maxX || y < minY || y > maxY) break; @@ -731,14 +784,14 @@ static int getSourceByPosition(int x, int y, float ratio) default: // MultiviewLayout::HORIZONTAL_TOP_8_SCENES if (float(cx) / float(cy) > ratio) { int validX = cy * ratio; - minX = pvwpgmX - (validX / 2); - maxX = pvwpgmX + (validX / 2); + minX = (cx / 2) - (validX / 2); + maxX = (cx / 2) + (validX / 2); } else { int validY = cx / ratio; - maxY = pvwpgmY + (validY / 2); + maxY = (cy / 2) + (validY / 2); } - minY = pvwpgmY; + minY = (cy / 2); if (x < minX || x > maxX || y < minY || y > maxY) break; @@ -767,7 +820,7 @@ void OBSProjector::mouseDoubleClickEvent(QMouseEvent *event) if (event->button() == Qt::LeftButton) { int pos = getSourceByPosition(event->x(), event->y(), ratio); - if (pos < 0) + if (pos < 0 || pos >= (int)numSrcs) return; OBSSource src = OBSGetStrongRef(multiviewScenes[pos]); if (!src) @@ -793,7 +846,7 @@ void OBSProjector::mousePressEvent(QMouseEvent *event) if (event->button() == Qt::LeftButton) { int pos = getSourceByPosition(event->x(), event->y(), ratio); - if (pos < 0) + if (pos < 0 || pos >= (int)numSrcs) return; OBSSource src = OBSGetStrongRef(multiviewScenes[pos]); if (!src) @@ -812,40 +865,25 @@ void OBSProjector::EscapeTriggered() void OBSProjector::UpdateMultiview() { - for (OBSWeakSource &val : multiviewScenes) - val = nullptr; - for (OBSSource &val : multiviewLabels) - val = nullptr; + multiviewScenes.clear(); + multiviewLabels.clear(); struct obs_video_info ovi; obs_get_video_info(&ovi); uint32_t w = ovi.base_width; uint32_t h = ovi.base_height; - fw = float(w); - fh = float(h); - ratio = fw / fh; - halfCX = fw / 2; - halfCY = fh / 2; - hiCX = halfCX - thicknessx2; - hiCY = halfCY - thicknessx2; - hiScaleX = (halfCX - thicknessx2) / fw; - hiScaleY = (halfCY - thicknessx2) / fh; - - quarterCX = halfCX / 2; - quarterCY = halfCY / 2; - qiCX = quarterCX - thicknessx2; - qiCY = quarterCY - thicknessx2; - qiScaleX = (quarterCX - thicknessx2) / fw; - qiScaleY = (quarterCY - thicknessx2) / fh; + fw = float(w); + fh = float(h); + ratio = fw / fh; struct obs_frontend_source_list scenes = {}; obs_frontend_get_scenes(&scenes); - size_t curIdx = 0; - - multiviewLabels[0] = CreateLabel(Str("StudioMode.Preview"), h / 2); - multiviewLabels[1] = CreateLabel(Str("StudioMode.Program"), h / 2); + multiviewLabels.emplace_back(CreateLabel(Str("StudioMode.Preview"), + h / 2)); + multiviewLabels.emplace_back(CreateLabel(Str("StudioMode.Program"), + h / 2)); multiviewLayout = static_cast(config_get_int( GetGlobalConfig(), "BasicWindow", "MultiviewLayout")); @@ -863,12 +901,34 @@ void OBSProjector::UpdateMultiview() "BasicWindow", "TransitionOnDoubleClick"); switch(multiviewLayout) { - default: - maxSrcs = 8; + case MultiviewLayout::HORIZONTAL_TOP_24_SCENES: + pvwprgCX = fw / 3; + pvwprgCY = fh / 3; + + maxSrcs = 24; + break; + default: + pvwprgCX = fw / 2; + pvwprgCY = fh / 2; + + maxSrcs = 8; } - for (size_t i = 0; i < scenes.sources.num && curIdx < maxSrcs; i++) { - obs_source_t *src = scenes.sources.array[i]; + ppiCX = pvwprgCX - thicknessx2; + ppiCY = pvwprgCY - thicknessx2; + ppiScaleX = (pvwprgCX - thicknessx2) / fw; + ppiScaleY = (pvwprgCY - thicknessx2) / fh; + + scenesCX = pvwprgCX / 2; + scenesCY = pvwprgCY / 2; + siCX = scenesCX - thicknessx2; + siCY = scenesCY - thicknessx2; + siScaleX = (scenesCX - thicknessx2) / fw; + siScaleY = (scenesCY - thicknessx2) / fh; + + numSrcs = 0; + while (numSrcs < scenes.sources.num && numSrcs < maxSrcs) { + obs_source_t *src = scenes.sources.array[numSrcs]; OBSData data = obs_source_get_private_settings(src); obs_data_release(data); @@ -876,19 +936,16 @@ void OBSProjector::UpdateMultiview() if (!obs_data_get_bool(data, "show_in_multiview")) continue; - multiviewScenes[curIdx] = OBSGetWeakRef(src); + // We have a displayable source. + numSrcs++; + + multiviewScenes.emplace_back(OBSGetWeakRef(src)); obs_source_inc_showing(src); - std::string name; - name += std::to_string(curIdx + 1); - name += " - "; - name += obs_source_get_name(src); - - multiviewLabels[curIdx + 2] = CreateLabel(name.c_str(), h / 3); - - curIdx++; + std::string name = std::to_string(numSrcs) + " - " + + obs_source_get_name(src); + multiviewLabels.emplace_back(CreateLabel(name.c_str(), h / 3)); } - numSrcs = curIdx; obs_frontend_source_list_free(&scenes); } diff --git a/UI/window-projector.hpp b/UI/window-projector.hpp index 4560cac13..1ec629d65 100644 --- a/UI/window-projector.hpp +++ b/UI/window-projector.hpp @@ -17,7 +17,8 @@ enum class MultiviewLayout : uint8_t { HORIZONTAL_TOP_8_SCENES = 0, HORIZONTAL_BOTTOM_8_SCENES = 1, VERTICAL_LEFT_8_SCENES = 2, - VERTICAL_RIGHT_8_SCENES = 3 + VERTICAL_RIGHT_8_SCENES = 3, + HORIZONTAL_TOP_24_SCENES = 4 }; class OBSProjector : public OBSQTDisplay { @@ -38,8 +39,8 @@ private: bool isWindow; QString projectorTitle; ProjectorType type = ProjectorType::Source; - OBSWeakSource multiviewScenes[8]; - OBSSource multiviewLabels[10]; + std::vector multiviewScenes; + std::vector multiviewLabels; gs_vertbuffer_t *actionSafeMargin = nullptr; gs_vertbuffer_t *graphicsSafeMargin = nullptr; gs_vertbuffer_t *fourByThreeSafeMargin = nullptr; @@ -50,10 +51,10 @@ private: gs_eparam_t *color = nullptr; // Multiview position helpers float thickness = 4; - float offset, thicknessx2 = thickness * 2, halfCX, - halfCY, sourceX, sourceY, labelX, labelY, quarterCX, quarterCY, - hiCX, hiCY, qiX, qiY, qiCX, qiCY, hiScaleX, hiScaleY, qiScaleX, - qiScaleY, fw, fh, ratio; + float offset, thicknessx2 = thickness * 2, pvwprgCX, + pvwprgCY, sourceX, sourceY, labelX, labelY, scenesCX, scenesCY, + ppiCX, ppiCY, siX, siY, siCX, siCY, ppiScaleX, ppiScaleY, + siScaleX, siScaleY, fw, fh, ratio; float lineLength = 0.1f; // Rec. ITU-R BT.1848-1 / EBU R 95