Skip to content

Commit

Permalink
UI: Add migration for relative coordinate system
Browse files Browse the repository at this point in the history
  • Loading branch information
derrod committed Aug 27, 2024
1 parent f61d0bb commit 8251005
Show file tree
Hide file tree
Showing 5 changed files with 232 additions and 6 deletions.
10 changes: 10 additions & 0 deletions UI/data/locale/en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,14 @@ Basic.Main.AddSceneCollection.Text="Please enter the name of the scene collectio
# rename scene collection dialog
Basic.Main.RenameSceneCollection.Title="Rename Scene Collection"

# remigrate scene collection dialog
Basic.Main.RemigrateSceneCollection.Title="Update Scene Collection Resolution"
Basic.Main.RemigrateSceneCollection.Text="Do you want to update the scene collection resolution of \"%1\" to match the current profile's canvas resolution of %2x%3?"
Basic.Main.RemigrateSceneCollection.CannotMigrate.Active="Cannot update scene collection resolution while outputs are active."
Basic.Main.RemigrateSceneCollection.CannotMigrate.UnknownBaseResolution="Failed to update scene collection resolution. The original resolution is unknown."
Basic.Main.RemigrateSceneCollection.CannotMigrate.FailedVideoReset="Reset not possible: Changing OBS resolution failed."
Basic.Main.RemigrateSceneCollection.CannotMigrate.BaseResolutionMatches="Reset not possible: Current resolution already the base resolution of scene collection."

# add profile dialog
AddProfile.Title="Add Profile"
AddProfile.Text="Please enter the name of the profile"
Expand Down Expand Up @@ -835,6 +843,8 @@ Basic.MainMenu.Profile.Import="Import Profile"
Basic.MainMenu.Profile.Export="Export Profile"
Basic.MainMenu.SceneCollection.Import="Import Scene Collection"
Basic.MainMenu.SceneCollection.Export="Export Scene Collection"
Basic.MainMenu.SceneCollection.Remigrate="Reset Base Resolution"
Basic.MainMenu.SceneCollection.Migrate="Set Base Resolution"
Basic.MainMenu.Profile.Exists="The profile already exists"

# basic mode help menu
Expand Down
6 changes: 6 additions & 0 deletions UI/forms/OBSBasic.ui
Original file line number Diff line number Diff line change
Expand Up @@ -777,6 +777,7 @@
<addaction name="actionExportSceneCollection"/>
<addaction name="separator"/>
<addaction name="actionShowMissingFiles"/>
<addaction name="actionRemigrateSceneCollection"/>
<addaction name="separator"/>
</widget>
<widget class="QMenu" name="viewMenu">
Expand Down Expand Up @@ -1934,6 +1935,11 @@
<string>Basic.MainMenu.File.ShowMissingFiles</string>
</property>
</action>
<action name="actionRemigrateSceneCollection">
<property name="text">
<string>Basic.MainMenu.SceneCollection.Remigrate</string>
</property>
</action>
<action name="actionNewProfile">
<property name="text">
<string>New</string>
Expand Down
91 changes: 91 additions & 0 deletions UI/window-basic-main-scene-collections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,97 @@ void OBSBasic::on_actionExportSceneCollection_triggered()
}
}

void OBSBasic::on_actionRemigrateSceneCollection_triggered()
{
if (Active()) {
OBSMessageBox::warning(
this,
QTStr("Basic.Main.RemigrateSceneCollection.Title"),
QTStr("Basic.Main.RemigrateSceneCollection.CannotMigrate.Active"));
return;
}

OBSDataAutoRelease priv = obs_get_private_data();

if (!usingAbsoluteCoordinates && !migrationBaseResolution) {
OBSMessageBox::warning(
this,
QTStr("Basic.Main.RemigrateSceneCollection.Title"),
QTStr("Basic.Main.RemigrateSceneCollection.CannotMigrate.UnknownBaseResolution"));
return;
}

obs_video_info ovi;
obs_get_video_info(&ovi);

if (!usingAbsoluteCoordinates &&
migrationBaseResolution->first == ovi.base_width &&
migrationBaseResolution->second == ovi.base_height) {
OBSMessageBox::warning(
this,
QTStr("Basic.Main.RemigrateSceneCollection.Title"),
QTStr("Basic.Main.RemigrateSceneCollection.CannotMigrate.BaseResolutionMatches"));
return;
}

QString name = config_get_string(App()->GlobalConfig(), "Basic",
"SceneCollection");
QString message = QTStr("Basic.Main.RemigrateSceneCollection.Text")
.arg(name)
.arg(ovi.base_width)
.arg(ovi.base_height);

auto answer = OBSMessageBox::question(
this, QTStr("Basic.Main.RemigrateSceneCollection.Title"),
message);

if (answer == QMessageBox::No)
return;

lastOutputResolution = {ovi.base_width, ovi.base_height};

if (!usingAbsoluteCoordinates) {
/* Temporarily change resolution to migration resolution */
ovi.base_width = migrationBaseResolution->first;
ovi.base_height = migrationBaseResolution->second;

if (obs_reset_video(&ovi) != OBS_VIDEO_SUCCESS) {
OBSMessageBox::critical(
this,
QTStr("Basic.Main.RemigrateSceneCollection.Title"),
QTStr("Basic.Main.RemigrateSceneCollection.CannotMigrate.FailedVideoReset"));
return;
}
}

char path[512];
int ret = GetConfigPath(path, 512, "obs-studio/basic/scenes/");
if (ret <= 0) {
blog(LOG_WARNING, "Failed to get scene collection config path");
return;
}

std::string fileName = path;
fileName += config_get_string(App()->GlobalConfig(), "Basic",
"SceneCollectionFile");
fileName += ".json";

if (api)
api->on_event(OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGING);

/* Save and immediately reload to (re-)run migrations. */
SaveProjectNow();
/* Reset video if we potentially changed to a temporary resolution */
if (!usingAbsoluteCoordinates)
ResetVideo();

Load(fileName.c_str(), !usingAbsoluteCoordinates);
RefreshSceneCollections();

if (api)
api->on_event(OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED);
}

