v0.1.0: software map renderer + SDL3 window viewer
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
module;
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
export module ra3.ui;
|
||||
|
||||
export import ra3.core;
|
||||
import ra3.render;
|
||||
|
||||
/**
|
||||
* A minimal SDL3 window for viewing a rendered scene.
|
||||
*
|
||||
* Controls: drag with the left mouse button to pan, wheel to zoom, Esc/close
|
||||
* to quit. When no display is available `run_viewer` returns false so the
|
||||
* caller can fall back to an offscreen image.
|
||||
*/
|
||||
export namespace ra3::ui {
|
||||
/** Window parameters. */
|
||||
struct viewer_options {
|
||||
std::string title = "OpenRA3";
|
||||
int width = 1024;
|
||||
int height = 768;
|
||||
};
|
||||
|
||||
/**
|
||||
* Show `scene` in a window until the user quits.
|
||||
*
|
||||
* @return true if the window ran; false if video init or window creation
|
||||
* failed (typically no display).
|
||||
*/
|
||||
[[nodiscard]] inline auto run_viewer(const ra3::render::image &scene, const viewer_options &options) -> bool {
|
||||
if (scene.empty()) return false;
|
||||
if (!SDL_Init(SDL_INIT_VIDEO)) return false;
|
||||
|
||||
SDL_Window *window = SDL_CreateWindow(options.title.c_str(), options.width, options.height, SDL_WINDOW_RESIZABLE);
|
||||
if (window == nullptr) {
|
||||
SDL_Quit();
|
||||
return false;
|
||||
}
|
||||
SDL_Renderer *renderer = SDL_CreateRenderer(window, nullptr);
|
||||
if (renderer == nullptr) {
|
||||
SDL_DestroyWindow(window);
|
||||
SDL_Quit();
|
||||
return false;
|
||||
}
|
||||
SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, static_cast<int>(scene.width()),
|
||||
static_cast<int>(scene.height()));
|
||||
if (texture == nullptr) {
|
||||
SDL_DestroyRenderer(renderer);
|
||||
SDL_DestroyWindow(window);
|
||||
SDL_Quit();
|
||||
return false;
|
||||
}
|
||||
SDL_UpdateTexture(texture, nullptr, scene.data(), static_cast<int>(scene.width()) * 4);
|
||||
SDL_SetTextureScaleMode(texture, SDL_SCALEMODE_NEAREST);
|
||||
|
||||
float zoom = 1.0F;
|
||||
float pan_x = 0.0F;
|
||||
float pan_y = 0.0F;
|
||||
bool running = true;
|
||||
SDL_Event event;
|
||||
while (running) {
|
||||
while (SDL_PollEvent(&event)) {
|
||||
if (event.type == SDL_EVENT_QUIT) {
|
||||
running = false;
|
||||
} else if (event.type == SDL_EVENT_KEY_DOWN && event.key.key == SDLK_ESCAPE) {
|
||||
running = false;
|
||||
} else if (event.type == SDL_EVENT_MOUSE_WHEEL) {
|
||||
zoom *= event.wheel.y > 0.0F ? 1.1F : (1.0F / 1.1F);
|
||||
zoom = std::clamp(zoom, 0.1F, 20.0F);
|
||||
} else if (event.type == SDL_EVENT_MOUSE_MOTION && (event.motion.state & SDL_BUTTON_LMASK) != 0U) {
|
||||
pan_x += event.motion.xrel;
|
||||
pan_y += event.motion.yrel;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
||||
SDL_RenderClear(renderer);
|
||||
const SDL_FRect dst{pan_x, pan_y, static_cast<float>(scene.width()) * zoom, static_cast<float>(scene.height()) * zoom};
|
||||
SDL_RenderTexture(renderer, texture, nullptr, &dst);
|
||||
SDL_RenderPresent(renderer);
|
||||
}
|
||||
|
||||
SDL_DestroyTexture(texture);
|
||||
SDL_DestroyRenderer(renderer);
|
||||
SDL_DestroyWindow(window);
|
||||
SDL_Quit();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user