banan-os/userspace/programs/ImageViewer/main.cpp

182 lines
4.7 KiB
C++

#include <BAN/Math.h>
#include <LibGUI/Window.h>
#include <LibImage/Image.h>
#include <stdio.h>
static constexpr size_t s_window_width = 400;
static constexpr size_t s_window_height = 400;
static constexpr float s_scale_factor = 0.9f;
static void run(LibImage::Image& image, LibGUI::Window& window)
{
int32_t xoff = static_cast<int32_t>(window.width() - image.width()) / 2;
int32_t yoff = static_cast<int32_t>(window.height() - image.height()) / 2;
float scale = 1.0f;
bool mouse_pressed = false;
int32_t mouse_x = 0;
int32_t mouse_y = 0;
bool should_close = false;
bool should_display = false;
bool linear = false;
const auto display_image =
[&]() -> void
{
window.texture().fill(0xFFFFFF);
for (int32_t winy = 0; winy < static_cast<int32_t>(window.height()); winy++)
{
for (int32_t winx = 0; winx < static_cast<int32_t>(window.width()); winx++)
{
LibImage::Image::Color color;
if (!linear)
{
const int32_t imgx = BAN::Math::round((winx - xoff) / scale);
const int32_t imgy = BAN::Math::round((winy - yoff) / scale);
if (imgx < 0 || imgx >= static_cast<int32_t>(image.width()))
continue;
if (imgy < 0 || imgy >= static_cast<int32_t>(image.height()))
continue;
color = image.get_color(imgx, imgy);
}
else
{
const float fimgx = (winx - xoff) / scale;
const float fimgy = (winy - yoff) / scale;
if (fimgx + 0.5f < 0 || fimgx + 0.5f >= image.width())
continue;
if (fimgy + 0.5f < 0 || fimgy + 0.5f >= image.height())
continue;
const int32_t imgl = BAN::Math::clamp<int32_t>(fimgx, 0, image.width() - 1);
const int32_t imgr = BAN::Math::clamp<int32_t>(imgl + 1, 0, image.width() - 1);
const int32_t imgt = BAN::Math::clamp<int32_t>(fimgy, 0, image.height() - 1);
const int32_t imgb = BAN::Math::clamp<int32_t>(imgt + 1, 0, image.height() - 1);
const auto tl = image.get_color(imgl, imgt);
const auto tr = image.get_color(imgr, imgt);
const auto bl = image.get_color(imgl, imgb);
const auto br = image.get_color(imgr, imgb);
const float weightx = fimgx - BAN::Math::floor(fimgx);
const float weighty = fimgy - BAN::Math::floor(fimgy);
color = LibImage::Image::Color::average(
LibImage::Image::Color::average(tl, tr, weightx),
LibImage::Image::Color::average(bl, br, weightx),
weighty
);
}
window.texture().set_pixel(winx, winy, color.as_argb());
}
}
window.invalidate();
};
window.set_close_window_event_callback([&] {
should_close = true;
});
window.set_resize_window_event_callback([&] {
should_display = true;
});
window.set_mouse_button_event_callback([&](auto event) {
if (event.button != LibInput::MouseButton::Left)
return;
mouse_pressed = event.pressed;
mouse_x = event.x;
mouse_y = event.y;
});
window.set_mouse_move_event_callback([&](auto event) {
if (mouse_pressed)
{
xoff += event.x - mouse_x;
yoff += event.y - mouse_y;
should_display = true;
}
mouse_x = event.x;
mouse_y = event.y;
});
window.set_mouse_scroll_event_callback([&](auto event) {
const float new_scale = scale * BAN::Math::pow<float>(s_scale_factor, -event.scroll);
xoff = mouse_x - (mouse_x - xoff) / scale * new_scale;
yoff = mouse_y - (mouse_y - yoff) / scale * new_scale;
scale = new_scale;
should_display = true;
});
window.set_key_event_callback([&](LibGUI::EventPacket::KeyEvent::event_t event) {
if (!event.pressed())
return;
switch (event.key)
{
case LibInput::Key::Space:
linear = !linear;
should_display = true;
break;
default:
break;
}
});
display_image();
auto attributes = window.get_attributes();
attributes.shown = true;
window.set_attributes(attributes);
while (!should_close)
{
window.wait_events();
window.poll_events();
if (should_display)
display_image();
should_display = false;
}
}
int main(int argc, char** argv)
{
if (argc != 2)
{
fprintf(stderr, "usage: %s image_file\n", argv[0]);
return 1;
}
auto image_or_error = LibImage::Image::load_from_file(argv[1]);
if (image_or_error.is_error())
{
fprintf(stderr, "Failed to load '%s': %s\n", argv[1], image_or_error.error().get_message());
return 1;
}
auto image = image_or_error.release_value();
auto window_attributes = LibGUI::Window::default_attributes;
window_attributes.resizable = true;
window_attributes.shown = false;
auto window_or_error = LibGUI::Window::create(s_window_width, s_window_height, argv[1], window_attributes);
if (window_or_error.is_error())
{
fprintf(stderr, "Failed to create an window: %s\n", window_or_error.error().get_message());
return 1;
}
auto window = window_or_error.release_value();
run(*image, *window);
return 0;
}