void OBSBasic::ChangeSceneCollection()
{
QAction *action = reinterpret_cast<QAction *>(sender());
Expand Down
121 changes: 117 additions & 4 deletions UI/window-basic-main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -953,7 +953,16 @@ void OBSBasic::Save(const char *file)
obs_data_set_obj(saveData, "resolution", res);
}

if (!obs_data_save_json_safe(saveData, file, "tmp", "bak"))
obs_data_set_int(saveData, "version", usingAbsoluteCoordinates ? 1 : 2);

if (migrationBaseResolution && !usingAbsoluteCoordinates) {
OBSDataAutoRelease res = obs_data_create();
obs_data_set_int(res, "x", migrationBaseResolution->first);
obs_data_set_int(res, "y", migrationBaseResolution->second);
obs_data_set_obj(saveData, "migration_resolution", res);
}

if (!obs_data_save_json_pretty_safe(saveData, file, "tmp", "bak"))
blog(LOG_ERROR, "Could not save scene data to %s", file);
}

Expand Down Expand Up @@ -1038,6 +1047,20 @@ void OBSBasic::CreateFirstRunSources()
Str("Basic.AuxDevice1"), 3);
}

void OBSBasic::DisableRelativeCoordinates(bool enable)
{
/* Allow disabling relative positioning to allow loading collections
* that cannot yet be migrated. */
OBSDataAutoRelease priv = obs_get_private_data();
obs_data_set_bool(priv, "AbsoluteCoordinates", enable);
usingAbsoluteCoordinates = enable;

ui->actionRemigrateSceneCollection->setText(
enable ? QTStr("Basic.MainMenu.SceneCollection.Migrate")
: QTStr("Basic.MainMenu.SceneCollection.Remigrate"));
ui->actionRemigrateSceneCollection->setEnabled(enable);
}

void OBSBasic::CreateDefaultScene(bool firstStart)
{
disableSaving++;
Expand All @@ -1048,6 +1071,7 @@ void OBSBasic::CreateDefaultScene(bool firstStart)
ui->transitionDuration->setValue(300);
SetTransition(fadeTransition);

DisableRelativeCoordinates(false);
OBSSceneAutoRelease scene = obs_scene_create(Str("Basic.Scene"));

if (firstStart)
Expand Down Expand Up @@ -1188,10 +1212,11 @@ void OBSBasic::LogScenes()
blog(LOG_INFO, "------------------------------------------------");
}

void OBSBasic::Load(const char *file)
void OBSBasic::Load(const char *file, bool remigrate)
{
disableSaving++;
lastOutputResolution.reset();
migrationBaseResolution.reset();

obs_data_t *data = obs_data_create_from_json_file_safe(file, "bak");
if (!data) {
Expand Down Expand Up @@ -1229,7 +1254,7 @@ void OBSBasic::Load(const char *file)
return;
}

LoadData(data, file);
LoadData(data, file, remigrate);
}

static inline void AddMissingFiles(void *data, obs_source_t *source)
Expand All @@ -1241,7 +1266,27 @@ static inline void AddMissingFiles(void *data, obs_source_t *source)
obs_missing_files_destroy(sf);
}

void OBSBasic::LoadData(obs_data_t *data, const char *file)
static void ClearRelativePosCb(obs_data_t *data, void *)
{
const string_view id = obs_data_get_string(data, "id");
if (id != "scene" && id != "group")
return;

OBSDataAutoRelease settings = obs_data_get_obj(data, "settings");
OBSDataArrayAutoRelease items = obs_data_get_array(settings, "items");

obs_data_array_enum(
items,
[](obs_data_t *data, void *) {
obs_data_unset_user_value(data, "pos_rel");
obs_data_unset_user_value(data, "scale_rel");
obs_data_unset_user_value(data, "scale_ref");
obs_data_unset_user_value(data, "bounds_rel");
},
nullptr);
}

