2026-02-17 20:16:07 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @file main.cpp
|
|
|
|
|
|
* @brief Extra2D 图片显示示例
|
|
|
|
|
|
*
|
|
|
|
|
|
* 演示如何使用 RenderBackend 抽象接口加载和显示图片
|
|
|
|
|
|
* 此示例不依赖任何特定渲染后端(如 OpenGL)
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
2026-02-19 01:23:39 +08:00
|
|
|
|
#include "extra2d/core/service_interface.h"
|
|
|
|
|
|
#include "extra2d/core/service_locator.h"
|
2026-02-17 20:16:07 +08:00
|
|
|
|
#include <extra2d/extra2d.h>
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
|
|
|
|
using namespace extra2d;
|
|
|
|
|
|
|
|
|
|
|
|
class ImageDisplayScene : public Scene {
|
|
|
|
|
|
public:
|
2026-02-17 20:44:33 +08:00
|
|
|
|
void onEnter() override {
|
|
|
|
|
|
// 加载图片
|
|
|
|
|
|
// 注意:请确保有图片文件在 assets/images/ 目录下
|
|
|
|
|
|
try {
|
|
|
|
|
|
texture_ = renderer_->loadTexture("assets/images/demo.jpg");
|
|
|
|
|
|
std::cout << "Image loaded successfully!" << std::endl;
|
|
|
|
|
|
std::cout << " Size: " << texture_->getWidth() << "x"
|
|
|
|
|
|
<< texture_->getHeight() << std::endl;
|
|
|
|
|
|
} catch (...) {
|
|
|
|
|
|
std::cerr << "Failed to load image from assets/images/demo.jpg"
|
|
|
|
|
|
<< std::endl;
|
|
|
|
|
|
// 尝试使用备用路径
|
|
|
|
|
|
try {
|
|
|
|
|
|
texture_ = renderer_->loadTexture(
|
|
|
|
|
|
"examples/image_display/assets/images/demo.jpg");
|
|
|
|
|
|
std::cout << "Image loaded from alternate path!" << std::endl;
|
|
|
|
|
|
} catch (...) {
|
|
|
|
|
|
std::cerr << "Failed to load image from alternate path!" << std::endl;
|
|
|
|
|
|
texture_ = nullptr;
|
|
|
|
|
|
}
|
2026-02-17 20:16:07 +08:00
|
|
|
|
}
|
2026-02-17 20:44:33 +08:00
|
|
|
|
}
|
2026-02-17 20:16:07 +08:00
|
|
|
|
|
2026-02-17 20:44:33 +08:00
|
|
|
|
void onExit() override { texture_.reset(); }
|
2026-02-17 20:16:07 +08:00
|
|
|
|
|
2026-02-17 20:44:33 +08:00
|
|
|
|
void onRender(RenderBackend &renderer) override {
|
|
|
|
|
|
Scene::onRender(renderer);
|
2026-02-17 20:16:07 +08:00
|
|
|
|
|
2026-02-17 20:44:33 +08:00
|
|
|
|
if (!texture_) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2026-02-17 20:16:07 +08:00
|
|
|
|
|
2026-02-17 20:44:33 +08:00
|
|
|
|
// 使用 RenderBackend 的抽象接口绘制图片
|
2026-02-17 20:16:07 +08:00
|
|
|
|
// 不依赖任何特定后端(如 OpenGL)
|
|
|
|
|
|
// 自动批处理:无需手动调用 begin/endSpriteBatch
|
|
|
|
|
|
|
|
|
|
|
|
// 计算图片显示位置(居中显示)
|
|
|
|
|
|
float windowWidth = 1280.0f;
|
|
|
|
|
|
float windowHeight = 720.0f;
|
|
|
|
|
|
float imgWidth = static_cast<float>(texture_->getWidth());
|
|
|
|
|
|
float imgHeight = static_cast<float>(texture_->getHeight());
|
|
|
|
|
|
|
|
|
|
|
|
// 缩放图片以适应窗口(保持宽高比)
|
|
|
|
|
|
float scale = 1.0f;
|
|
|
|
|
|
if (imgWidth > windowWidth * 0.8f || imgHeight > windowHeight * 0.8f) {
|
|
|
|
|
|
float scaleX = (windowWidth * 0.8f) / imgWidth;
|
|
|
|
|
|
float scaleY = (windowHeight * 0.8f) / imgHeight;
|
|
|
|
|
|
scale = std::min(scaleX, scaleY);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
float displayWidth = imgWidth * scale;
|
|
|
|
|
|
float displayHeight = imgHeight * scale;
|
|
|
|
|
|
float x = (windowWidth - displayWidth) * 0.5f;
|
|
|
|
|
|
float y = (windowHeight - displayHeight) * 0.5f;
|
|
|
|
|
|
|
|
|
|
|
|
// 使用 RenderBackend 的 drawSprite 方法绘制图片
|
|
|
|
|
|
// 参数:纹理、目标矩形、源矩形、颜色、旋转角度、锚点
|
|
|
|
|
|
Rect destRect(x, y, displayWidth, displayHeight);
|
|
|
|
|
|
Rect srcRect(0, 0, imgWidth, imgHeight);
|
2026-02-17 20:44:33 +08:00
|
|
|
|
renderer.drawSprite(*texture_, destRect, srcRect, Colors::White, 0.0f,
|
|
|
|
|
|
Vec2(0, 0));
|
2026-02-17 20:16:07 +08:00
|
|
|
|
|
|
|
|
|
|
// 注意:无需手动调用 renderer.endSpriteBatch(),帧结束时会自动刷新
|
2026-02-17 20:44:33 +08:00
|
|
|
|
}
|
2026-02-17 20:16:07 +08:00
|
|
|
|
|
2026-02-17 20:44:33 +08:00
|
|
|
|
void setRenderer(RenderBackend *renderer) { renderer_ = renderer; }
|
2026-02-17 20:16:07 +08:00
|
|
|
|
|
|
|
|
|
|
private:
|
2026-02-17 20:44:33 +08:00
|
|
|
|
Ptr<Texture> texture_;
|
|
|
|
|
|
RenderBackend *renderer_ = nullptr;
|
2026-02-17 20:16:07 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2026-02-17 20:44:33 +08:00
|
|
|
|
int main(int argc, char *argv[]) {
|
|
|
|
|
|
(void)argc;
|
|
|
|
|
|
(void)argv;
|
|
|
|
|
|
|
|
|
|
|
|
std::cout << "Extra2D Image Display Demo - Starting..." << std::endl;
|
|
|
|
|
|
|
|
|
|
|
|
Application &app = Application::get();
|
|
|
|
|
|
|
|
|
|
|
|
// 注册模块
|
|
|
|
|
|
app.use<WindowModule>([](auto &cfg) {
|
|
|
|
|
|
cfg.w = 1280;
|
|
|
|
|
|
cfg.h = 720;
|
2026-02-19 01:23:39 +08:00
|
|
|
|
cfg.title = "Extra2D 图片显示示例";
|
2026-02-17 20:44:33 +08:00
|
|
|
|
cfg.priority = 0;
|
2026-02-19 01:23:39 +08:00
|
|
|
|
cfg.backend = "sdl2";
|
2026-02-17 20:44:33 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
2026-02-19 01:23:39 +08:00
|
|
|
|
app.use<RenderModule>([](auto &cfg) {
|
|
|
|
|
|
cfg.priority = 10;
|
|
|
|
|
|
cfg.backend = "opengl";
|
|
|
|
|
|
});
|
2026-02-17 20:44:33 +08:00
|
|
|
|
|
|
|
|
|
|
app.use<InputModule>([](auto &cfg) { cfg.priority = 20; });
|
|
|
|
|
|
|
|
|
|
|
|
if (!app.init()) {
|
|
|
|
|
|
std::cerr << "Failed to initialize application!" << std::endl;
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-19 01:23:39 +08:00
|
|
|
|
auto win = app.window();
|
2026-02-17 20:44:33 +08:00
|
|
|
|
|
|
|
|
|
|
// 设置事件监听
|
|
|
|
|
|
auto eventService = ServiceLocator::instance().getService<IEventService>();
|
|
|
|
|
|
if (eventService) {
|
|
|
|
|
|
eventService->addListener(EventType::KeyPressed, [](Event &e) {
|
|
|
|
|
|
auto &keyEvent = std::get<KeyEvent>(e.data);
|
|
|
|
|
|
if (keyEvent.keyCode == static_cast<int>(Key::Escape)) {
|
|
|
|
|
|
e.handled = true;
|
|
|
|
|
|
Application::get().quit();
|
|
|
|
|
|
}
|
2026-02-17 20:16:07 +08:00
|
|
|
|
});
|
2026-02-17 20:44:33 +08:00
|
|
|
|
}
|
2026-02-17 20:16:07 +08:00
|
|
|
|
|
2026-02-17 20:44:33 +08:00
|
|
|
|
// 获取渲染器
|
|
|
|
|
|
RenderBackend *renderer = app.renderer();
|
2026-02-17 20:16:07 +08:00
|
|
|
|
|
|
|
|
|
|
// 创建并配置场景
|
|
|
|
|
|
auto scene = makeShared<ImageDisplayScene>();
|
|
|
|
|
|
scene->setRenderer(renderer);
|
2026-02-17 20:44:33 +08:00
|
|
|
|
scene->setBackgroundColor(Color(0.1f, 0.1f, 0.15f, 1.0f));
|
|
|
|
|
|
|
|
|
|
|
|
if (win) {
|
|
|
|
|
|
scene->setViewportSize(static_cast<float>(win->width()),
|
|
|
|
|
|
static_cast<float>(win->height()));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 配置相机
|
|
|
|
|
|
auto cameraService = ServiceLocator::instance().getService<ICameraService>();
|
|
|
|
|
|
if (cameraService && win) {
|
2026-02-19 01:23:39 +08:00
|
|
|
|
cameraService->setViewportConfig([&](auto &cfg) {
|
|
|
|
|
|
cfg.logicWidth = static_cast<float>(win->width());
|
|
|
|
|
|
cfg.logicHeight = static_cast<float>(win->height());
|
|
|
|
|
|
cfg.mode = ViewportMode::AspectRatio;
|
|
|
|
|
|
});
|
2026-02-17 20:44:33 +08:00
|
|
|
|
cameraService->updateViewport(win->width(), win->height());
|
|
|
|
|
|
cameraService->applyViewportAdapter();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
app.enterScene(scene);
|
|
|
|
|
|
|
|
|
|
|
|
app.run();
|
|
|
|
|
|
|
|
|
|
|
|
app.shutdown();
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
2026-02-17 20:16:07 +08:00
|
|
|
|
}
|