#include "Commands/ProjectCommands.h" #include "Core/EditorContext.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace fs = std::filesystem; namespace { constexpr const char* kDefaultModelAssetPath = "Assets/Models/nahida/Avatar_Loli_Catalyst_Nahida.fbx"; constexpr const char* kDefaultSceneAssetPath = "Assets/Scenes/NahidaPreview.xc"; constexpr const char* kDefaultSceneName = "Nahida Preview"; std::shared_ptr MakeModelAssetItem( const fs::path& projectRoot, const std::string& modelAssetPath) { auto item = std::make_shared(); item->name = fs::path(modelAssetPath).filename().string(); item->type = "Model"; item->isFolder = false; item->fullPath = (projectRoot / fs::path(modelAssetPath)).string(); return item; } void ConfigurePreviewCamera(XCEngine::Components::GameObject& gameObject) { using namespace XCEngine; gameObject.GetTransform()->SetLocalPosition(Math::Vector3(0.0f, 1.3f, -2.75f)); gameObject.GetTransform()->SetLocalRotation(Math::Quaternion(0.104528f, 0.0f, 0.0f, 0.994522f)); auto* camera = gameObject.AddComponent(); camera->SetProjectionType(Components::CameraProjectionType::Perspective); camera->SetFieldOfView(35.0f); camera->SetNearClipPlane(0.01f); camera->SetFarClipPlane(100.0f); camera->SetDepth(0.0f); camera->SetPrimary(true); camera->SetClearMode(Components::CameraClearMode::Auto); camera->SetStackType(Components::CameraStackType::Base); camera->SetCullingMask(0xFFFFFFFFu); camera->SetViewportRect(Math::Rect(0.0f, 0.0f, 1.0f, 1.0f)); camera->SetClearColor(Math::Color(0.04f, 0.05f, 0.07f, 1.0f)); camera->SetSkyboxEnabled(false); camera->SetSkyboxTopColor(Math::Color(0.18f, 0.36f, 0.74f, 1.0f)); camera->SetSkyboxHorizonColor(Math::Color(0.78f, 0.84f, 0.92f, 1.0f)); camera->SetSkyboxBottomColor(Math::Color(0.92f, 0.93f, 0.95f, 1.0f)); } void ConfigureKeyLight(XCEngine::Components::GameObject& gameObject) { using namespace XCEngine; gameObject.GetTransform()->SetLocalPosition(Math::Vector3(2.5f, 3.0f, -2.0f)); gameObject.GetTransform()->SetLocalRotation(Math::Quaternion(0.21644f, -0.39404f, 0.09198f, 0.88755f)); auto* light = gameObject.AddComponent(); light->SetLightType(Components::LightType::Directional); light->SetColor(Math::Color(1.0f, 0.976f, 0.94f, 1.0f)); light->SetIntensity(1.4f); light->SetRange(10.0f); light->SetSpotAngle(30.0f); light->SetCastsShadows(true); } void ConfigureFillLight(XCEngine::Components::GameObject& gameObject) { using namespace XCEngine; gameObject.GetTransform()->SetLocalPosition(Math::Vector3(-1.75f, 1.5f, -1.25f)); gameObject.GetTransform()->SetLocalRotation(Math::Quaternion::Identity()); auto* light = gameObject.AddComponent(); light->SetLightType(Components::LightType::Point); light->SetColor(Math::Color(0.24f, 0.32f, 0.5f, 1.0f)); light->SetIntensity(0.35f); light->SetRange(10.0f); light->SetSpotAngle(30.0f); light->SetCastsShadows(false); } void ConfigureGround(XCEngine::Components::GameObject& gameObject) { using namespace XCEngine; gameObject.GetTransform()->SetLocalPosition(Math::Vector3::Zero()); gameObject.GetTransform()->SetLocalRotation(Math::Quaternion::Identity()); gameObject.GetTransform()->SetLocalScale(Math::Vector3(8.0f, 1.0f, 8.0f)); auto* meshFilter = gameObject.AddComponent(); meshFilter->SetMeshPath("builtin://meshes/plane"); auto* meshRenderer = gameObject.AddComponent(); meshRenderer->SetMaterialPath(0, "builtin://materials/default-primitive"); meshRenderer->SetCastShadows(true); meshRenderer->SetReceiveShadows(true); meshRenderer->SetRenderLayer(0); } std::string ParseArgValue(int argc, char** argv, const char* name, const char* fallback) { const std::string optionPrefix = std::string(name) + "="; for (int index = 1; index < argc; ++index) { const std::string argument = argv[index]; if (argument.rfind(optionPrefix, 0) == 0) { return argument.substr(optionPrefix.size()); } } return fallback != nullptr ? std::string(fallback) : std::string(); } } // namespace int main(int argc, char** argv) { using namespace XCEngine; const fs::path repoRoot(XCENGINE_EDITOR_REPO_ROOT); const std::string projectArg = ParseArgValue(argc, argv, "--project-root", nullptr); const fs::path projectRoot = projectArg.empty() ? (repoRoot / "project") : fs::path(projectArg); const std::string modelAssetPath = ParseArgValue(argc, argv, "--model-asset", kDefaultModelAssetPath); const std::string sceneAssetPath = ParseArgValue(argc, argv, "--scene-asset", kDefaultSceneAssetPath); const fs::path sceneFilePath = projectRoot / fs::path(sceneAssetPath); if (!fs::exists(projectRoot) || !fs::is_directory(projectRoot)) { std::cerr << "Project root does not exist: " << projectRoot << std::endl; return 1; } Editor::EditorContext context; context.SetProjectPath(projectRoot.string()); context.GetProjectManager().Initialize(projectRoot.string()); context.GetSceneManager().NewScene(kDefaultSceneName); auto& resourceManager = Resources::ResourceManager::Get(); resourceManager.Initialize(); resourceManager.SetResourceRoot(projectRoot.string().c_str()); auto* camera = context.GetSceneManager().CreateEntity("Preview Camera"); auto* keyLight = context.GetSceneManager().CreateEntity("Key Light"); auto* fillLight = context.GetSceneManager().CreateEntity("Fill Light"); auto* ground = context.GetSceneManager().CreateEntity("Ground"); auto* avatarRoot = context.GetSceneManager().CreateEntity("AvatarRoot"); if (camera == nullptr || keyLight == nullptr || fillLight == nullptr || ground == nullptr || avatarRoot == nullptr) { std::cerr << "Failed to create preview scene entities." << std::endl; return 1; } ConfigurePreviewCamera(*camera); ConfigureKeyLight(*keyLight); ConfigureFillLight(*fillLight); ConfigureGround(*ground); avatarRoot->GetTransform()->SetLocalPosition(Math::Vector3::Zero()); avatarRoot->GetTransform()->SetLocalRotation(Math::Quaternion::Identity()); avatarRoot->GetTransform()->SetLocalScale(Math::Vector3::One()); const auto modelItem = MakeModelAssetItem(projectRoot, modelAssetPath); auto* createdRoot = Editor::Commands::InstantiateModelAsset( context, modelItem, avatarRoot, "Instantiate Nahida Preview Model"); if (createdRoot == nullptr) { std::cerr << "Failed to instantiate model asset: " << modelAssetPath << std::endl; return 1; } createdRoot->SetName("NahidaUnityModel"); if (!context.GetSceneManager().SaveSceneAs(sceneFilePath.string())) { std::cerr << "Failed to save scene: " << sceneFilePath << std::endl; return 1; } resourceManager.UnloadAll(); resourceManager.SetResourceRoot(""); resourceManager.Shutdown(); std::cout << "Generated scene: " << sceneFilePath << std::endl; std::cout << "Model asset: " << modelAssetPath << std::endl; return 0; }