void OBSBasic::LoadData(obs_data_t *data, const char *file, bool remigrate)
{
ClearSceneData();
ClearContextBar();
Expand Down Expand Up @@ -1322,9 +1367,70 @@ void OBSBasic::LoadData(obs_data_t *data, const char *file)
obs_data_array_push_back_array(sources, groups);
}

/* Reset relative coordinate data if forcefully remigrating. */
if (remigrate) {
obs_data_set_int(data, "version", 1);
obs_data_array_enum(sources, ClearRelativePosCb, nullptr);
}

bool resetVideo = false;
bool disableRelativeCoords = false;
obs_video_info ovi;

int64_t version = obs_data_get_int(data, "version");
OBSDataAutoRelease res = obs_data_get_obj(data, "resolution");
if (res) {
lastOutputResolution = {obs_data_get_int(res, "x"),
obs_data_get_int(res, "y")};
}

/* Only migrate legacy collection if resolution is saved. */
if (version < 2 && lastOutputResolution) {
obs_get_video_info(&ovi);

uint32_t width = obs_data_get_int(res, "x");
uint32_t height = obs_data_get_int(res, "y");

migrationBaseResolution = {width, height};

if (ovi.base_height != height || ovi.base_width != width) {
ovi.base_width = width;
ovi.base_height = height;

/* Attempt to reset to last known canvas resolution for migration. */
resetVideo = obs_reset_video(&ovi) == OBS_VIDEO_SUCCESS;
disableRelativeCoords = !resetVideo;
}

/* If migration is possible, and it wasn't forced, back up the original file. */
if (!disableRelativeCoords && !remigrate) {
auto path = filesystem::u8path(file);
auto backupPath = path.concat(".v1");
if (!filesystem::exists(backupPath)) {
if (!obs_data_save_json_pretty_safe(
data, backupPath.u8string().c_str(),
"tmp", NULL)) {
blog(LOG_WARNING,
"Failed to create a backup of existing scene collection data!");
}
}
}
} else if (version < 2) {
disableRelativeCoords = true;
} else if (OBSDataAutoRelease migration_res =
obs_data_get_obj(data, "migration_resolution")) {
migrationBaseResolution = {obs_data_get_int(migration_res, "x"),
obs_data_get_int(migration_res,
"y")};
}

DisableRelativeCoordinates(disableRelativeCoords);

obs_missing_files_t *files = obs_missing_files_create();
obs_load_sources(sources, AddMissingFiles, files);

if (resetVideo)
ResetVideo();
if (transitions)
LoadTransitions(transitions, AddMissingFiles, files);
if (sceneOrder)
Expand Down Expand Up @@ -4953,6 +5059,13 @@ int OBSBasic::ResetVideo()
OBSBasicStats::InitializeValues();
OBSProjector::UpdateMultiviewProjectors();

bool canMigrate =
usingAbsoluteCoordinates ||
(migrationBaseResolution &&
(migrationBaseResolution->first != ovi.base_width ||
migrationBaseResolution->second != ovi.base_height));
ui->actionRemigrateSceneCollection->setEnabled(canMigrate);

emit CanvasResized(ovi.base_width, ovi.base_height);
emit OutputResized(ovi.output_width, ovi.output_height);
}
Expand Down
10 changes: 8 additions & 2 deletions UI/window-basic-main.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,10 @@ class OBSBasic : public OBSMainWindow {

std::atomic<obs_scene_t *> currentScene = nullptr;
std::optional<std::pair<uint32_t, uint32_t>> lastOutputResolution;
std::optional<std::pair<uint32_t, uint32_t>> migrationBaseResolution;
bool usingAbsoluteCoordinates = false;

void DisableRelativeCoordinates(bool disable);

void OnEvent(enum obs_frontend_event event);

Expand All @@ -377,8 +381,9 @@ class OBSBasic : public OBSMainWindow {
void UploadLog(const char *subdir, const char *file, const bool crash);

void Save(const char *file);
void LoadData(obs_data_t *data, const char *file);
void Load(const char *file);
void LoadData(obs_data_t *data, const char *file,
bool remigrate = false);
void Load(const char *file, bool remigrate = false);

void InitHotkeys();
void CreateHotkeys();
Expand Down Expand Up @@ -1149,6 +1154,7 @@ private slots:
void on_actionRemoveSceneCollection_triggered();
void on_actionImportSceneCollection_triggered();
void on_actionExportSceneCollection_triggered();
void on_actionRemigrateSceneCollection_triggered();

void on_actionNewProfile_triggered();
void on_actionDupProfile_triggered();
Expand Down

0 comments on commit 8251005

Please sign in to comment.