#include #include #include #include #include #include namespace raylib { #include } #include "bounding_box.h" #include "frame.h" #include "pack.h" #include "png.h" namespace fs = std::filesystem; struct Button { raylib::Rectangle rect; std::string text; bool hover = false; bool pressed() { hover = raylib::CheckCollisionPointRec(raylib::GetMousePosition(), rect); return hover and raylib::IsMouseButtonReleased(raylib::MOUSE_BUTTON_LEFT); }; void draw() const { raylib::DrawRectangleRec(rect, raylib::LIGHTGRAY); raylib::DrawRectangleLines(rect.x, rect.y, rect.width, rect.height, raylib::BLUE); raylib::DrawText(text.c_str(), (rect.x + rect.width / 2 - raylib::MeasureText(text.c_str(), 10) / 2), rect.y + 11, 10, raylib::DARKBLUE); }; }; void draw(const BoundingBox& box, const raylib::Vector2& offset, const raylib::Color& color) { const raylib::Rectangle rect = {offset.x + box.left, offset.y + box.top, static_cast(box.right - box.left), static_cast(box.bottom - box.top)}; raylib::DrawRectangleRec(rect, raylib::ColorAlpha(color, 0.3)); raylib::DrawRectangleLinesEx(rect, 3, color); } raylib::Image image_from_frame(const Frame& frame) { raylib::Image image = {0}; const int format = raylib::PIXELFORMAT_UNCOMPRESSED_R8G8B8; const unsigned int size = raylib::GetPixelDataSize(frame.width, frame.height, format); image.data = RL_MALLOC(size); memcpy(image.data, frame.data, size); image.width = frame.width; image.height = frame.height; image.mipmaps = 1; image.format = format; return image; } int main(int argc, const char* argv[]) { if (argc < 2 or (argc - 2) % 4 != 0) { std::cerr << "Usage: " << argv[0] << " path/to/image" << " [x1 y1 x2 y2 ...]\n" << "x/y points must be grouped by 4 to define bounding boxes\n"; return 1; } const fs::path input(argv[1]); if (!fs::exists(input)) { std::cerr << "Input file " << input << " does not exist.\n"; return 1; } const std::optional in_frame = load_png(input); if (!in_frame) { std::cerr << "Cannot load file " << input << "\n"; return 1; } std::vector bboxes; bboxes.reserve((argc - 2) / 4); int i = 2; while (i < argc) { const uint32_t x1 = atoi(argv[i]); const uint32_t y1 = atoi(argv[i + 1]); const uint32_t x2 = atoi(argv[i + 2]); const uint32_t y2 = atoi(argv[i + 3]); bboxes.push_back(BoundingBox({x1, y1, x2, y2})); i += 4; } const std::vector bbox_colors = {raylib::RED, raylib::GREEN, raylib::BLUE}; raylib::Vector2 win_size = {800, 450}; const int padding = 5; const raylib::Vector2 in_offset = {padding, 40}; raylib::InitWindow(win_size.x, win_size.y, "netatmo - rect packing"); raylib::SetTargetFPS(60); raylib::Image in_img = image_from_frame(*in_frame); raylib::Texture2D in_texture = raylib::LoadTextureFromImage(in_img); raylib::Image pack_img; raylib::Texture2D pack_texture; bool packed = false; win_size.x = std::max(win_size.x, in_offset.x + in_texture.width + padding); win_size.y = std::max(win_size.y, in_offset.y + in_texture.height + padding); raylib::SetWindowSize(win_size.x, win_size.y); const raylib::Vector2 b_size = {150, 30}; Button b_add_box = {{padding, padding, b_size.x, b_size.y}, "Add box"}; Button b_pack = {{padding * 2 + b_size.x, padding, b_size.x, b_size.y}, "Pack rects"}; while (!raylib::WindowShouldClose()) { // // Update // if (b_add_box.pressed()) { bboxes.push_back(BoundingBox({0, 0, 64, 64})); } if (b_pack.pressed()) { Frame f_packed = pack(*in_frame, bboxes); if (packed) { raylib::UnloadTexture(pack_texture); raylib::UnloadImage(pack_img); } pack_img = image_from_frame(f_packed); pack_texture = raylib::LoadTextureFromImage(pack_img); packed = true; win_size.x = std::max(win_size.x, in_offset.x + in_texture.width + padding * 2 + pack_texture.width); win_size.y = std::max( win_size.y, in_offset.y + std::max(in_texture.height, pack_texture.height) + padding); raylib::SetWindowSize(win_size.x, win_size.y); } // // Draw // raylib::BeginDrawing(); raylib::ClearBackground(raylib::RAYWHITE); b_add_box.draw(); b_pack.draw(); // Input image raylib::DrawTexture(in_texture, in_offset.x, in_offset.y, raylib::WHITE); raylib::DrawRectangleLines(in_offset.x, in_offset.y, in_texture.width, in_texture.height, raylib::BLACK); int c = 0; for (const auto& b : bboxes) { const auto& color = bbox_colors[c % bboxes.size()]; draw(b, in_offset, color); ++c; }; // Packed image if (packed) { const int offset_x = in_offset.x + in_texture.width + padding; raylib::DrawTexture(pack_texture, offset_x, in_offset.y, raylib::WHITE); raylib::DrawRectangleLines(offset_x, in_offset.y, pack_texture.width, pack_texture.height, raylib::BLACK); } raylib::EndDrawing(); } // Cleanup raylib::UnloadTexture(in_texture); raylib::UnloadImage(in_img); if (packed) { raylib::UnloadTexture(pack_texture); raylib::UnloadImage(pack_img); } raylib::CloseWindow(); return 0; }