VideoCommon: add graphics mod editor state

This commit is contained in:
iwubcode 2023-07-24 00:41:37 -05:00
parent 0512bd9a18
commit dc40e46651
2 changed files with 411 additions and 0 deletions

View file

@ -0,0 +1,245 @@
// Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "VideoCommon/GraphicsModEditor/EditorState.h"
#include <chrono>
#include <fmt/format.h>
#include "Common/EnumUtils.h"
#include "Common/Logging/Log.h"
#include "Common/StringUtil.h"
#include "Common/VariantUtil.h"
#include "VideoCommon/GraphicsModSystem/Config/GraphicsMod.h"
#include "VideoCommon/GraphicsModSystem/Constants.h"
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModActionFactory.h"
namespace GraphicsModEditor
{
void WriteToGraphicsMod(const UserData& user_data, GraphicsModSystem::Config::GraphicsMod* config)
{
config->m_title = user_data.m_title;
config->m_author = user_data.m_author;
config->m_description = user_data.m_description;
config->m_assets = user_data.m_asset_library->GetAssets(user_data.m_current_mod_path);
config->m_tags = user_data.m_tags;
std::map<GraphicsModAction*, std::size_t> action_to_index;
for (const auto& action : user_data.m_actions)
{
GraphicsModSystem::Config::GraphicsModAction action_config;
action_config.m_factory_name = action->GetFactoryName();
picojson::object serialized_data;
action->SerializeToConfig(&serialized_data);
action_config.m_data = picojson::value{serialized_data};
config->m_actions.push_back(std::move(action_config));
action_to_index[action.get()] = config->m_actions.size() - 1;
}
for (const auto& [tag_name, actions] : user_data.m_tag_name_to_actions)
{
auto& action_indexes = config->m_tag_name_to_action_indexes[tag_name];
for (const auto& action : actions)
{
action_indexes.push_back(action_to_index[action]);
}
}
std::set<GraphicsModSystem::DrawCallID> draw_calls;
for (const auto& [draw_call_id, actions] : user_data.m_draw_call_id_to_actions)
{
draw_calls.insert(draw_call_id);
}
for (const auto& [draw_call_id, actions] : user_data.m_draw_call_id_to_user_data)
{
draw_calls.insert(draw_call_id);
}
for (const auto& draw_call_id : draw_calls)
{
const auto target_index = config->m_targets.size();
GraphicsModSystem::Config::IntTarget i_target;
i_target.m_target_id = Common::ToUnderlying(draw_call_id);
if (const auto iter = user_data.m_draw_call_id_to_actions.find(draw_call_id);
iter != user_data.m_draw_call_id_to_actions.end())
{
auto& action_indexes = config->m_target_index_to_action_indexes[target_index];
for (const auto& action : iter->second)
{
action_indexes.push_back(action_to_index[action]);
}
}
if (const auto iter = user_data.m_draw_call_id_to_user_data.find(draw_call_id);
iter != user_data.m_draw_call_id_to_user_data.end())
{
i_target.m_name = iter->second.m_friendly_name;
for (const auto& tag_name : iter->second.m_tag_names)
{
i_target.m_tag_names.push_back(tag_name);
}
}
config->m_targets.push_back(std::move(i_target));
}
std::set<GraphicsModSystem::TextureCacheID> texture_cache_ids;
for (const auto& [texture_cache_id, actions] : user_data.m_texture_cache_id_to_actions)
{
texture_cache_ids.insert(texture_cache_id);
}
for (const auto& [texture_cache_id, actions] : user_data.m_texture_cache_id_to_user_data)
{
texture_cache_ids.insert(texture_cache_id);
}
for (const auto& texture_cache_id : texture_cache_ids)
{
const auto target_index = config->m_targets.size();
GraphicsModSystem::Config::StringTarget s_target;
s_target.m_target_id = texture_cache_id;
if (const auto iter = user_data.m_texture_cache_id_to_actions.find(texture_cache_id);
iter != user_data.m_texture_cache_id_to_actions.end())
{
auto& action_indexes = config->m_target_index_to_action_indexes[target_index];
for (const auto& action : iter->second)
{
action_indexes.push_back(action_to_index[action]);
}
}
if (const auto iter = user_data.m_texture_cache_id_to_user_data.find(texture_cache_id);
iter != user_data.m_texture_cache_id_to_user_data.end())
{
s_target.m_name = iter->second.m_friendly_name;
for (const auto& tag_name : iter->second.m_tag_names)
{
s_target.m_tag_names.push_back(tag_name);
}
}
config->m_targets.push_back(std::move(s_target));
}
}
void ReadFromGraphicsMod(UserData* user_data, EditorData* editor_data,
const RuntimeState& runtime_state,
const GraphicsModSystem::Config::GraphicsMod& config,
const std::string& mod_root)
{
user_data->m_title = config.m_title;
user_data->m_author = config.m_author;
user_data->m_description = config.m_description;
user_data->m_current_mod_path = mod_root;
user_data->m_asset_library->AddAssets(config.m_assets, user_data->m_current_mod_path);
const auto create_action =
[&](const std::string_view& action_name,
const picojson::value& json_data) -> std::unique_ptr<GraphicsModAction> {
auto action =
GraphicsModActionFactory::Create(action_name, json_data, user_data->m_asset_library);
if (action == nullptr)
{
return nullptr;
}
return action;
};
for (const auto& action_config : config.m_actions)
{
if (auto action = create_action(action_config.m_factory_name, action_config.m_data))
{
user_data->m_actions.push_back(std::make_unique<EditorAction>(std::move(action)));
user_data->m_actions.back().get()->SetID(editor_data->m_next_action_id);
editor_data->m_next_action_id++;
}
}
user_data->m_tags = config.m_tags;
for (const auto& target : config.m_targets)
{
std::visit(
overloaded{
[&](const GraphicsModSystem::Config::IntTarget& int_target) {
const GraphicsModSystem::DrawCallID draw_call_id{int_target.m_target_id};
auto& actions = user_data->m_draw_call_id_to_actions[draw_call_id];
actions = {};
if (int_target.m_name != "")
{
user_data->m_draw_call_id_to_user_data[draw_call_id].m_friendly_name =
int_target.m_name;
}
for (const auto& tag_name : int_target.m_tag_names)
{
user_data->m_draw_call_id_to_user_data[draw_call_id].m_tag_names.push_back(
tag_name);
}
},
[&](const GraphicsModSystem::Config::StringTarget& str_target) {
const GraphicsModSystem::TextureCacheID texture_cache_id{str_target.m_target_id};
auto& actions = user_data->m_texture_cache_id_to_actions[texture_cache_id];
actions = {};
if (str_target.m_name != "")
{
user_data->m_texture_cache_id_to_user_data[texture_cache_id].m_friendly_name =
str_target.m_name;
}
for (const auto& tag_name : str_target.m_tag_names)
{
user_data->m_texture_cache_id_to_user_data[texture_cache_id].m_tag_names.push_back(
tag_name);
}
}},
target);
}
for (const auto& target_to_actions_pair : config.m_target_index_to_action_indexes)
{
const u64 target_index = target_to_actions_pair.first;
const std::vector<u64>& action_indexes = target_to_actions_pair.second;
std::visit(
overloaded{[&](const GraphicsModSystem::Config::IntTarget& int_target) {
const GraphicsModSystem::DrawCallID draw_call_id{int_target.m_target_id};
auto& actions = user_data->m_draw_call_id_to_actions[draw_call_id];
for (const auto& action_index : action_indexes)
{
actions.push_back(user_data->m_actions[action_index].get());
}
},
[&](const GraphicsModSystem::Config::StringTarget& str_target) {
const GraphicsModSystem::TextureCacheID texture_cache_id{
str_target.m_target_id};
auto& actions = user_data->m_texture_cache_id_to_actions[texture_cache_id];
for (const auto& action_index : action_indexes)
{
actions.push_back(user_data->m_actions[action_index].get());
}
}},
config.m_targets[target_index]);
}
for (const auto& [tag_name, action_indexes] : config.m_tag_name_to_action_indexes)
{
auto& actions = user_data->m_tag_name_to_actions[tag_name];
for (const auto& action_index : action_indexes)
{
actions.push_back(user_data->m_actions[action_index].get());
}
}
}
} // namespace GraphicsModEditor

