#include #include #include #include #include #include #include #include // Shows a render target filling the whole panel. class ViewportPanel : public sophia::Panel { public: ViewportPanel(sophia::UI& ui, sophia::RenderTargetHandle target) : Panel{{.name = "Image", .windowFlags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse}}, ui{ui}, target{target} {} void onUpdate(const sophia::FrameInfo&) override { ui.image(target); } private: sophia::UI& ui; sophia::RenderTargetHandle target; }; // Displays an image file (anything stb_image reads: JPEG, PNG, BMP, ...) as a // sprite in a 2D scene, scaled to fit the viewport. // image_viewer [path] class ImageViewer : public sophia::Application { public: ImageViewer() : Application{{.width = 1000, .height = 750, .name = "ImageViewer"}} {} void onCreate() override { std::string path = args.size() > 1 ? args[1] : IMAGE_VIEWER_ASSET_DIR "/dog.jpeg"; sophia::SceneHandle sceneHandle = scenes().create(); sophia::Scene& scene = scenes().get(sceneHandle); camera = scene.createCamera(); sophia::TextureHandle texture = resources().load(path); imageSize = resources().getExtent(texture); // One world unit per image pixel; the camera zooms to fit. sophia::Entity image = scene.createEntity("Image"); image.addComponent( sophia::SpriteComponent{.texture = texture, .size = imageSize}); target = resources().create(); views().create({.scene = sceneHandle, .target = target, .clearColor = {0.1f, 0.1f, 0.15f, 1.f}}); panels().emplace(ui(), target); // panels().setDefaultLayout({.center = {"Image"}}); } void onUpdate(const sophia::FrameInfo&) override { // Fit the whole image: show enough height that neither dimension of the // image overflows the viewport. glm::vec2 viewport = resources().getExtent(target); float viewportAspect = viewport.x / viewport.y; camera.getComponent().ortho.height = std::max(imageSize.y, imageSize.x / viewportAspect); } private: sophia::Entity camera; sophia::RenderTargetHandle target{}; glm::vec2 imageSize{1.f}; }; SOPHIA_MAIN(ImageViewer)