Explorar o código

UI: Add option to draw safe areas in preview

Clayton Groeneveld %!s(int64=4) %!d(string=hai) anos
pai
achega
afd58a78e5

+ 90 - 0
UI/display-helpers.hpp

@@ -17,6 +17,9 @@
 
 #pragma once
 
+#include <graphics/vec4.h>
+#include <graphics/matrix4.h>
+
 static inline void GetScaleAndCenterPos(int baseCX, int baseCY, int windowCX,
 					int windowCY, int &x, int &y,
 					float &scale)
@@ -53,3 +56,90 @@ static inline QSize GetPixelSize(QWidget *widget)
 {
 	return widget->size() * widget->devicePixelRatioF();
 }
+
+#define OUTLINE_COLOR 0xFFD0D0D0
+#define LINE_LENGTH 0.1f
+
+// Rec. ITU-R BT.1848-1 / EBU R 95
+#define ACTION_SAFE_PERCENT 0.035f       // 3.5%
+#define GRAPHICS_SAFE_PERCENT 0.05f      // 5.0%
+#define FOURBYTHREE_SAFE_PERCENT 0.1625f // 16.25%
+
+static inline void InitSafeAreas(gs_vertbuffer_t **actionSafeMargin,
+				 gs_vertbuffer_t **graphicsSafeMargin,
+				 gs_vertbuffer_t **fourByThreeSafeMargin,
+				 gs_vertbuffer_t **leftLine,
+				 gs_vertbuffer_t **topLine,
+				 gs_vertbuffer_t **rightLine)
+{
+	obs_enter_graphics();
+
+	// All essential action should be placed inside this area
+	gs_render_start(true);
+	gs_vertex2f(ACTION_SAFE_PERCENT, ACTION_SAFE_PERCENT);
+	gs_vertex2f(ACTION_SAFE_PERCENT, 1 - ACTION_SAFE_PERCENT);
+	gs_vertex2f(1 - ACTION_SAFE_PERCENT, 1 - ACTION_SAFE_PERCENT);
+	gs_vertex2f(1 - ACTION_SAFE_PERCENT, ACTION_SAFE_PERCENT);
+	gs_vertex2f(ACTION_SAFE_PERCENT, ACTION_SAFE_PERCENT);
+	*actionSafeMargin = gs_render_save();
+
+	// All graphics should be placed inside this area
+	gs_render_start(true);
+	gs_vertex2f(GRAPHICS_SAFE_PERCENT, GRAPHICS_SAFE_PERCENT);
+	gs_vertex2f(GRAPHICS_SAFE_PERCENT, 1 - GRAPHICS_SAFE_PERCENT);
+	gs_vertex2f(1 - GRAPHICS_SAFE_PERCENT, 1 - GRAPHICS_SAFE_PERCENT);
+	gs_vertex2f(1 - GRAPHICS_SAFE_PERCENT, GRAPHICS_SAFE_PERCENT);
+	gs_vertex2f(GRAPHICS_SAFE_PERCENT, GRAPHICS_SAFE_PERCENT);
+	*graphicsSafeMargin = gs_render_save();
+
+	// 4:3 safe area for widescreen
+	gs_render_start(true);
+	gs_vertex2f(FOURBYTHREE_SAFE_PERCENT, GRAPHICS_SAFE_PERCENT);
+	gs_vertex2f(1 - FOURBYTHREE_SAFE_PERCENT, GRAPHICS_SAFE_PERCENT);
+	gs_vertex2f(1 - FOURBYTHREE_SAFE_PERCENT, 1 - GRAPHICS_SAFE_PERCENT);
+	gs_vertex2f(FOURBYTHREE_SAFE_PERCENT, 1 - GRAPHICS_SAFE_PERCENT);
+	gs_vertex2f(FOURBYTHREE_SAFE_PERCENT, GRAPHICS_SAFE_PERCENT);
+	*fourByThreeSafeMargin = gs_render_save();
+
+	gs_render_start(true);
+	gs_vertex2f(0.0f, 0.5f);
+	gs_vertex2f(LINE_LENGTH, 0.5f);
+	*leftLine = gs_render_save();
+
+	gs_render_start(true);
+	gs_vertex2f(0.5f, 0.0f);
+	gs_vertex2f(0.5f, LINE_LENGTH);
+	*topLine = gs_render_save();
+
+	gs_render_start(true);
+	gs_vertex2f(1.0f, 0.5f);
+	gs_vertex2f(1 - LINE_LENGTH, 0.5f);
+	*rightLine = gs_render_save();
+
+	obs_leave_graphics();
+}
+
+static inline void RenderSafeAreas(gs_vertbuffer_t *vb, int cx, int cy)
+{
+	if (!vb)
+		return;
+
+	matrix4 transform;
+	matrix4_identity(&transform);
+	transform.x.x = cx;
+	transform.y.y = cy;
+
+	gs_load_vertexbuffer(vb);
+
+	gs_matrix_push();
+	gs_matrix_mul(&transform);
+
+	gs_effect_t *solid = obs_get_base_effect(OBS_EFFECT_SOLID);
+	gs_eparam_t *color = gs_effect_get_param_by_name(solid, "color");
+
+	gs_effect_set_color(color, OUTLINE_COLOR);
+	while (gs_effect_loop(solid, "Solid"))
+		gs_draw(GS_LINESTRIP, 0, 0);
+
+	gs_matrix_pop();
+}

