/* * * Copyright (C) 2024 Brett Terpstra * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef GP_IMAGE_TEST_IMAGE_H #define GP_IMAGE_TEST_IMAGE_H #include #include #include #include "blt/std/assert.h" #include "blt/std/utility.h" #include "blt/std/allocator.h" #include "blt/math/vectors.h" #include #include using image_data_t = std::array; inline blt::bump_allocator img_allocator(8192); class image { private: mutable std::variant data; public: image() { data = img_allocator.allocate(1); img_allocator.construct(std::get(data)); } image(const image& copy) { std::visit(blt::lambda_visitor{ [&](const image_data_t* d) { data = img_allocator.allocate(1); img_allocator.construct(std::get(data)); for (size_t i = 0; i < d->size(); i++) std::get(data)[i] = d[i]; }, [&](const blt::vec3& v) { this->data = v; }, [&](float f) { this->data = f; } }, copy.data); } image(image&& move) noexcept { data = std::move(move.data); move.data = nullptr; } image& operator=(const image& copy) { if (© == this) return *this; std::visit(blt::lambda_visitor{ [&](const image_data_t* d) { if (std::holds_alternative(data)) img_allocator.deallocate(std::get(data), 1); data = img_allocator.allocate(1); img_allocator.construct(std::get(data)); for (size_t i = 0; i < d->size(); i++) std::get(data)[i] = d[i]; }, [&](const blt::vec3& v) { this->data = v; }, [&](float f) { this->data = f; } }, copy.data); return *this; }; image& operator=(image&& move) noexcept { std::swap(move.data, data); return *this; } image(const blt::vec3& v): data(v) {} image(float f): data(f) {} image_data_t& getData() { if (std::holds_alternative(data)) return *std::get(data); else { blt::vec3 color = std::visit(blt::lambda_visitor{ [](const image_data_t*) -> blt::vec3 { BLT_ASSERT("There has been an error in the matrix. You should not have gotten here!"); return {}; }, [](const blt::vec3& v) -> blt::vec3 { return v; }, [](float f) -> blt::vec3 { return blt::vec3{f, f, f}; } }, data); data = img_allocator.allocate(1); img_allocator.construct(std::get(data)); for (auto& v : *std::get(data)) v = color; return *std::get(data); } } [[nodiscard]] const image_data_t& getData() const { if (std::holds_alternative(data)) return *std::get(data); else { blt::vec3 color = std::visit(blt::lambda_visitor{ [](const image_data_t*) -> blt::vec3 { BLT_ASSERT("There has been an error in the matrix. You should not have gotten here!"); return {}; }, [](const blt::vec3& v) -> blt::vec3 { return v; }, [](float f) -> blt::vec3 { return blt::vec3{f, f, f}; } }, data); data = img_allocator.allocate(1); img_allocator.construct(std::get(data)); for (auto& v : *std::get(data)) v = color; return *std::get(data); } } [[nodiscard]] blt::vec3 get(blt::i32 x = 0, blt::i32 y = 0) const { return std::visit(blt::lambda_visitor{ [x, y](const image_data_t* d) -> blt::vec3 { if (x < 0 || y < 0 || x >= width || y >= height) return blt::vec3{0, 0, 0}; return (*d)[y * height + x]; }, [](const blt::vec3& v) -> blt::vec3 { return v; }, [](float f) -> blt::vec3 { return blt::vec3{f, f, f}; } }, data); } void set(const blt::vec3& c, blt::i32 x, blt::i32 y) { if (!std::holds_alternative(data)) { data = img_allocator.allocate(1); img_allocator.construct(std::get(data)); } (*std::get(data))[y * height + x] = c; } ~image() { if (std::holds_alternative(data)) img_allocator.deallocate(std::get(data), 1); } }; #endif //GP_IMAGE_TEST_IMAGE_H