MetaCore/tests/FilamentImGuiDemo.cpp
2026-07-14 17:41:55 +08:00

129 lines
4.5 KiB
C++

#include <filament/Camera.h>
#include <filament/Engine.h>
#include <filament/RenderTarget.h>
#include <filament/Renderer.h>
#include <filament/Scene.h>
#include <filament/Skybox.h>
#include <filament/SwapChain.h>
#include <filament/Texture.h>
#include <filament/View.h>
#include <filament/Viewport.h>
#include <imgui.h>
#include <utils/Entity.h>
#include <utils/EntityManager.h>
#include "MetaCoreRender/MetaCoreImGuiHelper.h"
#include <cstdint>
#include <iostream>
using namespace filament;
int main() {
constexpr std::uint32_t displayWidth = 1280;
constexpr std::uint32_t displayHeight = 720;
constexpr std::uint32_t viewportWidth = 800;
constexpr std::uint32_t viewportHeight = 600;
std::cout << "[Demo] Creating headless Filament engine..." << std::endl;
// uiBlit currently ships OpenGL shader material data. The swap chain is
// offscreen, while Filament's Linux OpenGL platform still requires X11.
Engine* engine = Engine::create(Engine::Backend::OPENGL);
if (engine == nullptr) {
std::cerr << "[Demo] Failed to create Filament engine." << std::endl;
return 1;
}
Renderer* renderer = engine->createRenderer();
SwapChain* swapChain = engine->createSwapChain(displayWidth, displayHeight);
Scene* scene = engine->createScene();
View* sceneView = engine->createView();
View* uiView = engine->createView();
if (renderer == nullptr || swapChain == nullptr || scene == nullptr ||
sceneView == nullptr || uiView == nullptr) {
std::cerr << "[Demo] Failed to create Filament headless resources." << std::endl;
Engine::destroy(&engine);
return 1;
}
utils::Entity cameraEntity = utils::EntityManager::get().create();
Camera* camera = engine->createCamera(cameraEntity);
sceneView->setScene(scene);
sceneView->setCamera(camera);
Skybox* skybox = Skybox::Builder()
.color({1.0F, 0.0F, 1.0F, 1.0F})
.build(*engine);
scene->setSkybox(skybox);
Texture* viewportTexture = Texture::Builder()
.width(viewportWidth)
.height(viewportHeight)
.levels(1)
.usage(Texture::Usage::COLOR_ATTACHMENT | Texture::Usage::SAMPLEABLE)
.format(Texture::InternalFormat::RGBA8)
.build(*engine);
RenderTarget* renderTarget = RenderTarget::Builder()
.texture(RenderTarget::AttachmentPoint::COLOR, viewportTexture)
.build(*engine);
sceneView->setRenderTarget(renderTarget);
sceneView->setViewport({0, 0, viewportWidth, viewportHeight});
sceneView->setPostProcessingEnabled(true);
uiView->setViewport({0, 0, displayWidth, displayHeight});
uiView->setPostProcessingEnabled(false);
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
io.DisplaySize = ImVec2(static_cast<float>(displayWidth), static_cast<float>(displayHeight));
io.DeltaTime = 1.0F / 60.0F;
{
MetaCore::MetaCoreImGuiHelper imguiHelper(engine, uiView, "", ImGui::GetCurrentContext());
imguiHelper.setDisplaySize(displayWidth, displayHeight);
// This is a deterministic offscreen smoke demo rather than an interactive
// platform window. A few frames are enough to exercise both render paths.
for (int frame = 0; frame < 3; ++frame) {
if (!renderer->beginFrame(swapChain)) {
continue;
}
renderer->render(sceneView);
ImGui::NewFrame();
ImGui::SetNextWindowSize(ImVec2(820.0F, 640.0F), ImGuiCond_Always);
ImGui::Begin("3D Viewport");
ImGui::Image(
reinterpret_cast<ImTextureID>(viewportTexture),
ImVec2(static_cast<float>(viewportWidth), static_cast<float>(viewportHeight)),
ImVec2(0.0F, 1.0F),
ImVec2(1.0F, 0.0F)
);
ImGui::End();
ImGui::Render();
imguiHelper.processImGuiCommands(ImGui::GetDrawData(), io);
renderer->render(uiView);
renderer->endFrame();
}
}
ImGui::DestroyContext();
engine->destroy(renderTarget);
engine->destroy(viewportTexture);
engine->destroy(skybox);
engine->destroy(sceneView);
engine->destroy(uiView);
engine->destroy(scene);
engine->destroyCameraComponent(cameraEntity);
utils::EntityManager::get().destroy(cameraEntity);
engine->destroy(renderer);
engine->destroy(swapChain);
Engine::destroy(&engine);
std::cout << "[Demo] Headless render completed." << std::endl;
return 0;
}