View file

@ -0,0 +1,166 @@
// Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <filesystem>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <string_view>
#include <vector>
#include <picojson.h>
#include "Common/CommonTypes.h"
#include "VideoCommon/AbstractTexture.h"
#include "VideoCommon/Assets/CustomAsset.h"
#include "VideoCommon/Assets/DirectFilesystemAssetLibrary.h"
#include "VideoCommon/GraphicsModEditor/EditorAssetSource.h"
#include "VideoCommon/GraphicsModEditor/EditorTypes.h"
#include "VideoCommon/GraphicsModEditor/SceneDumper.h"
#include "VideoCommon/GraphicsModSystem/Config/GraphicsModHashPolicy.h"
#include "VideoCommon/GraphicsModSystem/Config/GraphicsModTag.h"
#include "VideoCommon/GraphicsModSystem/Runtime/CustomTextureCache.h"
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModAction.h"
#include "VideoCommon/GraphicsModSystem/Types.h"
namespace GraphicsModSystem::Config
{
struct GraphicsMod;
}
namespace GraphicsModEditor
{
struct EditorData
{
// A map of editor specific textures accessible by name
std::map<std::string, std::unique_ptr<AbstractTexture>> m_name_to_texture;
// A map of editor specific templates accessible by name
std::map<std::string, std::string> m_name_to_template;
// Editor specific tags
std::map<std::string, GraphicsModSystem::Config::GraphicsModTag> m_tags;
// User data that is waiting on the editor to generate
// a preview
std::map<VideoCommon::CustomAssetLibrary::AssetID, std::shared_ptr<VideoCommon::CustomAsset>>
m_assets_waiting_for_preview;
std::shared_ptr<VideoCommon::DirectFilesystemAssetLibrary> m_asset_library;
bool m_disable_all_actions = false;
bool m_view_lighting = false;
bool m_view_normals = false;
GraphicsModSystem::DrawCallID m_export_dolphin_material_draw_call;
GraphicsModSystem::DrawCallID m_create_material_draw_call;
u64 m_next_action_id = 1;
};
struct UserData
{
std::string m_title;
std::string m_author;
std::string m_description;
std::filesystem::path m_current_mod_path;
GraphicsModSystem::Config::HashPolicy m_hash_policy =
GraphicsModSystem::Config::GetDefaultHashPolicy();
// References of actions defined by the user to provide to the graphics mod interface
std::map<GraphicsModSystem::DrawCallID, std::vector<GraphicsModAction*>>
m_draw_call_id_to_actions;
// References of actions defined by the user to provide to the graphics mod interface
std::map<GraphicsModSystem::TextureCacheID, std::vector<GraphicsModAction*>>
m_texture_cache_id_to_actions;
// References of actions defined by the user to provide to the graphics mod interface
std::map<GraphicsModSystem::LightID, std::vector<GraphicsModAction*>>
m_light_id_to_reference_actions;
std::vector<std::unique_ptr<EditorAction>> m_actions;
std::vector<GraphicsModSystem::Config::GraphicsModTag> m_tags;
// References of actions defined by the user to provide to the graphics mod interface
std::map<std::string, std::vector<GraphicsModAction*>> m_tag_name_to_actions;
// Mapping the draw call id to any user data for the target
std::map<GraphicsModSystem::DrawCallID, DrawCallUserData> m_draw_call_id_to_user_data;
// Mapping the texture cache id to any user data for the target
std::map<GraphicsModSystem::TextureCacheID, TextureCacheUserData> m_texture_cache_id_to_user_data;
// Mapping the light id to any user data for the target
std::map<GraphicsModSystem::LightID, LightUserData> m_light_id_to_user_data;
// The asset library provided to all user actions
std::shared_ptr<EditorAssetSource> m_asset_library;
};
struct RuntimeState
{
struct XFBData
{
struct DrawCallWithTime
{
GraphicsModSystem::DrawCallID draw_call_id;
std::chrono::steady_clock::time_point sort_time;
};
struct DrawCallWithTimeCompare
{
bool operator()(const DrawCallWithTime& lhs, const DrawCallWithTime& rhs) const
{
return lhs.sort_time < rhs.sort_time;
}
};
// The draw call ids this frame
std::set<DrawCallWithTime, DrawCallWithTimeCompare> m_draw_call_ids;
// The EFB/XFB calls triggered this frame
std::set<GraphicsModSystem::TextureCacheID> m_texture_cache_ids;
// The game lights triggered this frame
std::set<GraphicsModSystem::LightID> m_light_ids;
};
std::map<std::string, XFBData, std::less<>> m_xfb_to_data;
std::vector<std::string> m_xfbs_presented;
XFBData m_current_xfb;
// Mapping the draw call id to the last known data
std::map<GraphicsModSystem::DrawCallID, DrawCallData> m_draw_call_id_to_data;
// Mapping the EFB/XFB calls to the last known data
std::map<GraphicsModSystem::TextureCacheID, TextureCacheData, std::less<>>
m_texture_cache_id_to_data;
// Mapping the game light id to the last known data
std::map<GraphicsModSystem::LightID, LightData> m_light_id_to_data;
};
struct EditorState
{
EditorData m_editor_data;
UserData m_user_data;
RuntimeState m_runtime_data;
SceneDumper m_scene_dumper;
};
void WriteToGraphicsMod(const UserData& user_data, GraphicsModSystem::Config::GraphicsMod* config);
void ReadFromGraphicsMod(UserData* user_data, EditorData* editor_data,
const RuntimeState& runtime_state,
const GraphicsModSystem::Config::GraphicsMod& config,
const std::string& mod_root);
} // namespace GraphicsModEditor