+ 7 - 0
UI/forms/OBSBasicSettings.ui

@@ -595,6 +595,13 @@
                      </property>
                     </widget>
                    </item>
+                   <item row="3" column="1">
+                    <widget class="QCheckBox" name="previewSafeAreas">
+                     <property name="text">
+                      <string>Basic.Settings.General.Multiview.DrawSafeAreas</string>
+                     </property>
+                    </widget>
+                   </item>
                    <item row="0" column="1">
                     <widget class="QCheckBox" name="overflowHide">
                      <property name="text">

+ 29 - 0
UI/window-basic-main.cpp

@@ -458,6 +458,8 @@ OBSBasic::OBSBasic(QWidget *parent)
 
 	connect(ui->broadcastButton, &QPushButton::clicked, this,
 		&OBSBasic::BroadcastButtonClicked);
+
+	UpdatePreviewSafeAreas();
 }
 
 static void SaveAudioDevice(const char *name, int channel, obs_data_t *parent,
@@ -1642,6 +1644,8 @@ void OBSBasic::InitPrimitives()
 	}
 	circle = gs_render_save();
 
+	InitSafeAreas(&actionSafeMargin, &graphicsSafeMargin,
+		      &fourByThreeSafeMargin, &leftLine, &topLine, &rightLine);
 	obs_leave_graphics();
 }
 
@@ -2643,6 +2647,12 @@ OBSBasic::~OBSBasic()
 	gs_vertexbuffer_destroy(boxRight);
 	gs_vertexbuffer_destroy(boxBottom);
 	gs_vertexbuffer_destroy(circle);
+	gs_vertexbuffer_destroy(actionSafeMargin);
+	gs_vertexbuffer_destroy(graphicsSafeMargin);
+	gs_vertexbuffer_destroy(fourByThreeSafeMargin);
+	gs_vertexbuffer_destroy(leftLine);
+	gs_vertexbuffer_destroy(topLine);
+	gs_vertexbuffer_destroy(rightLine);
 	obs_leave_graphics();
 
 	/* When shutting down, sometimes source references can get in to the
@@ -4081,6 +4091,19 @@ void OBSBasic::RenderMain(void *data, uint32_t cx, uint32_t cy)
 
 	window->ui->preview->DrawSceneEditing();
 
+	uint32_t targetCX = window->previewCX;
+	uint32_t targetCY = window->previewCY;
+
+	if (window->drawSafeAreas) {
+		RenderSafeAreas(window->actionSafeMargin, targetCX, targetCY);
+		RenderSafeAreas(window->graphicsSafeMargin, targetCX, targetCY);
+		RenderSafeAreas(window->fourByThreeSafeMargin, targetCX,
+				targetCY);
+		RenderSafeAreas(window->leftLine, targetCX, targetCY);
+		RenderSafeAreas(window->topLine, targetCX, targetCY);
+		RenderSafeAreas(window->rightLine, targetCX, targetCY);
+	}
+
 	/* --------------------------------------- */
 
 	gs_projection_pop();
@@ -9650,3 +9673,9 @@ void OBSBasic::ShowStatusBarMessage(const QString &message)
 	ui->statusbar->clearMessage();
 	ui->statusbar->showMessage(message, 10000);
 }
+
+void OBSBasic::UpdatePreviewSafeAreas()
+{
+	drawSafeAreas = config_get_bool(App()->GlobalConfig(), "BasicWindow",
+					"ShowSafeAreas");
+}

+ 10 - 0
UI/window-basic-main.hpp

@@ -243,6 +243,13 @@ private:
 	gs_vertbuffer_t *boxBottom = nullptr;
 	gs_vertbuffer_t *circle = 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;
+
 	int previewX = 0, previewY = 0;
 	int previewCX = 0, previewCY = 0;
 	float previewScale = 0.0f;
@@ -570,6 +577,9 @@ private:
 #endif
 	void BroadcastButtonClicked();
 
+	void UpdatePreviewSafeAreas();
+	bool drawSafeAreas = false;
+
 public slots:
 	void DeferSaveBegin();
 	void DeferSaveEnd();

+ 11 - 0
UI/window-basic-settings.cpp

@@ -408,6 +408,7 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
 	HookWidget(ui->overflowHide,         CHECK_CHANGED,  GENERAL_CHANGED);
 	HookWidget(ui->overflowAlwaysVisible,CHECK_CHANGED,  GENERAL_CHANGED);
 	HookWidget(ui->overflowSelectionHide,CHECK_CHANGED,  GENERAL_CHANGED);
+	HookWidget(ui->previewSafeAreas,     CHECK_CHANGED,  GENERAL_CHANGED);
 	HookWidget(ui->automaticSearch,      CHECK_CHANGED,  GENERAL_CHANGED);
 	HookWidget(ui->doubleClickSwitch,    CHECK_CHANGED,  GENERAL_CHANGED);
 	HookWidget(ui->studioPortraitLayout, CHECK_CHANGED,  GENERAL_CHANGED);
