mirror of https://github.com/AxioDL/metaforce.git
Add experimental Assets window
This commit is contained in:
parent
4df59e3e39
commit
2c032ada13
|
@ -76,6 +76,7 @@ public:
|
|||
u32 GetFakeStaticSize() const { return 0; }
|
||||
void AsyncIdle();
|
||||
CAssetId GetMLVLId() const { return m_mlvlId; }
|
||||
const std::vector<SResInfo>& GetResList() const { return x74_resList; }
|
||||
};
|
||||
|
||||
} // namespace metaforce
|
||||
|
|
|
@ -37,7 +37,22 @@ void ImGuiTextCenter(std::string_view text) {
|
|||
static std::unordered_map<CAssetId, std::unique_ptr<CDummyWorld>> dummyWorlds;
|
||||
static std::unordered_map<CAssetId, TCachedToken<CStringTable>> stringTables;
|
||||
|
||||
std::string ImGuiLoadStringTable(CAssetId stringId, int idx) {
|
||||
std::vector<std::string> ImGuiLoadStringTable(CAssetId stringId) {
|
||||
if (!stringId.IsValid()) {
|
||||
return {};
|
||||
}
|
||||
if (!stringTables.contains(stringId)) {
|
||||
stringTables[stringId] = g_SimplePool->GetObj(SObjectTag{SBIG('STRG'), stringId});
|
||||
}
|
||||
std::vector<std::string> result;
|
||||
CStringTable* pTable = stringTables[stringId].GetObj();
|
||||
for (u32 i = 0; i < pTable->GetStringCount(); ++i) {
|
||||
result.push_back(hecl::Char16ToUTF8(pTable->GetString(s32(i))));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string ImGuiLoadStringTableIndex(CAssetId stringId, int idx) {
|
||||
if (!stringId.IsValid()) {
|
||||
return ""s;
|
||||
}
|
||||
|
@ -71,7 +86,7 @@ static std::vector<std::pair<std::string, CAssetId>> ListWorlds() {
|
|||
if (!stringId.IsValid()) {
|
||||
continue;
|
||||
}
|
||||
worlds.emplace_back(ImGuiLoadStringTable(stringId, 0), worldId);
|
||||
worlds.emplace_back(ImGuiLoadStringTableIndex(stringId, 0), worldId);
|
||||
}
|
||||
return worlds;
|
||||
}
|
||||
|
@ -88,7 +103,7 @@ static std::vector<std::pair<std::string, TAreaId>> ListAreas(CAssetId worldId)
|
|||
if (!stringId.IsValid()) {
|
||||
continue;
|
||||
}
|
||||
areas.emplace_back(ImGuiLoadStringTable(stringId, 0), i);
|
||||
areas.emplace_back(ImGuiLoadStringTableIndex(stringId, 0), i);
|
||||
}
|
||||
return areas;
|
||||
}
|
||||
|
@ -783,7 +798,7 @@ void ImGuiConsole::ShowDebugOverlay() {
|
|||
}
|
||||
hasPrevious = true;
|
||||
|
||||
const std::string name = ImGuiLoadStringTable(g_StateManager->GetWorld()->IGetStringTableAssetId(), 0);
|
||||
const std::string name = ImGuiLoadStringTableIndex(g_StateManager->GetWorld()->IGetStringTableAssetId(), 0);
|
||||
ImGuiStringViewText(
|
||||
fmt::format(FMT_STRING("World Asset ID: 0x{}, Name: {}\n"), g_GameState->CurrentWorldAssetId(), name));
|
||||
}
|
||||
|
@ -810,7 +825,7 @@ void ImGuiConsole::ShowDebugOverlay() {
|
|||
CAssetId stringId = pArea->IGetStringTableAssetId();
|
||||
ImGuiStringViewText(
|
||||
fmt::format(FMT_STRING("Area Asset ID: 0x{}, Name: {}\nArea ID: {}, Active Layer bits: {}\n"),
|
||||
pArea->GetAreaAssetId(), ImGuiLoadStringTable(stringId, 0), pArea->GetAreaId(), layerBits));
|
||||
pArea->GetAreaAssetId(), ImGuiLoadStringTableIndex(stringId, 0), pArea->GetAreaId(), layerBits));
|
||||
}
|
||||
}
|
||||
if (m_layerInfo && g_StateManager != nullptr) {
|
||||
|
@ -1031,6 +1046,7 @@ void ImGuiConsole::ShowAppMainMenuBar(bool canInspect) {
|
|||
ImGui::MenuItem("Items", nullptr, &m_showItemsWindow, canInspect && m_developer && m_cheats);
|
||||
ImGui::MenuItem("Layers", nullptr, &m_showLayersWindow, canInspect && m_developer);
|
||||
ImGui::MenuItem("Console Variables", nullptr, &m_showConsoleVariablesWindow);
|
||||
ImGui::MenuItem("Assets", nullptr, &m_showAssetsWindow, canInspect);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (ImGui::BeginMenu("Debug")) {
|
||||
|
@ -1152,6 +1168,9 @@ void ImGuiConsole::PreUpdate() {
|
|||
if (canInspect && m_showLayersWindow) {
|
||||
ShowLayersWindow();
|
||||
}
|
||||
if (canInspect && m_showAssetsWindow) {
|
||||
ShowAssetsWindow();
|
||||
}
|
||||
if (m_showAboutWindow) {
|
||||
ShowAboutWindow(true);
|
||||
}
|
||||
|
@ -1479,6 +1498,52 @@ void ImGuiConsole::ShowLayersWindow() {
|
|||
ImGui::End();
|
||||
}
|
||||
|
||||
void ImGuiConsole::ShowAssetsWindow() {
|
||||
if (ImGui::Begin("Assets", &m_showAssetsWindow)) {
|
||||
for (const auto& pak : g_ResFactory->GetResLoader()->GetPaks()) {
|
||||
const std::vector<std::pair<std::string, SObjectTag>>& vector = pak->GetNameList();
|
||||
const std::string_view pakName = pak->GetPath();
|
||||
if (ImGui::TreeNode(pakName.data())) {
|
||||
for (const auto& item : pak->GetResList()) {
|
||||
// TODO(encounter): store reverse lookup map
|
||||
const auto found = std::find_if(vector.begin(), vector.end(), [&](const std::pair<std::string, SObjectTag>& v) {
|
||||
return v.second.id == item.GetId();
|
||||
});
|
||||
std::string label;
|
||||
if (found != vector.end()) {
|
||||
label = fmt::format(FMT_STRING("0x{:08X}: {} {}"), item.GetId().Value(), item.GetType().toString().c_str(), found->first.c_str());
|
||||
} else {
|
||||
label = fmt::format(FMT_STRING("0x{:08X}: {}"), item.GetId().Value(), item.GetType().toString().c_str());
|
||||
}
|
||||
ImGui::Selectable(label.c_str()); // TODO(encounter): open separate asset viewer window on click
|
||||
if (ImGui::IsItemHovered()) {
|
||||
if (item.GetType() == SBIG('TXTR')) {
|
||||
ImGui::BeginTooltip();
|
||||
float imgSize = 128.f * ImGui::GetIO().DisplayFramebufferScale.x;
|
||||
// TODO(encounter): size based on CTexture dimensions
|
||||
ImGui::Image(SObjectTag{item.GetType(), item.GetId()}, ImVec2{imgSize, imgSize}, ImVec2{0, 1},
|
||||
ImVec2{1, 0});
|
||||
// TODO(encounter): show CTexture information
|
||||
ImGui::EndTooltip();
|
||||
} else if (item.GetType() == SBIG('STRG')) {
|
||||
ImGui::BeginTooltip();
|
||||
auto vec = ImGuiLoadStringTable(item.GetId());
|
||||
for (int i = 0; i < vec.size(); ++i) {
|
||||
// TODO(encounter): parse format strings or use CGuiTextSupport
|
||||
ImGuiStringViewText(fmt::format(FMT_STRING("{}: {}"), i, vec[i]));
|
||||
}
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
// TODO(encounter): preview more types
|
||||
}
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void ImGuiConsole::ShowMenuHint() {
|
||||
if (m_menuHintTime <= 0.f) {
|
||||
return;
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
namespace metaforce {
|
||||
void ImGuiStringViewText(std::string_view text);
|
||||
void ImGuiTextCenter(std::string_view text);
|
||||
std::string ImGuiLoadStringTable(CAssetId stringId, int idx);
|
||||
std::vector<std::string> ImGuiLoadStringTable(CAssetId stringId);
|
||||
std::string ImGuiLoadStringTableIndex(CAssetId stringId, int idx);
|
||||
|
||||
struct ImGuiEntityEntry {
|
||||
TUniqueId uid = kInvalidUniqueId;
|
||||
|
@ -57,6 +58,7 @@ private:
|
|||
bool m_showItemsWindow = false;
|
||||
bool m_showLayersWindow = false;
|
||||
bool m_showConsoleVariablesWindow = false;
|
||||
bool m_showAssetsWindow = false;
|
||||
|
||||
bool m_paused = false;
|
||||
bool m_stepFrame = false;
|
||||
|
@ -102,5 +104,6 @@ private:
|
|||
void ShowLayersWindow();
|
||||
void ShowConsoleVariablesWindow();
|
||||
void ShowMenuHint();
|
||||
void ShowAssetsWindow();
|
||||
};
|
||||
} // namespace metaforce
|
||||
|
|
|
@ -767,7 +767,7 @@ IMGUI_ENTITY_INSPECT(CScriptDock, CPhysicsActor, ScriptDock, {
|
|||
auto areaId = dock->GetConnectedAreaId(dock->GetReferenceCount());
|
||||
if (areaId != kInvalidAreaId) {
|
||||
CAssetId stringId = g_StateManager->GetWorld()->GetArea(areaId)->IGetStringTableAssetId();
|
||||
ImGuiStringViewText(fmt::format(FMT_STRING("Connected Area: {}"), ImGuiLoadStringTable(stringId, 0)));
|
||||
ImGuiStringViewText(fmt::format(FMT_STRING("Connected Area: {}"), ImGuiLoadStringTableIndex(stringId, 0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
#include "Runtime/GameGlobalObjects.hpp"
|
||||
#include "Runtime/Input/CInputGenerator.hpp"
|
||||
#include "Runtime/CSimplePool.hpp"
|
||||
#include "Runtime/CToken.hpp"
|
||||
#include <zeus/CMatrix4f.hpp>
|
||||
|
||||
extern "C" const uint8_t NOTO_MONO_FONT[];
|
||||
|
@ -33,6 +35,7 @@ static boo::ObjToken<boo::IGraphicsBufferD> IndexBuffer;
|
|||
static boo::ObjToken<boo::IGraphicsBufferD> UniformBuffer;
|
||||
static std::array<boo::ObjToken<boo::IShaderDataBinding>, ImGuiUserTextureID_MAX> ShaderDataBindings;
|
||||
static std::array<boo::ObjToken<boo::ITextureS>, ImGuiUserTextureID_MAX> Textures;
|
||||
static std::unordered_map<CAssetId, boo::ObjToken<boo::IShaderDataBinding>> ResourceBindings;
|
||||
static boo::SWindowRect WindowRect;
|
||||
static std::string IniFilePath;
|
||||
static std::string LogFilePath;
|
||||
|
@ -157,6 +160,7 @@ void ImGuiEngine::Shutdown() {
|
|||
for (auto& item : Textures) {
|
||||
item.reset();
|
||||
}
|
||||
ResourceBindings.clear();
|
||||
VertexBuffer.reset();
|
||||
IndexBuffer.reset();
|
||||
UniformBuffer.reset();
|
||||
|
@ -296,6 +300,22 @@ void ImGuiEngine::End() {
|
|||
|
||||
for (int i = 0; i < drawData->CmdListsCount; ++i) {
|
||||
const auto* cmdList = drawData->CmdLists[i];
|
||||
for (const auto& drawCmd : cmdList->CmdBuffer) {
|
||||
const auto& textureId = drawCmd.TextureId;
|
||||
if (textureId.textureId == ImGuiUserTextureID_MAX && textureId.objectTag.id.IsValid()) {
|
||||
if (ResourceBindings.contains(textureId.objectTag.id)) {
|
||||
continue;
|
||||
}
|
||||
if (textureId.objectTag.type == SBIG('TXTR')) {
|
||||
TLockedToken<CTexture> tex = g_SimplePool->GetObj(textureId.objectTag);
|
||||
// TODO(encounter): store token until loaded, but right now we force it to load immediately
|
||||
// if (tex.IsLoaded())
|
||||
ResourceBindings[textureId.objectTag.id] = BuildShaderDataBinding(ctx, tex->GetBooTexture());
|
||||
} else {
|
||||
Log.report(logvisor::Fatal, FMT_STRING("Unknown type to render: {}"), textureId.objectTag.type.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
int vtxBufferSz = cmdList->VtxBuffer.size();
|
||||
int idxBufferSz = cmdList->IdxBuffer.size();
|
||||
memcpy(vtxBuf, cmdList->VtxBuffer.begin(), vtxBufferSz * sizeof(ImDrawVert));
|
||||
|
@ -304,6 +324,8 @@ void ImGuiEngine::End() {
|
|||
idxBuf += idxBufferSz;
|
||||
}
|
||||
|
||||
// TODO(encounter): clean up unreferenced ResourceBindings
|
||||
|
||||
VertexBuffer->unmap();
|
||||
IndexBuffer->unmap();
|
||||
return true;
|
||||
|
@ -324,18 +346,32 @@ void ImGuiEngine::Draw(boo::IGraphicsCommandQueue* gfxQ) {
|
|||
|
||||
size_t idxOffset = 0;
|
||||
size_t vtxOffset = 0;
|
||||
size_t currentTextureID = ImGuiUserTextureID_MAX;
|
||||
ImTextureID currentTextureID = ImGuiUserTextureID_MAX;
|
||||
for (int i = 0; i < drawData->CmdListsCount; ++i) {
|
||||
const auto* cmdList = drawData->CmdLists[i];
|
||||
for (const auto& drawCmd : cmdList->CmdBuffer) {
|
||||
auto* cmdList = drawData->CmdLists[i];
|
||||
for (auto& drawCmd : cmdList->CmdBuffer) {
|
||||
if (drawCmd.UserCallback != nullptr) {
|
||||
if (drawCmd.UserCallback == ImDrawCallback_ResetRenderState) {
|
||||
gfxQ->setViewport(viewportRect);
|
||||
} else {
|
||||
if (drawCmd.UserCallbackData == nullptr) {
|
||||
drawCmd.UserCallbackData = gfxQ;
|
||||
}
|
||||
drawCmd.UserCallback(cmdList, &drawCmd);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (currentTextureID != drawCmd.TextureId) {
|
||||
currentTextureID = drawCmd.TextureId;
|
||||
gfxQ->setShaderDataBinding(ShaderDataBindings[currentTextureID]);
|
||||
}
|
||||
if (drawCmd.UserCallback != nullptr) {
|
||||
drawCmd.UserCallback(cmdList, &drawCmd);
|
||||
if (currentTextureID.textureId == ImGuiUserTextureID_MAX) {
|
||||
if (!ResourceBindings.contains(currentTextureID.objectTag.id)) {
|
||||
continue;
|
||||
}
|
||||
gfxQ->setShaderDataBinding(ResourceBindings[currentTextureID.objectTag.id]);
|
||||
} else {
|
||||
gfxQ->setShaderDataBinding(ShaderDataBindings[currentTextureID.textureId]);
|
||||
}
|
||||
}
|
||||
ImVec2 pos = drawData->DisplayPos;
|
||||
int clipX = static_cast<int>(drawCmd.ClipRect.x - pos.x);
|
||||
int clipY = static_cast<int>(drawCmd.ClipRect.y - pos.y);
|
||||
|
@ -354,17 +390,23 @@ void ImGuiEngine::Draw(boo::IGraphicsCommandQueue* gfxQ) {
|
|||
}
|
||||
}
|
||||
|
||||
void ImGuiEngine::BuildShaderDataBindings(boo::IGraphicsDataFactory::Context& ctx) {
|
||||
boo::ObjToken<boo::IShaderDataBinding> ImGuiEngine::BuildShaderDataBinding(boo::IGraphicsDataFactory::Context& ctx,
|
||||
boo::ObjToken<boo::ITexture> texture) {
|
||||
std::array<boo::ObjToken<boo::IGraphicsBuffer>, 1> uniforms = {UniformBuffer.get()};
|
||||
std::array<boo::PipelineStage, uniforms.size()> unistages = {boo::PipelineStage::Vertex};
|
||||
std::array<size_t, uniforms.size()> unioffs{0};
|
||||
std::array<size_t, uniforms.size()> unisizes{sizeof(Uniform)};
|
||||
for (int i = 0; i < ImGuiUserTextureID_MAX; ++i) {
|
||||
std::array<boo::ObjToken<boo::ITexture>, 1> texs{Textures[i].get()};
|
||||
ShaderDataBindings[i] = ctx.newShaderDataBinding(ShaderPipeline, VertexBuffer.get(), nullptr, IndexBuffer.get(),
|
||||
uniforms.size(), uniforms.data(), unistages.data(), unioffs.data(),
|
||||
unisizes.data(), texs.size(), texs.data(), nullptr, nullptr);
|
||||
std::array<boo::ObjToken<boo::ITexture>, 1> texs{texture};
|
||||
return ctx.newShaderDataBinding(ShaderPipeline, VertexBuffer.get(), nullptr, IndexBuffer.get(), uniforms.size(),
|
||||
uniforms.data(), unistages.data(), unioffs.data(), unisizes.data(), texs.size(),
|
||||
texs.data(), nullptr, nullptr);
|
||||
}
|
||||
|
||||
void ImGuiEngine::BuildShaderDataBindings(boo::IGraphicsDataFactory::Context& ctx) {
|
||||
for (int i = 0; i < ImGuiUserTextureID_MAX; ++i) {
|
||||
ShaderDataBindings[i] = BuildShaderDataBinding(ctx, Textures[i].get());
|
||||
}
|
||||
ResourceBindings.clear();
|
||||
}
|
||||
|
||||
bool ImGuiWindowCallback::m_mouseCaptured = false;
|
||||
|
|
|
@ -29,6 +29,9 @@ public:
|
|||
static void End();
|
||||
static void Draw(boo::IGraphicsCommandQueue* gfxQ);
|
||||
|
||||
static boo::ObjToken<boo::IShaderDataBinding> BuildShaderDataBinding(boo::IGraphicsDataFactory::Context& ctx,
|
||||
boo::ObjToken<boo::ITexture> texture);
|
||||
|
||||
private:
|
||||
static void BuildShaderDataBindings(boo::IGraphicsDataFactory::Context& ctx);
|
||||
};
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <cstdint>
|
||||
|
||||
#include "Runtime/RetroTypes.hpp"
|
||||
#include <zeus/CVector2f.hpp>
|
||||
|
||||
#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
|
@ -7,12 +8,23 @@
|
|||
// Use 32-bit index type for boo
|
||||
#define ImDrawIdx uint32_t
|
||||
|
||||
enum ImUserTextureID {
|
||||
enum ImUserTextureID : uint8_t {
|
||||
ImGuiUserTextureID_Atlas,
|
||||
ImGuiUserTextureID_MetaforceIcon,
|
||||
ImGuiUserTextureID_MAX,
|
||||
};
|
||||
#define ImTextureID ImUserTextureID
|
||||
struct ImUserTexture {
|
||||
ImUserTextureID textureId = ImGuiUserTextureID_MAX;
|
||||
metaforce::SObjectTag objectTag{};
|
||||
|
||||
ImUserTexture() noexcept = default;
|
||||
ImUserTexture(long /* null */) noexcept {}
|
||||
ImUserTexture(ImUserTextureID textureId) noexcept : textureId(textureId) {}
|
||||
ImUserTexture(metaforce::SObjectTag objectTag) noexcept : objectTag(objectTag) {}
|
||||
bool operator==(const ImUserTexture& rhs) const { return textureId == rhs.textureId && objectTag == rhs.objectTag; }
|
||||
operator intptr_t() const { return (intptr_t(textureId) << 56) | objectTag.id.Value(); }
|
||||
};
|
||||
#define ImTextureID ImUserTexture
|
||||
|
||||
#define IM_VEC2_CLASS_EXTRA \
|
||||
ImVec2(const zeus::CVector2f& v) { \
|
||||
|
|
Loading…
Reference in New Issue