MetaCore/Apps/MetaCorePlayer/main.cpp

291 lines
13 KiB
C++

#include "MetaCorePlatform/MetaCoreWindow.h"
#include "MetaCoreFoundation/MetaCoreGeneratedReflection.h"
#include "MetaCoreFoundation/MetaCoreProject.h"
#include "MetaCoreRender/MetaCoreEditorViewportRenderer.h"
#include "MetaCoreRender/MetaCoreRenderDevice.h"
#include "MetaCoreRender/MetaCoreRenderTypes.h"
#include "MetaCoreRuntimeData/MetaCoreRuntimeDataDispatcher.h"
#include "MetaCoreRuntimeData/MetaCoreRuntimeDataProject.h"
#include "MetaCoreRuntimeData/MetaCoreRuntimeDataSource.h"
#include "MetaCoreScene/MetaCoreScenePackage.h"
#include "MetaCoreScene/MetaCoreScene.h"
#include <filesystem>
#include <iostream>
#include <memory>
namespace {
MetaCore::MetaCoreSceneView MetaCoreBuildPlayerSceneView() {
MetaCore::MetaCoreSceneView sceneView;
sceneView.CameraPosition = {0.0F, 2.5F, 6.5F};
sceneView.CameraTarget = {0.0F, 0.7F, 0.0F};
sceneView.CameraUp = {0.0F, 1.0F, 0.0F};
sceneView.VerticalFieldOfViewDegrees = 60.0F;
return sceneView;
}
[[nodiscard]] MetaCore::MetaCoreRuntimeProjectDocument MetaCoreBuildDefaultRuntimeProjectDocument() {
MetaCore::MetaCoreRuntimeProjectDocument document;
document.StartupScenePath = std::filesystem::path("Scenes") / "Main.mcscene";
document.DataSourcesPath = std::filesystem::path("Runtime") / "DataSources.mcruntime";
document.BindingsPath = std::filesystem::path("Runtime") / "Bindings.mcruntime";
document.DiagnosticsPath = std::filesystem::path("Runtime") / "Diagnostics.mcruntimestate";
return document;
}
[[nodiscard]] MetaCore::MetaCoreRuntimeDataSourcesDocument MetaCoreBuildDefaultRuntimeDataSourcesDocument() {
MetaCore::MetaCoreRuntimeDataSourcesDocument document;
document.Sources.push_back(MetaCore::MetaCoreDataSourceDefinition{
"replay-source",
"file_replay",
"Replay Source",
{MetaCore::MetaCoreDataSourceSetting{"file_path", "TestProject/Runtime/RuntimeReplay.mcstream"}},
true,
1000
});
document.DataPoints.push_back(MetaCore::MetaCoreDataPointDefinition{
"cube.position",
"replay-source",
"cube.position",
MetaCore::MetaCoreRuntimeValueType::Vec3
});
document.DataPoints.push_back(MetaCore::MetaCoreDataPointDefinition{
"cube.visible",
"replay-source",
"cube.visible",
MetaCore::MetaCoreRuntimeValueType::Bool
});
document.DataPoints.push_back(MetaCore::MetaCoreDataPointDefinition{
"cube.base_color",
"replay-source",
"cube.base_color",
MetaCore::MetaCoreRuntimeValueType::Vec3
});
document.DataPoints.push_back(MetaCore::MetaCoreDataPointDefinition{
"valve.visible",
"replay-source",
"valve.visible",
MetaCore::MetaCoreRuntimeValueType::Bool
});
document.DataPoints.push_back(MetaCore::MetaCoreDataPointDefinition{
"tank.base_color",
"replay-source",
"tank.base_color",
MetaCore::MetaCoreRuntimeValueType::Vec3
});
document.DataPoints.push_back(MetaCore::MetaCoreDataPointDefinition{
"alarm.intensity",
"replay-source",
"alarm.intensity",
MetaCore::MetaCoreRuntimeValueType::Double
});
return document;
}
[[nodiscard]] MetaCore::MetaCoreRuntimeBindingsDocument MetaCoreBuildDefaultRuntimeBindingsDocument() {
MetaCore::MetaCoreRuntimeBindingsDocument document;
document.Bindings.push_back(MetaCore::MetaCoreSceneBindingDefinition{
"binding.cube.position",
"cube.position",
3,
MetaCore::MetaCoreRuntimeBindingTarget::TransformPosition,
MetaCore::MetaCoreRuntimeMissingDataPolicy::KeepLastValue
});
document.Bindings.push_back(MetaCore::MetaCoreSceneBindingDefinition{
"binding.cube.visible",
"cube.visible",
3,
MetaCore::MetaCoreRuntimeBindingTarget::MeshRendererVisible,
MetaCore::MetaCoreRuntimeMissingDataPolicy::KeepLastValue
});
document.Bindings.push_back(MetaCore::MetaCoreSceneBindingDefinition{
"binding.cube.base_color",
"cube.base_color",
3,
MetaCore::MetaCoreRuntimeBindingTarget::MeshRendererBaseColor,
MetaCore::MetaCoreRuntimeMissingDataPolicy::KeepLastValue
});
document.Bindings.push_back(MetaCore::MetaCoreSceneBindingDefinition{
"binding.valve.visible",
"valve.visible",
4,
MetaCore::MetaCoreRuntimeBindingTarget::MeshRendererVisible,
MetaCore::MetaCoreRuntimeMissingDataPolicy::KeepLastValue
});
document.Bindings.push_back(MetaCore::MetaCoreSceneBindingDefinition{
"binding.tank.base_color",
"tank.base_color",
5,
MetaCore::MetaCoreRuntimeBindingTarget::MeshRendererBaseColor,
MetaCore::MetaCoreRuntimeMissingDataPolicy::KeepLastValue
});
document.Bindings.push_back(MetaCore::MetaCoreSceneBindingDefinition{
"binding.alarm.intensity",
"alarm.intensity",
6,
MetaCore::MetaCoreRuntimeBindingTarget::LightIntensity,
MetaCore::MetaCoreRuntimeMissingDataPolicy::KeepLastValue
});
return document;
}
} // namespace
int main(int argc, char* argv[]) {
if (argc > 0) {
std::filesystem::current_path(std::filesystem::path(argv[0]).parent_path());
}
MetaCore::MetaCoreWindow window;
if (!window.Initialize(1280, 720, "MetaCore Player")) {
std::cerr << "MetaCorePlayer: window initialize failed\n";
return 1;
}
MetaCore::MetaCoreRenderDevice renderDevice;
if (!renderDevice.Initialize(window)) {
std::cerr << "MetaCorePlayer: render device initialize failed\n";
return 1;
}
MetaCore::MetaCoreEditorViewportRenderer viewportRenderer;
if (!viewportRenderer.Initialize(renderDevice)) {
std::cerr << "MetaCorePlayer: viewport renderer initialize failed\n";
return 1;
}
const auto projectRoot = MetaCore::MetaCoreDiscoverProjectRoot();
if (!projectRoot.has_value()) {
std::cerr << "MetaCorePlayer: failed to discover project root\n";
return 1;
}
const std::filesystem::path projectPath = MetaCore::MetaCoreGetProjectFilePath(*projectRoot);
MetaCore::MetaCoreTypeRegistry typeRegistry;
MetaCore::MetaCoreRegisterRuntimeDataGeneratedTypes(typeRegistry);
const auto loadedRuntimeProjectDocument = MetaCore::MetaCoreReadRuntimeProjectDocument(
*projectRoot / "Runtime" / "ProjectRuntime.mcruntimecfg",
typeRegistry
);
const auto runtimeProjectDocument = loadedRuntimeProjectDocument.value_or(MetaCoreBuildDefaultRuntimeProjectDocument());
std::optional<MetaCore::MetaCoreSceneDocument> startupSceneDocument;
if (!runtimeProjectDocument.StartupScenePath.empty()) {
startupSceneDocument = MetaCore::MetaCoreReadScenePackage(*projectRoot / runtimeProjectDocument.StartupScenePath);
}
if (!startupSceneDocument.has_value()) {
startupSceneDocument = MetaCore::MetaCoreLoadStartupSceneDocument(projectPath);
}
MetaCore::MetaCoreScene scene;
if (startupSceneDocument.has_value()) {
MetaCore::MetaCoreSceneSnapshot snapshot;
snapshot.GameObjects = startupSceneDocument->GameObjects;
scene.RestoreSnapshot(snapshot);
std::cout << "MetaCorePlayer: loaded startup scene from project "
<< projectPath.string() << '\n';
} else {
scene = MetaCore::MetaCoreCreateDefaultScene();
std::cout << "MetaCorePlayer: startup scene unavailable, using built-in default scene\n";
}
MetaCore::MetaCoreRuntimeDataDispatcher runtimeDataDispatcher(scene);
const auto sourcesPath = (*projectRoot / runtimeProjectDocument.DataSourcesPath).lexically_normal();
const auto bindingsPath = (*projectRoot / runtimeProjectDocument.BindingsPath).lexically_normal();
const auto diagnosticsPath = (*projectRoot / runtimeProjectDocument.DiagnosticsPath).lexically_normal();
const auto loadedSourcesDocument = MetaCore::MetaCoreReadRuntimeDataSourcesDocument(sourcesPath, typeRegistry);
const auto loadedBindingsDocument = MetaCore::MetaCoreReadRuntimeBindingsDocument(bindingsPath, typeRegistry);
const auto sourcesDocument = loadedSourcesDocument.value_or(MetaCoreBuildDefaultRuntimeDataSourcesDocument());
const auto bindingsDocument = loadedBindingsDocument.value_or(MetaCoreBuildDefaultRuntimeBindingsDocument());
if (loadedSourcesDocument.has_value() && loadedBindingsDocument.has_value()) {
std::cout << "MetaCorePlayer: loaded runtime config from binary .mcruntime documents\n";
} else {
const bool sourcesExists = std::filesystem::exists(sourcesPath);
const bool bindingsExists = std::filesystem::exists(bindingsPath);
if ((sourcesExists && !loadedSourcesDocument.has_value()) ||
(bindingsExists && !loadedBindingsDocument.has_value())) {
std::cerr << "MetaCorePlayer: runtime config exists but is unreadable or corrupted, using built-in fallback config\n";
} else {
std::cout << "MetaCorePlayer: runtime config missing, using built-in fallback config\n";
}
}
runtimeDataDispatcher.SetDataPointDefinitions(sourcesDocument.DataPoints);
runtimeDataDispatcher.SetBindingDefinitions(bindingsDocument.Bindings);
std::unique_ptr<MetaCore::MetaCoreIRuntimeDataSourceAdapter> runtimeAdapter;
if (!sourcesDocument.Sources.empty()) {
runtimeAdapter = MetaCore::MetaCoreCreateRuntimeDataSourceAdapter(sourcesDocument.Sources.front().AdapterType);
if (runtimeAdapter == nullptr) {
std::cerr << "MetaCorePlayer: unsupported adapter type "
<< sourcesDocument.Sources.front().AdapterType << '\n';
return 1;
}
if (!runtimeAdapter->Configure(sourcesDocument.Sources.front())) {
std::cerr << "MetaCorePlayer: failed to configure runtime adapter error="
<< runtimeAdapter->GetStatus().LastError << '\n';
return 1;
}
if (!runtimeAdapter->Connect()) {
std::cerr << "MetaCorePlayer: failed to connect runtime adapter error="
<< runtimeAdapter->GetStatus().LastError << '\n';
return 1;
}
}
MetaCore::MetaCoreRuntimeDataSourceState lastReportedSourceState =
runtimeAdapter != nullptr
? runtimeAdapter->GetStatus().State
: MetaCore::MetaCoreRuntimeDataSourceState::Disconnected;
std::uint64_t diagnosticsWriteFrame = 0;
while (!window.ShouldClose()) {
window.BeginFrame();
const auto [windowWidth, windowHeight] = window.GetWindowSize();
viewportRenderer.SetViewportRect(MetaCore::MetaCoreViewportRect{
0.0F,
0.0F,
static_cast<float>(windowWidth),
static_cast<float>(windowHeight)
});
if (runtimeAdapter != nullptr) {
runtimeAdapter->Tick(1.0 / 60.0);
runtimeDataDispatcher.ApplyUpdates(runtimeAdapter->PollUpdates());
runtimeDataDispatcher.TickStaleness(runtimeAdapter->GetStatus().LastUpdateAt);
}
const auto diagnostics = runtimeDataDispatcher.BuildDiagnosticsSnapshot(
runtimeAdapter != nullptr
? std::vector<MetaCore::MetaCoreRuntimeDataSourceStatus>{runtimeAdapter->GetStatus()}
: std::vector<MetaCore::MetaCoreRuntimeDataSourceStatus>{}
);
if ((diagnosticsWriteFrame % 15ULL) == 0ULL) {
(void)MetaCore::MetaCoreWriteRuntimeDiagnosticsSnapshot(diagnosticsPath, diagnostics, typeRegistry);
}
++diagnosticsWriteFrame;
if (runtimeAdapter != nullptr && runtimeAdapter->GetStatus().State != lastReportedSourceState) {
std::cout << "MetaCorePlayer: data source state changed to "
<< static_cast<int>(runtimeAdapter->GetStatus().State)
<< " error=" << runtimeAdapter->GetStatus().LastError << '\n';
lastReportedSourceState = runtimeAdapter->GetStatus().State;
}
if (diagnostics.HasFaults) {
for (const MetaCore::MetaCoreRuntimeBindingStatus& bindingStatus : diagnostics.BindingStatuses) {
if (!bindingStatus.Healthy || bindingStatus.Stale) {
std::cout << "MetaCorePlayer: binding issue id=" << bindingStatus.BindingId
<< " stale=" << (bindingStatus.Stale ? "true" : "false")
<< " error=" << bindingStatus.LastError << '\n';
}
}
}
viewportRenderer.RenderSceneToViewport(scene, MetaCoreBuildPlayerSceneView());
renderDevice.RenderFrame();
renderDevice.PresentFrame();
window.EndFrame();
}
viewportRenderer.Shutdown();
renderDevice.Shutdown();
window.Shutdown();
return 0;
}