@@ -1313,6 +1314,10 @@ void OBSBasicSettings::LoadGeneralSettings()
 		GetGlobalConfig(), "BasicWindow", "OverflowSelectionHidden");
 	ui->overflowSelectionHide->setChecked(overflowSelectionHide);
 
+	bool safeAreas = config_get_bool(GetGlobalConfig(), "BasicWindow",
+					 "ShowSafeAreas");
+	ui->previewSafeAreas->setChecked(safeAreas);
+
 	bool automaticSearch = config_get_bool(GetGlobalConfig(), "General",
 					       "AutomaticCollectionSearch");
 	ui->automaticSearch->setChecked(automaticSearch);
@@ -3021,6 +3026,12 @@ void OBSBasicSettings::SaveGeneralSettings()
 		config_set_bool(GetGlobalConfig(), "BasicWindow",
 				"OverflowSelectionHidden",
 				ui->overflowSelectionHide->isChecked());
+	if (WidgetChanged(ui->previewSafeAreas)) {
+		config_set_bool(GetGlobalConfig(), "BasicWindow",
+				"ShowSafeAreas",
+				ui->previewSafeAreas->isChecked());
+		main->UpdatePreviewSafeAreas();
+	}
 	if (WidgetChanged(ui->doubleClickSwitch))
 		config_set_bool(GetGlobalConfig(), "BasicWindow",
 				"TransitionOnDoubleClick",

+ 18 - 85
UI/window-projector.cpp

@@ -70,58 +70,9 @@ OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, int monitor,
 		&OBSProjector::ScreenRemoved);
 
 	if (type == ProjectorType::Multiview) {
-		obs_enter_graphics();
-
-		// All essential action should be placed inside this area
-		gs_render_start(true);
-		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(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(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(lineLength, 0.5f);
-		leftLine = gs_render_save();
-
-		gs_render_start(true);
-		gs_vertex2f(0.5f, 0.0f);
-		gs_vertex2f(0.5f, lineLength);
-		topLine = gs_render_save();
-
-		gs_render_start(true);
-		gs_vertex2f(1.0f, 0.5f);
-		gs_vertex2f(1 - lineLength, 0.5f);
-		rightLine = gs_render_save();
-		obs_leave_graphics();
-
-		solid = obs_get_base_effect(OBS_EFFECT_SOLID);
-		color = gs_effect_get_param_by_name(solid, "color");
-
+		InitSafeAreas(&actionSafeMargin, &graphicsSafeMargin,
+			      &fourByThreeSafeMargin, &leftLine, &topLine,
+			      &rightLine);
 		UpdateMultiview();
 
 		multiviewProjectors.push_back(this);
@@ -297,31 +248,13 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy)
 	OBSSource programSrc = main->GetProgramSource();
 	bool studioMode = main->IsPreviewProgramMode();
 
-	auto renderVB = [&](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(window->color, colorVal);
-		while (gs_effect_loop(window->solid, "Solid"))
-			gs_draw(GS_LINESTRIP, 0, 0);
-
-		gs_matrix_pop();
-	};
-
 	auto drawBox = [&](float cx, float cy, uint32_t colorVal) {
-		gs_effect_set_color(window->color, colorVal);
-		while (gs_effect_loop(window->solid, "Solid"))
+		gs_effect_t *solid = obs_get_base_effect(OBS_EFFECT_SOLID);
+		gs_eparam_t *color =
+			gs_effect_get_param_by_name(solid, "color");
+
+		gs_effect_set_color(color, colorVal);
+		while (gs_effect_loop(solid, "Solid"))
 			gs_draw_sprite(nullptr, 0, (uint32_t)cx, (uint32_t)cy);
 	};
 
@@ -549,17 +482,17 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy)
 		obs_source_video_render(previewSrc);
 	else
 		obs_render_main_texture();
+
 	if (drawSafeArea) {
-		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);
+		RenderSafeAreas(window->actionSafeMargin, targetCX, targetCY);
+		RenderSafeAreas(window->graphicsSafeMargin, targetCX, targetCY);
+		RenderSafeAreas(window->fourByThreeSafeMargin, targetCX,
+				targetCY);
+		RenderSafeAreas(window->leftLine, targetCX, targetCY);
+		RenderSafeAreas(window->topLine, targetCX, targetCY);
+		RenderSafeAreas(window->rightLine, targetCX, targetCY);
 	}
+
 	endRegion();
 	gs_matrix_pop();
 

+ 0 - 7
UI/window-projector.hpp

@@ -49,8 +49,6 @@ 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;
 	// Multiview position helpers
 	float thickness = 4;
 	float offset, thicknessx2 = thickness * 2, pvwprgCX, pvwprgCY, sourceX,
@@ -58,11 +56,6 @@ private:
 		      siX, siY, siCX, siCY, ppiScaleX, ppiScaleY, siScaleX,
 		      siScaleY, fw, fh, ratio;
 
-	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