diff --git a/CMakeLists.txt b/CMakeLists.txt index f0dd72da..8c86700f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -149,9 +149,9 @@ add_test(NAME Logging COMMAND FunGame Test Logging) add_test(NAME ChunkDataTest COMMAND FunGame Test ChunkDataTest) add_test(NAME LoadManifest COMMAND FunGame Test LoadManifest) add_test(NAME PathFinderTest COMMAND FunGame Test PathFinderTest) +add_test(NAME ColorImageTest COMMAND FunGame Test ColorImageTest) add_test(NAME LuaMap COMMAND FunGame Test Lua Map) add_test(NAME LuaLogging COMMAND FunGame Test Lua Logging) add_test(NAME LuaLoadTime COMMAND FunGame Test Lua LoadTime) add_test(NAME LuaLoadScript COMMAND FunGame Test Lua LoadScript) add_test(NAME LuaTransferScript COMMAND FunGame Test Lua TransferScript) - diff --git a/src/gui/render/gpu_data/frame_buffer.cpp b/src/gui/render/gpu_data/frame_buffer.cpp index 19a9867b..5f5a82f6 100644 --- a/src/gui/render/gpu_data/frame_buffer.cpp +++ b/src/gui/render/gpu_data/frame_buffer.cpp @@ -55,12 +55,12 @@ FrameBufferBase::copy_to( ); } -std::shared_ptr +std::expected FrameBufferBase::read_data(int8_t color_component) const { return read_data(0, 0, width_, height_, color_component); } -std::shared_ptr +std::expected FrameBufferBase::read_data( screen_size_t start_w, screen_size_t start_h, screen_size_t image_w, screen_size_t image_h, int8_t color_component @@ -72,10 +72,11 @@ FrameBufferBase::read_data( FrameBufferHandler& fbh = FrameBufferHandler::instance(); fbh.bind_fbo(frame_buffer); // need to crate a locking accessor + // choose which component we are reading from if (color_component == DEPTH_COMPONENT_ID) { if (!depth_buffer_) { LOG_ERROR(logging::opengl_logger, "No depth Component to read from"); - return {}; + return std::unexpected(1); } type = depth_buffer_->get_type(); format = depth_buffer_->get_format(); @@ -87,7 +88,7 @@ FrameBufferBase::read_data( logging::opengl_logger, "Color component {} does not exist.", color_component ); - return {}; + return std::unexpected(1); } const auto& color_texture = render_texture_.at(color_component); if (!color_texture) { @@ -95,7 +96,7 @@ FrameBufferBase::read_data( logging::opengl_logger, "Color component {} exist, but has no value.", color_component ); - return {}; + return std::unexpected(1); } type = color_texture->get_type(); format = color_texture->get_format(); @@ -111,46 +112,33 @@ FrameBufferBase::read_data( read_format = GPUPixelReadFormat::RGBA; break; default: - LOG_ERROR(logging::opengl_logger, "Cannot read from depth texture"); - return {}; + LOG_ERROR(logging::opengl_logger, "No known format."); + return std::unexpected(2); } // GLuint attachment = GL_COLOR_ATTACHMENT0 + color_component; } - // type - // number of - size_t format_size = get_size(read_format); - size_t type_size = get_size(type) / sizeof(char); - std::shared_ptr data(new char[image_w * image_h * format_size * type_size]); - - glReadPixels( - start_w, start_h, image_w, image_h, static_cast(read_format), - static_cast(type), data.get() - ); if (type != GPUPixelType::FLOAT) { LOG_ERROR(logging::opengl_logger, "NOT IMPLEMENTED MUST USE FLOAT"); + return std::unexpected(3); } - switch (format) { - case GPUPixelStorageFormat::RED: - case GPUPixelStorageFormat::DEPTH: - // in this case format_size should be 1 - return std::make_shared( - data, image_w, image_h, format_size - ); - case GPUPixelStorageFormat::RGB: - return std::make_shared( - data, image_w, image_h, format_size - ); - case GPUPixelStorageFormat::RGBA: - return std::make_shared( - data, image_w, image_h, format_size - ); + util::image::ImageVariant out = util::image::make_image(GPUPixelType::FLOAT, read_format, image_w, image_h); - default: - return {}; - } + const auto visitor = util::image::ImageVisitor( + [this, start_w, start_h, read_format](auto&& image) { + + glReadPixels( + start_w, start_h, image.get_width(), image.get_height(), static_cast(read_format), + static_cast(GPUPixelType::FLOAT), image.get_raw_data() + ); + } + ); + + std::visit(visitor, out); + + return out; } } // namespace gpu_data diff --git a/src/gui/render/gpu_data/frame_buffer.hpp b/src/gui/render/gpu_data/frame_buffer.hpp index d81cfcfb..0967847e 100644 --- a/src/gui/render/gpu_data/frame_buffer.hpp +++ b/src/gui/render/gpu_data/frame_buffer.hpp @@ -205,10 +205,11 @@ class FrameBufferBase { std::array params ) const; - std::shared_ptr + std::expected read_data(int8_t color_component = DEPTH_COMPONENT_ID) const; - std::shared_ptr read_data( + std::expected + read_data( screen_size_t start_w, screen_size_t start_h, screen_size_t image_w, screen_size_t image_h, int8_t color_component = DEPTH_COMPONENT_ID ) const; diff --git a/src/gui/render/gpu_data/texture.cpp b/src/gui/render/gpu_data/texture.cpp index 6a4bf91e..1b3b91d1 100644 --- a/src/gui/render/gpu_data/texture.cpp +++ b/src/gui/render/gpu_data/texture.cpp @@ -72,7 +72,7 @@ Texture2D::connect_depth_texture(GLuint framebuffer_ID) { } void -Texture2D::setup(std::shared_ptr image) { +Texture2D::load_settings() { #if DEBUG() GlobalContext& context = GlobalContext::instance(); if (!context.is_main_thread()) { @@ -98,22 +98,22 @@ Texture2D::setup(std::shared_ptr image) { glTexParameteri(target, GL_TEXTURE_COMPARE_MODE, settings_.compare_mode); } // set other paremeters +} - if (image) { - load_data(image); +void +Texture2D::setup() { + // bind + if (settings_.multisample) { + glTexImage2DMultisample( + GL_TEXTURE_2D_MULTISAMPLE, settings_.samples, + static_cast(settings_.internal_format), width_, height_, GL_TRUE + ); } else { - if (settings_.multisample) { - glTexImage2DMultisample( - GL_TEXTURE_2D_MULTISAMPLE, settings_.samples, - static_cast(settings_.internal_format), width_, height_, GL_TRUE - ); - } else { - glTexImage2D( - GL_TEXTURE_2D, 0, static_cast(settings_.internal_format), - width_, height_, 0, static_cast(settings_.read_format), - static_cast(settings_.type), nullptr - ); - } + glTexImage2D( + GL_TEXTURE_2D, 0, static_cast(settings_.internal_format), + width_, height_, 0, static_cast(settings_.read_format), + static_cast(settings_.type), nullptr + ); } } @@ -122,65 +122,50 @@ Texture2D::Texture2D( ) : width_(width), height_(height), settings_(settings) { if (differed) { GlobalContext& context = GlobalContext::instance(); - context.push_opengl_task([this]() { setup(nullptr); }); + context.push_opengl_task([this]() { load_settings(); setup(); }); } else { - setup(nullptr); + load_settings(); + setup(); } } Texture2D::Texture2D( - std::shared_ptr image, TextureSettings settings, bool differed -) : settings_(settings) { - if (!image) { - return; - } - width_ = image->get_width(); - height_ = image->get_height(); + util::image::ImageVariant image, TextureSettings settings, bool differed +) : + settings_(settings) { +// width_ = image->get_width(); +// height_ = image->get_height(); if (differed) { GlobalContext& context = GlobalContext::instance(); - context.push_opengl_task([this, image]() { setup(image); }); + context.push_opengl_task([this, image]() { load_settings(); load_image(image); }); } else { - setup(image); + load_settings(); + load_image(image); } } void -Texture2D::load_data(std::shared_ptr image) { - // TODO lots of checks - if (settings_.multisample) { - LOG_ERROR(logging::opengl_logger, "Cannot write data to multisample texture"); - return; - } - if (settings_.internal_format == gpu_data::GPUPixelStorageFormat::DEPTH) { - // - } - width_ = image->get_width(); - height_ = image->get_height(); - glTexImage2D( - GL_TEXTURE_2D, 0, static_cast(settings_.internal_format), - image->get_width(), image->get_height(), 0, - static_cast(settings_.read_format), static_cast(settings_.type), - image->data() +Texture2D::load_image(util::image::ImageVariant image) { + const auto visitor = util::image::ImageVisitor( + [this](auto&& image) {this->load_data(image);} ); - if (settings_.type == GPUPixelType::FLOAT - || settings_.type == GPUPixelType::HALF_FLOAT) { - glGenerateMipmap(GL_TEXTURE_2D); - } + + std::visit(visitor, image); } -std::shared_ptr +std::expected Texture2D::get_image() const { // multiplying by 2 fixes the memory error, but that can't possibly be correct. // TODO GL_PACK_ALIGNMENT size_t data_size = width_ * height_ * get_size(settings_.type) * get_size(settings_.read_format) * 2; - std::shared_ptr data = std::make_shared(data_size); +// std::shared_ptr data = std::make_shared(data_size); if (settings_.multisample) { LOG_ERROR(logging::opengl_logger, "Cannot load multisample texture to image."); - return nullptr; + return std::unexpected(1); } glBindTexture(GL_TEXTURE_2D, texture_ID_); @@ -214,81 +199,22 @@ Texture2D::get_image() const { #endif - glGetTexImage( - GL_TEXTURE_2D, 0, static_cast(settings_.read_format), - static_cast(settings_.type), data.get() - ); + util::image::ImageVariant out = util::image::make_image(settings_.type, settings_.read_format, width_, height_); - switch (settings_.type) { - case GPUPixelType::FLOAT: - case GPUPixelType::HALF_FLOAT: - switch (settings_.read_format) { - case GPUPixelReadFormat::DEPTH_COMPONENT: - case GPUPixelReadFormat::DEPTH_STENCIL: - case GPUPixelReadFormat::RED: - case GPUPixelReadFormat::GREEN: - case GPUPixelReadFormat::BLUE: - return std::make_shared( - data, width_, height_, get_size(settings_.type) - ); - case GPUPixelReadFormat::RGB: - case GPUPixelReadFormat::BGR: - return std::make_shared( - data, width_, height_, get_size(settings_.type) - ); - - case GPUPixelReadFormat::RGBA: - case GPUPixelReadFormat::BGRA: - return std::make_shared( - data, width_, height_, get_size(settings_.type) - ); - - default: - LOG_ERROR( - logging::opengl_logger, - "Cannot load image. Unknown read_format {}.", - static_cast(settings_.read_format) - ); - return nullptr; - } - case GPUPixelType::UNSIGNED_BYTE: - switch (settings_.read_format) { - case GPUPixelReadFormat::DEPTH_COMPONENT: - case GPUPixelReadFormat::DEPTH_STENCIL: - case GPUPixelReadFormat::RED: - case GPUPixelReadFormat::GREEN: - case GPUPixelReadFormat::BLUE: - return std::make_shared( - data, width_, height_, get_size(settings_.type) - ); - case GPUPixelReadFormat::RGB: - case GPUPixelReadFormat::BGR: - return std::make_shared( - data, width_, height_, get_size(settings_.type) - ); - - case GPUPixelReadFormat::RGBA: - case GPUPixelReadFormat::BGRA: - return std::make_shared( - data, width_, height_, get_size(settings_.type) - ); - - default: - LOG_ERROR( - logging::opengl_logger, - "Cannot load image. Unknown read_format {}.", - static_cast(settings_.read_format) - ); - return nullptr; - } - default: - LOG_ERROR( - logging::opengl_logger, "Cannot load image. Unknown type {}.", - static_cast(settings_.type) + const auto visitor = util::image::ImageVisitor( + [this](auto&& image) { + glGetTexImage( + GL_TEXTURE_2D, 0, static_cast(this->settings_.read_format), + static_cast(this->settings_.type), static_cast(image.get_raw_data()) ); - return nullptr; + } + ); + + std::visit(visitor, out); + + return out; + } -} } // namespace gpu_data diff --git a/src/gui/render/gpu_data/texture.hpp b/src/gui/render/gpu_data/texture.hpp index a7302ee4..7b95a82a 100644 --- a/src/gui/render/gpu_data/texture.hpp +++ b/src/gui/render/gpu_data/texture.hpp @@ -4,6 +4,7 @@ #include "data_types.hpp" #include "types.hpp" #include "util/image.hpp" +#include #include #include @@ -82,7 +83,34 @@ class Texture2D : virtual public GPUDataRenderBuffer { const TextureSettings settings_; GLuint texture_ID_; - void setup(std::shared_ptr image); + void load_settings(); + + void setup(); + + void bind(); + + template + void load_data_(T image) { + if (settings_.multisample) { + LOG_ERROR(logging::opengl_logger, "Cannot write data to multisample texture"); + return; + } + if (settings_.internal_format == gpu_data::GPUPixelStorageFormat::DEPTH) { + // Not sure what I wanted to put here + } + width_ = image.get_width(); + height_ = image.get_height(); + glTexImage2D( + GL_TEXTURE_2D, 0, static_cast(settings_.internal_format), + width_, height_, 0, + static_cast(settings_.read_format), static_cast(settings_.type), + image.get_raw_data() + ); + if (settings_.type == GPUPixelType::FLOAT + || settings_.type == GPUPixelType::HALF_FLOAT) { + glGenerateMipmap(GL_TEXTURE_2D); + } + } public: Texture2D( @@ -91,11 +119,30 @@ class Texture2D : virtual public GPUDataRenderBuffer { ); Texture2D( - std::shared_ptr Image, TextureSettings settings = {}, + util::image::ImageVariant Image, TextureSettings settings = {}, bool differed = true ); - void load_data(std::shared_ptr image); + inline void load_data(util::image::MonochromeImage image) { + return load_data_(image); + } + inline void load_data(util::image::PolychromeImage image) { + return load_data_(image); + } + inline void load_data(util::image::PolychromeAlphaImage image) { + return load_data_(image); + } + inline void load_data(util::image::FloatMonochromeImage image) { + return load_data_(image); + } + inline void load_data(util::image::FloatPolychromeImage image) { + return load_data_(image); + } + inline void load_data(util::image::FloatPolychromeAlphaImage image) { + return load_data_(image); + } + + void load_image(util::image::ImageVariant image); ~Texture2D() { glDeleteTextures(1, &texture_ID_); } @@ -139,7 +186,9 @@ class Texture2D : virtual public GPUDataRenderBuffer { glBindTexture(target, texture_ID_); } - [[nodiscard]] std::shared_ptr get_image() const; + // instead of ints could return error enums + [[nodiscard]] std::expected + get_image() const; }; } // namespace gpu_data diff --git a/src/gui/render/structures/font.cpp b/src/gui/render/structures/font.cpp index 37936330..0d021723 100644 --- a/src/gui/render/structures/font.cpp +++ b/src/gui/render/structures/font.cpp @@ -45,7 +45,7 @@ FontTexture::FontTexture(std::filesystem::path font_file) { unsigned int max_height = 0; unsigned int total_width = 0; - std::unordered_map images; + std::unordered_map images; descender_height_ = -font_face->descender; ascender_height_ = -font_face->ascender; @@ -77,8 +77,8 @@ FontTexture::FontTexture(std::filesystem::path font_file) { } images.emplace( - c, util::image::ByteMonochromeImage( - data.data(), char_size.x, char_size.y, sizeof(char) + c, util::image::MonochromeImage( + char_size.x, char_size.y, data ) ); @@ -100,12 +100,12 @@ FontTexture::FontTexture(std::filesystem::path font_file) { } LOG_BACKTRACE(logging::main_logger, "Combining characters into single image."); - auto image = std::make_shared( + auto image = util::image::MonochromeImage( total_width, max_height, sizeof(char) ); for (unsigned char c = 0; c < 128; c++) { - image->draw_at( + image.draw_at( images.at(c), font_textures_[c].position_in_texture.x, font_textures_[c].position_in_texture.y ); @@ -113,7 +113,7 @@ FontTexture::FontTexture(std::filesystem::path font_file) { LOG_BACKTRACE(logging::main_logger, "Loading font to texture."); - image->transpose(); + image.transpose(); texture_ = std::make_shared(image, settings); GlobalContext& global_context = GlobalContext::instance(); diff --git a/src/gui/render/structures/model.hpp b/src/gui/render/structures/model.hpp index 517e34bf..900b4253 100644 --- a/src/gui/render/structures/model.hpp +++ b/src/gui/render/structures/model.hpp @@ -85,7 +85,7 @@ class ModelController : virtual public gui::gpu_data::GPUDataElementsInstanced { ) noexcept : model_mesh_(model_mesh, {}), model_textures_( - std::make_shared(vector_data) + util::image::FloatPolychromeAlphaImage(vector_data) ) {} inline virtual ~ModelController() {} diff --git a/src/gui/render/structures/window_texture.cpp b/src/gui/render/structures/window_texture.cpp index d54fa108..03521803 100644 --- a/src/gui/render/structures/window_texture.cpp +++ b/src/gui/render/structures/window_texture.cpp @@ -13,7 +13,7 @@ namespace gui { namespace render { WindowTexture::WindowTexture( - std::shared_ptr image, glm::ivec4 border_size, + util::image::ImageVariant image, glm::ivec4 border_size, glm::ivec4 side_lengths, glm::ivec2 inner_pattern_size, std::array texture_regions ) : @@ -54,7 +54,7 @@ WindowTexture::WindowTexture( } WindowTexture::WindowTexture( - std::shared_ptr image, const window_texture_data_t& texture_data + util::image::ImageVariant image, const window_texture_data_t& texture_data ) : WindowTexture( image, texture_data.border_size, texture_data.side_lengths, diff --git a/src/gui/render/structures/window_texture.hpp b/src/gui/render/structures/window_texture.hpp index 7860d26d..862e5256 100644 --- a/src/gui/render/structures/window_texture.hpp +++ b/src/gui/render/structures/window_texture.hpp @@ -132,13 +132,13 @@ class WindowTexture : public virtual gpu_data::GPUData { * */ WindowTexture( - std::shared_ptr image, glm::ivec4 border_size, + util::image::ImageVariant image, glm::ivec4 border_size, glm::ivec4 side_lengths, glm::ivec2 inner_pattern_size, std::array texture_regions ); WindowTexture( - std::shared_ptr image, + util::image::ImageVariant image, const window_texture_data_t& texture_data ); diff --git a/src/gui/the_buttons/text_widget.hpp b/src/gui/the_buttons/text_widget.hpp index e6b2eff9..a25479c9 100644 --- a/src/gui/the_buttons/text_widget.hpp +++ b/src/gui/the_buttons/text_widget.hpp @@ -73,7 +73,7 @@ class TextWidget : public virtual WidgetBase, public virtual gpu_data::GPUDataEl vertex_array_object_(differed), font_(font), text_(text), num_characters_(text_.length()), - wrap_text_(wrap_text), text_color_(text_color), text_scale_(text_scale) { + text_color_(text_color), wrap_text_(wrap_text), text_scale_(text_scale) { if (differed) { GlobalContext& context = GlobalContext::instance(); context.push_opengl_task([this]() { initialize(); }); diff --git a/src/gui/the_buttons/user_interface.cpp b/src/gui/the_buttons/user_interface.cpp index ffce03f2..bc431025 100644 --- a/src/gui/the_buttons/user_interface.cpp +++ b/src/gui/the_buttons/user_interface.cpp @@ -40,16 +40,6 @@ UserInterface::UserInterface(shader::ShaderHandler& shader_handler, uint8_t ui_s files::get_resources_path() / "shaders" / "overlay" / "TextWindow.frag" ); - // auto image_result = image::read_image(files::get_resources_path() / "textures" / - // "GenericBorder.png"); if (!image_result.has_value()) { - // LOG_ERROR(logging::file_io_logger, "Error Code {}", image_result.error()); - // return; - // } - // std::shared_ptr image = image_result.value(); - - // gpu_data::Texture2D border_texture(image, gui::gpu_data::TextureSettings{}, - // false); - // Overwrites anything that was there before std::function render_setup = []() { // Draw over everything @@ -100,7 +90,7 @@ UserInterface::update( } } -// maybe visitor pattern +// visitor pattern // double dispatch on render frames // render_border // render_text @@ -133,8 +123,6 @@ UserInterface::render_frame( bounding_box[0] + x_frame_position, bounding_box[1] + y_frame_position, bounding_box[2] - bounding_box[0], bounding_box[3] - bounding_box[1], 0, frame ); - - // frame->render_children(this, x_frame_position, y_frame_position); } void diff --git a/src/gui/ui/imgui_windows.cpp b/src/gui/ui/imgui_windows.cpp index 198529bc..845d87bb 100644 --- a/src/gui/ui/imgui_windows.cpp +++ b/src/gui/ui/imgui_windows.cpp @@ -136,14 +136,11 @@ display_data( ImGui::DragInt2("Sample Position", xy, 1.0, 0, 2000); const auto& mid_ground = scene.get_mid_ground_framebuffer(); - std::shared_ptr read_data = - mid_ground.read_data(xy[0], xy[1], 1, 1); - auto float_data = - std::dynamic_pointer_cast(read_data); + FrameBufferHandler& fbh = FrameBufferHandler::instance(); fbh.bind_fbo(0); - + ImGui::Text("Texture ID %i", mid_ground.get_depth_buffer()->value()); ImGui::Image( reinterpret_cast(mid_ground.get_depth_buffer()->value()), @@ -154,7 +151,7 @@ display_data( ImVec2(0, float(window_width) / float(mid_ground.get_width())), ImVec2(float(window_height) / float(mid_ground.get_height()), 0) ); - + ImGui::Text("Texture ID %i", mid_ground.get_texture(0)->value()); ImGui::Image( reinterpret_cast(mid_ground.get_texture(0)->value()), @@ -165,12 +162,17 @@ display_data( ImVec2(0, float(window_height) / float(mid_ground.get_height())), ImVec2(float(window_width) / float(mid_ground.get_width()), 0) ); - - if (!float_data) { + + auto read_data = + mid_ground.read_data(xy[0], xy[1], 1, 1); + if (!read_data.has_value()) { ImGui::Text("Cannot display depth. Something went wrong."); - + } + else if (!std::holds_alternative(read_data.value())) { // FloatMonochromeImage + ImGui::Text("Cannot display depth. Not float valued."); } else { - float depth_value = float_data->get_data(0, 0); + auto float_data = std::get(read_data.value()); + float depth_value = float_data.get_data(0, 0); ImGui::Text("Depth 32 %f", depth_value); diff --git a/src/gui/ui/user_interface_setup.cpp b/src/gui/ui/user_interface_setup.cpp index bd75ac87..491d9905 100644 --- a/src/gui/ui/user_interface_setup.cpp +++ b/src/gui/ui/user_interface_setup.cpp @@ -30,7 +30,7 @@ setup(the_buttons::UserInterface& user_interface) { LOG_ERROR(logging::file_io_logger, "Error Code {}", image_result.error()); return; } - std::shared_ptr image = image_result.value(); + util::image::ImageVariant image = image_result.value(); std::shared_ptr a_window = std::make_shared( @@ -62,7 +62,7 @@ setup(the_buttons::UserInterface& user_interface) { LOG_ERROR(logging::file_io_logger, "Error Code {}", image_result_2.error()); return; } - std::shared_ptr image_2 = image_result_2.value(); + util::image::ImageVariant image_2 = image_result_2.value(); std::shared_ptr a_widget = a_second_window->make( @@ -87,7 +87,7 @@ setup(the_buttons::UserInterface& user_interface) { LOG_ERROR(logging::file_io_logger, "Error Code {}", image_result_3.error()); return; } - std::shared_ptr image_3 = image_result_3.value(); + util::image::ImageVariant image_3 = image_result_3.value(); auto a_button = a_widget->make( std::make_shared(image_3, texture_data_3.value()), diff --git a/src/main.cpp b/src/main.cpp index bcb94283..7bb195a4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,6 +14,7 @@ #include "util/lua/lua_tests.hpp" #include "util/mesh.hpp" #include "util/png_image.hpp" +#include "util/image.hpp" #include "util/time.hpp" #include "util/voxel_io.hpp" #include "world/biome.hpp" @@ -212,14 +213,14 @@ color_image_text() { LOG_ERROR(logging::file_io_logger, "Error Code {}", image_result.error()); return 1; } - std::shared_ptr image = image_result.value(); + util::image::ImageVariant image = image_result.value(); - auto FPAimage = - std::dynamic_pointer_cast(image); + auto FPAimage = std::get(image); + // std::dynamic_pointer_cast<>(image; auto result = image::write_image( - *FPAimage.get(), - files::get_resources_path() / "textures" / "GenericBorder_out_test.png" + FPAimage, + files::get_root_path() / "logs" / "GenericBorder_out_test.png" ); if (!result == image::write_result_t::WR_OK) { diff --git a/src/util/image.cpp b/src/util/image.cpp index 6dc35a59..2b995d44 100644 --- a/src/util/image.cpp +++ b/src/util/image.cpp @@ -1,146 +1,57 @@ #include "image.hpp" -#include "util/color.hpp" - -#include - namespace util { - namespace image { - -Image::Image(void* data, size_t width, size_t height, size_t data_size) : - width_(width), height_(height), data_size_(data_size), - data_(new char[width * height * data_size]) { - std::memcpy(data_.get(), data, width * height * data_size); -}; - -Image::Image(size_t width, size_t height, size_t data_size) : - width_(width), height_(height), data_size_(data_size), - data_(new char[width * height * data_size]) { - std::memset(data_.get(), char(0), width * height * data_size); -}; - -png_byte -FloatMonochromeImage::get_color(size_t i, size_t j) const { - assert(i < width_ && j < height_ && "Position must be within image."); - return read_data(data_, i * height_ + j)[0]; -} - -float -FloatMonochromeImage::get_data(size_t i, size_t j) const { - assert(i < width_ && j < height_ && "Position must be within image."); - return read_data_float(data_, i * height_ + j)[0]; -} - -std::array -FloatPolychromeImage::get_color(size_t i, size_t j) const { - assert(i < width_ && j < height_ && "Position must be within image."); - return read_data(data_, i * height_ + j); -} - -std::array -FloatPolychromeImage::get_data(size_t i, size_t j) const { - assert(i < width_ && j < height_ && "Position must be within image."); - return read_data_float(data_, i * height_ + j); -} - -FloatPolychromeAlphaImage_data_t -FloatPolychromeAlphaImage::pad_color_data( - const std::vector>& vector_data -) { - uint width = 0; - uint height = vector_data.size(); - - for (const auto& row : vector_data) { - if (row.size() > width) { - width = row.size(); - } - } - - std::shared_ptr data( - new char[width * height * sizeof(ColorFloat) / sizeof(char)] - ); - - size_t j = 0; - ColorFloat* float_color_data = reinterpret_cast(data.get()); - - for (const auto& row : vector_data) { - for (const auto& color_f : row) { - // data.push_back(color); - float_color_data[j] = color_f; - j++; - } - for (size_t i = 0; i < width - row.size(); i++) { - float_color_data[j] = color::black; - j++; - } - } - - return FloatPolychromeAlphaImage_data_t(data, width, height); + +ImageVariant +make_image(gui::gpu_data::GPUPixelType type, gui::gpu_data::GPUPixelReadFormat format, size_t width, size_t height, size_t width_bit_alignment){ + switch (type) { + case gui::gpu_data::GPUPixelType::FLOAT: + case gui::gpu_data::GPUPixelType::HALF_FLOAT: + switch (format) { + case gui::gpu_data::GPUPixelReadFormat::DEPTH_COMPONENT: + case gui::gpu_data::GPUPixelReadFormat::DEPTH_STENCIL: + case gui::gpu_data::GPUPixelReadFormat::RED: + case gui::gpu_data::GPUPixelReadFormat::GREEN: + case gui::gpu_data::GPUPixelReadFormat::BLUE: + return MonochromeImage(width, height, width_bit_alignment); + case gui::gpu_data::GPUPixelReadFormat::RGB: + case gui::gpu_data::GPUPixelReadFormat::BGR: + return MonochromeImage(width, height, width_bit_alignment); + + case gui::gpu_data::GPUPixelReadFormat::RGBA: + case gui::gpu_data::GPUPixelReadFormat::BGRA: + return MonochromeImage(width, height, width_bit_alignment); + } + case gui::gpu_data::GPUPixelType::UNSIGNED_BYTE: + switch (format) { + case gui::gpu_data::GPUPixelReadFormat::DEPTH_COMPONENT: + case gui::gpu_data::GPUPixelReadFormat::DEPTH_STENCIL: + case gui::gpu_data::GPUPixelReadFormat::RED: + case gui::gpu_data::GPUPixelReadFormat::GREEN: + case gui::gpu_data::GPUPixelReadFormat::BLUE: + return MonochromeImage( + width, height, width_bit_alignment + ); + case gui::gpu_data::GPUPixelReadFormat::RGB: + case gui::gpu_data::GPUPixelReadFormat::BGR: + return PolychromeImage( + width, height, width_bit_alignment + ); + + case gui::gpu_data::GPUPixelReadFormat::RGBA: + case gui::gpu_data::GPUPixelReadFormat::BGRA: + return PolychromeAlphaImage( + width, height, width_bit_alignment + ); + } + +} + // LOR error + abort(); } -std::array -FloatPolychromeAlphaImage::get_color(size_t i, size_t j) const { - assert(i < width_ && j < height_ && "Position must be within image."); - return read_data(data_, i * height_ + j); } -std::array -FloatPolychromeAlphaImage::get_data(size_t i, size_t j) const { - assert(i < width_ && j < height_ && "Position must be within image."); - return read_data_float(data_, i * height_ + j); } -#if __HAVE_FLOAT16 -// HALF FLOAT -png_byte -HALFFloatMonochromeImage::get_color(size_t i, size_t j) const { - assert(i < width_ && j < height_ && "Position must be within image."); - return read_data<_Float16, 1>(data_, i * height_ + j)[0]; -} - -std::array -HALFFloatPolychromeImage::get_color(size_t i, size_t j) const { - assert(i < width_ && j < height_ && "Position must be within image."); - return read_data<_Float16, 3>(data_, i * height_ + j); -} - -std::array -HALFFloatPolychromeAlphaImage::get_color(size_t i, size_t j) const { - assert(i < width_ && j < height_ && "Position must be within image."); - return read_data<_Float16, 4>(data_, i * height_ + j); -} -#endif - -png_byte -ByteMonochromeImage::get_color(size_t i, size_t j) const { - assert(i < width_ && j < height_ && "Position must be within image."); - return read_data_byte(data_, i * height_ + j)[0]; -} - -std::array -BytePolychromeImage::get_color(size_t i, size_t j) const { - assert(i < width_ && j < height_ && "Position must be within image."); - return read_data_byte(data_, i * height_ + j); -} - -std::array -BytePolychromeAlphaImage::get_color(size_t i, size_t j) const { - assert(i < width_ && j < height_ && "Position must be within image."); - return read_data_byte(data_, i * height_ + j); -} - -void -ByteMonochromeImage::draw_at( - const ByteMonochromeImage& other, size_t position_x, size_t position_y -) { - for (size_t i = 0; i < other.get_width(); i++) { - for (size_t j = 0; j < other.get_height(); j++) { - set_color(other.get_color(i, j), i + position_x, j + position_y); - } - } -} - -} // namespace image - -} // namespace util \ No newline at end of file diff --git a/src/util/image.hpp b/src/util/image.hpp index 9441c642..bcaa4b22 100644 --- a/src/util/image.hpp +++ b/src/util/image.hpp @@ -2,193 +2,138 @@ #include "types.hpp" #include "util/color.hpp" +#include "gui/render/gl_enums.hpp" #include -#include +#include +#include namespace util { namespace image { -struct FloatPolychromeAlphaImage_data_t { - std::shared_ptr data; - screen_size_t width; - screen_size_t height; -}; - -// t represents the underlying type of the data structure; -template -std::array -read_data(std::shared_ptr data, size_t offset) { - // assert(sizeof(T) == data_size_) - size_t bit_offset = offset * sizeof(T) * datum_number; - char* data_ptr = &data[bit_offset]; - T* pixel_data = reinterpret_cast(data_ptr); - std::array out; - for (size_t i = 0; i < datum_number; i++) { - // normalize data to size of png_byte - out[i] = pixel_data[i] * (2 >> sizeof(png_byte)); - } - return out; -} +/* +Image +v +different types, byte float [0, 1) -template -std::array -read_data_float(std::shared_ptr data, size_t offset) { - size_t bit_offset = offset * sizeof(T) * datum_number; - char* data_ptr = &data[bit_offset]; - T* pixel_data = reinterpret_cast(data_ptr); - std::array out; - for (size_t i = 0; i < datum_number; i++) { - out[i] = pixel_data[i]; - } - return out; -} +get_width, get_height, get_pixel(), and finally a settings struct -template -std::array -read_data_byte(std::shared_ptr data, size_t offset) { - // assert(sizeof(T) == data_size_) - size_t bit_offset = offset * sizeof(T) * datum_number; - char* data_ptr = &data[bit_offset]; - T* pixel_data = reinterpret_cast(data_ptr); - std::array out; - for (size_t i = 0; i < datum_number; i++) { - // normalize data to size of png_byte - out[i] = pixel_data[i]; - } - return out; -} +byte and float have get_data() which returns a byte of float -class Image { - // some data - protected: - size_t width_; - size_t height_; - size_t data_size_; - std::shared_ptr data_; - public: - inline virtual size_t - get_width() const { - return width_; - } +*/ - inline virtual size_t - get_height() const { - return height_; - } +//namespace { - inline virtual void* - data() const { - return data_.get(); +template +[[maybe_unused]] inline std::array +convert_to_color(std::array& data) { + std::array out_color; + for (size_t index = 0; index < n; index++) { + out_color[index] = data[index] * 256; } + return out_color; +} - inline Image( - std::shared_ptr data, size_t width, size_t height, size_t data_size - ) : width_(width), height_(height), data_size_(data_size), data_(data) {}; - - Image(void* data, size_t width, size_t height, size_t data_size); - - Image(size_t width, size_t height, size_t data_size); - - virtual ~Image() {} -}; +[[maybe_unused]] inline png_byte +convert_to_color(float data) { + return data * 255; +} -class MonochromeImage : public virtual Image { - public: - virtual png_byte get_color(size_t i, size_t j) const = 0; +template +[[maybe_unused]] inline std::array +convert_to_color(const std::array& data) { + return data; +} - inline virtual ~MonochromeImage() {} -}; +template +[[maybe_unused]] std::array +convert_to_color(std::array&& data) { + return data; +} -class PolychromeImage : public virtual Image { - public: - virtual std::array get_color(size_t i, size_t j) const = 0; +[[maybe_unused]] inline png_byte +convert_to_color(png_byte data) { + return data; +} - inline virtual ~PolychromeImage() {} -}; +template +inline +std::vector convert(const std::vector& data) { + static_assert(sizeof(T) == sizeof(D), "must be same size"); + std::vector out(data.size()); + // I give up + memcpy(out.data(), data.data(), data.size() * sizeof(D)); + return out; +} -class PolychromeAlphaImage : public virtual Image { - public: - virtual std::array get_color(size_t i, size_t j) const = 0; +template +struct intermediate { + size_t width; + size_t height; +// size_t data_width; + size_t width_bit_alignment; - inline virtual ~PolychromeAlphaImage() {} + std::vector data; }; -// FLOAT -class FloatMonochromeImage : public virtual MonochromeImage { - public: - virtual png_byte get_color(size_t i, size_t j) const override; - - virtual float get_data(size_t i, size_t j) const; +template +intermediate +inline +make_intermediate(const std::vector>& data, size_t width_bit_alignment) { - FloatMonochromeImage( - std::shared_ptr data, size_t width, size_t height, size_t data_size - ) : Image(data, width, height, data_size) { - assert(data_size == sizeof(float) && "data size must match expected size"); - } + std::vector data_out; - inline virtual size_t - get_width() const { - return width_; + size_t width = 0; + size_t height = data.size(); + + for (const auto& row : data) { + if (row.size() > width) { + width = row.size(); } - - inline virtual size_t - get_height() const { - return height_; } - - inline virtual ~FloatMonochromeImage() {} -}; - -class FloatPolychromeImage : public virtual PolychromeImage { - public: - virtual std::array get_color(size_t i, size_t j) const override; - - virtual std::array get_data(size_t i, size_t j) const; - - FloatPolychromeImage( - std::shared_ptr data, size_t width, size_t height, size_t data_size - ) : Image(data, width, height, data_size) { - assert(data_size == sizeof(float) && "data size must match expected size"); + + data_out.resize(width * height); + for (size_t i = 0; i < height; i++) { + data_out.insert(data_out.end(), data[i].begin(), data[i].end()); + data_out.insert(data_out.end(), width - data[i].size(), T()); } - inline virtual size_t - get_width() const { - return width_; - } + return intermediate(width, height, width_bit_alignment, data_out); +} - inline virtual size_t - get_height() const { - return height_; - } +template +class ImageImplementation { + protected: + size_t width_; + size_t height_; + size_t data_width_; // width with padding + size_t width_bit_alignment_; // 1, 2, 4, 8 - inline virtual ~FloatPolychromeImage() {} -}; -class FloatPolychromeAlphaImage : public virtual PolychromeAlphaImage { - private: - static FloatPolychromeAlphaImage_data_t - pad_color_data(const std::vector>& vector_data); + std::vector data_; - FloatPolychromeAlphaImage(FloatPolychromeAlphaImage_data_t data) : - Image(data.data, data.width, data.height, sizeof(ColorFloat)) {} + // private intermediate + template + inline + ImageImplementation(intermediate inter) : ImageImplementation(inter.width, inter.height, inter.data, inter.width_bit_alignment) {} public: - virtual std::array get_color(size_t i, size_t j) const override; - - virtual std::array get_data(size_t i, size_t j) const; - - FloatPolychromeAlphaImage( - std::shared_ptr data, size_t width, size_t height, size_t data_size - ) : Image(data, width, height, data_size) { - assert(data_size == sizeof(float) && "data size must match expected size"); + template + inline + ImageImplementation(size_t width, size_t height, const std::vector& data, size_t width_bit_alignment = 1) + : width_(width), height_(height), width_bit_alignment_(width_bit_alignment), data_(convert(data)) { + data_width_ = width_; // TODO } + template + inline + ImageImplementation(const std::vector>& data, size_t width_bit_alignment = 1) + : ImageImplementation(make_intermediate(data, width_bit_alignment)) { } - FloatPolychromeAlphaImage(std::vector> data) : - FloatPolychromeAlphaImage(pad_color_data(data)) {} + ImageImplementation(size_t width, size_t height, size_t width_bit_alignment = 1) + : ImageImplementation(width, height, std::vector(), width_bit_alignment) {} inline virtual size_t get_width() const { @@ -200,178 +145,104 @@ class FloatPolychromeAlphaImage : public virtual PolychromeAlphaImage { return height_; } - inline virtual ~FloatPolychromeAlphaImage() {} -}; - -#if __HAVE_FLOAT16 -// HALF FLOAT -class HALFFloatMonochromeImage : public virtual MonochromeImage { - public: - virtual png_byte get_color(size_t i, size_t j) const; -}; - -class HALFFloatPolychromeImage : public virtual PolychromeImage { - public: - virtual std::array get_color(size_t i, size_t j) const; -}; - -class HALFFloatPolychromeAlphaImage : public virtual PolychromeAlphaImage { - public: - virtual std::array get_color(size_t i, size_t j) const; -}; -#endif - -// BYTE // 8 bit color channels 24 or 32 bit image -class ByteMonochromeImage : public virtual MonochromeImage { - public: - virtual png_byte get_color(size_t i, size_t j) const override; - - // virtual png_byte get_data(size_t i, size_t j) const; - - ByteMonochromeImage( - std::shared_ptr data, size_t width, size_t height, size_t data_size - ) : Image(data, width, height, data_size) { - assert( - data_size == sizeof(unsigned char) && "data size must match expected size" - ); - } - - ByteMonochromeImage(void* data, size_t width, size_t height, size_t data_size) : - Image(data, width, height, data_size) { - assert( - data_size == sizeof(unsigned char) && "data size must match expected size" - ); +// template + inline const T* get_raw_data() const { + return data_.data(); } - ByteMonochromeImage(size_t width, size_t height, size_t data_size) : - Image(width, height, data_size) { - assert( - data_size == sizeof(unsigned char) && "data size must match expected size" - ); +// template + inline T* get_raw_data() { + return data_.data(); } - void - draw_at(const ByteMonochromeImage& other, size_t position_x, size_t position_y); - - void - set_color(png_byte color, size_t i, size_t j) { - reinterpret_cast(data_.get())[i * height_ + j] = color; +// template + inline T get_data(size_t i, size_t j) const { + assert(i < width_ && j < height_ && "Position must be within image."); + return data_.at(j * data_width_ + i); } - inline void - transpose() { - auto temp = width_; - width_ = height_; - height_ = temp; + inline auto get_color(size_t i, size_t j) const { + return convert_to_color(get_data(i, j)); } - inline virtual size_t - get_width() const { - return width_; + // TODO + inline void draw_at(ImageImplementation other, size_t x, size_t y) { + return; } - inline virtual size_t - get_height() const { - return height_; + // not sure what this does + inline void transpose() { + return; } - - inline virtual ~ByteMonochromeImage() {} }; -class BytePolychromeImage : public virtual PolychromeImage { - public: - virtual std::array get_color(size_t i, size_t j) const override; - - // virtual std::array get_data(size_t i, size_t j) const; - // if needed make inline get color - BytePolychromeImage( - std::shared_ptr data, size_t width, size_t height, size_t data_size - ) : Image(data, width, height, data_size) { - assert( - data_size == sizeof(unsigned char) && "data size must match expected size" - ); - } - - BytePolychromeImage(void* data, size_t width, size_t height, size_t data_size) : - Image(data, width, height, data_size) { - assert( - data_size == sizeof(unsigned char) && "data size must match expected size" - ); - } +//} - BytePolychromeImage(size_t width, size_t height, size_t data_size) : - Image(width, height, data_size) { - assert( - data_size == sizeof(unsigned char) && "data size must match expected size" - ); - } +struct FloatPolychromeAlphaImage_data_t { + std::shared_ptr data; + screen_size_t width; + screen_size_t height; +}; - inline virtual size_t - get_width() const { - return width_; +// t represents the underlying type of the data structure; +template +std::array +read_data(std::shared_ptr data, size_t offset) { + // assert(sizeof(T) == data_size_) + size_t bit_offset = offset * sizeof(T) * datum_number; + char* data_ptr = &data[bit_offset]; + T* pixel_data = reinterpret_cast(data_ptr); + std::array out; + for (size_t i = 0; i < datum_number; i++) { + // normalize data to size of png_byte + out[i] = pixel_data[i] * (2 >> sizeof(png_byte)); } + return out; +} - inline virtual size_t - get_height() const { - return height_; +template +std::array +read_data_float(std::shared_ptr data, size_t offset) { + size_t bit_offset = offset * sizeof(T) * datum_number; + char* data_ptr = &data[bit_offset]; + T* pixel_data = reinterpret_cast(data_ptr); + std::array out; + for (size_t i = 0; i < datum_number; i++) { + out[i] = pixel_data[i]; } + return out; +} - inline virtual ~BytePolychromeImage() {} -}; - -// TODO -// Everything commented out is a todo -class BytePolychromeAlphaImage : public virtual PolychromeAlphaImage { - private: - // static BytePolychromeAlphaImage_data_t - // pad_color_data(const std::vector>& vector_data); - - // BytePolychromeAlphaImage(BytePolychromeAlphaImage_data_t data) : - // Image(data.data, data.width, data.height, sizeof(ColorByte)) {} - - public: - virtual std::array get_color(size_t i, size_t j) const override; +using MonochromeImage = ImageImplementation; +using PolychromeImage = ImageImplementation>; +using PolychromeAlphaImage = ImageImplementation>; - // virtual std::array get_data(size_t i, size_t j) const; +using FloatMonochromeImage = ImageImplementation; +using FloatPolychromeImage = ImageImplementation>; +using FloatPolychromeAlphaImage = ImageImplementation>; - BytePolychromeAlphaImage( - std::shared_ptr data, size_t width, size_t height, size_t data_size - ) : Image(data, width, height, data_size) { - assert( - data_size == sizeof(unsigned char) && "data size must match expected size" - ); - } +using ImageVariant = std::variant; - BytePolychromeAlphaImage( - void* data, size_t width, size_t height, size_t data_size - ) : Image(data, width, height, data_size) { - assert( - data_size == sizeof(unsigned char) && "data size must match expected size" - ); - } +#if 0 +// HALF FLOAT - BytePolychromeAlphaImage(size_t width, size_t height, size_t data_size) : - Image(width, height, data_size) { - assert( - data_size == sizeof(unsigned char) && "data size must match expected size" - ); - } +using HalfFloatMonochromeImage = ImageImplementation; +using HalfFloatPolychromeImage = ImageImplementation>; +using HalfFloatPolychromeAlphaImage = ImageImplementation>; - // BytePolychromeAlphaImage(std::vector> data) : - // BytePolychromeAlphaImage(pad_color_data(data)) {} +#endif - inline virtual size_t - get_width() const { - return width_; - } +template +struct ImageVisitor : Ts... { using Ts::operator()...;}; - inline virtual size_t - get_height() const { - return height_; - } +ImageVariant +make_image(gui::gpu_data::GPUPixelType type, gui::gpu_data::GPUPixelReadFormat format, size_t width, size_t height, size_t width_bit_alignment = 1); - inline virtual ~BytePolychromeAlphaImage() {} -}; +template +ImageVariant +make_image(size_t width, size_t height, size_t width_bit_alignment = 1) { + return ImageImplementation(width, height, {}, width_bit_alignment); +} } // namespace image diff --git a/src/util/png_image.cpp b/src/util/png_image.cpp index d4b3f389..e3b5d243 100644 --- a/src/util/png_image.cpp +++ b/src/util/png_image.cpp @@ -52,23 +52,47 @@ test_function() { #endif -[[nodiscard]] std::expected, int> +class PNG_read_info { + public: + png_structp png_ptr = nullptr; + png_infop png_info = nullptr; + + PNG_read_info() { + // Create our write struct + // TODO these nullptr should be function pointers + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + if (!png_ptr) {return ;} + // Create our info struct for this png image + png_info = png_create_info_struct(png_ptr); + } + + ~PNG_read_info() { + auto temp_ptr_struct = (png_ptr) ? &png_ptr : nullptr; + auto temp_png_info = (png_info) ? &png_info : nullptr; + png_destroy_read_struct(temp_ptr_struct, temp_png_info, nullptr); + } +}; + +std::expected read_image(std::filesystem::path path) { path = std::filesystem::absolute(path); - LOG_BACKTRACE(logging::file_io_logger, "Reading image from {}.", path.string()); + std::string path_string = path.string(); + LOG_BACKTRACE(logging::file_io_logger, "Reading image from {}.", path_string); // Read the tiles from the path specified, and save - // std::ifstream file(path, std::ios::in | std::ios::binary); if (!std::filesystem::exists(path)) { LOG_ERROR( logging::file_io_logger, - "Could not open {}. Are you in the right directory?", path.string() + "Could not open {}. Are you in the right directory?", path_string ); - throw exc::file_not_found_error(path); + return std::unexpected(1); } - std::FILE* file = fopen(path.c_str(), "rb"); - + std::unique_ptr file ( + fopen(path_string.c_str(), "rb"), [](std::FILE* file){ + fclose(file); + } + ); png_uint_32 width; png_uint_32 height; int bit_depth; @@ -79,40 +103,35 @@ read_image(std::filesystem::path path) { unsigned char signal[8]; - fread(signal, 1, 8, file); - - // file.read(reinterpret_cast(signal), 8); + fread(signal, 1, 8, file.get()); if (!png_check_sig(signal, 8)) { LOG_ERROR(logging::file_io_logger, "Failed due to: Bad Signal"); - return std::unexpected(1); + return std::unexpected(2); } - auto png_ptr = - png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); - if (png_ptr == nullptr) { + auto struct_ptr = std::unique_ptr( + png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr), + [](png_struct* ptr){ + png_destroy_read_struct(&ptr, nullptr, nullptr); + } + ); + PNG_read_info info; + if (!info.png_ptr) { LOG_ERROR(logging::file_io_logger, "Failed due to: Out of Memory"); return std::unexpected(4); } - - auto info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == nullptr) { - png_destroy_read_struct(&png_ptr, nullptr, nullptr); + if (!info.png_info) { LOG_ERROR(logging::file_io_logger, "Failed due to: Out of Memory"); return std::unexpected(4); } - if (setjmp(png_jmpbuf(png_ptr))) { - png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); - return std::unexpected(2); - } - - png_init_io(png_ptr, file); - png_set_sig_bytes(png_ptr, 8); - png_read_info(png_ptr, info_ptr); + png_init_io(info.png_ptr, file.get()); + png_set_sig_bytes(info.png_ptr, 8); + png_read_info(info.png_ptr, info.png_info); png_get_IHDR( - png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_method, + info.png_ptr, info.png_info, &width, &height, &bit_depth, &color_type, &interlace_method, &compression_method, &filter_method ); @@ -120,49 +139,45 @@ read_image(std::filesystem::path path) { LOG_WARNING(logging::file_io_logger, "Color type not RGBA"); } - /* I don't really care about a background color; - if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) { + /* I don't really care about a background color, but if I did + if (!png_get_valid(info.png_ptr, info.png_info, PNG_INFO_bKGD)) { LOG_ERROR(logging::file_io_logger, "Failed due to: Out of Memory"); return std::unexpected(1); }*/ - // png_bytep [height]; std::shared_ptr row_pointers(new png_bytep[height]); - png_uint_32 row_bytes = png_get_rowbytes(png_ptr, info_ptr); - std::shared_ptr data(new char[row_bytes * height]); - // data.reserve(row_bytes * height); + png_uint_32 row_bytes = png_get_rowbytes(info.png_ptr, info.png_info); + std::vector> data (width * height); for (unsigned int i = 0; i < height; i++) { - row_pointers[i] = reinterpret_cast(data.get() + i * row_bytes); + row_pointers[i] = reinterpret_cast(data.data()) + i * row_bytes; } - png_read_image(png_ptr, row_pointers.get()); - - png_read_end(png_ptr, nullptr); + png_read_image(info.png_ptr, row_pointers.get()); - fclose(file); + png_read_end(info.png_ptr, nullptr); // todo do things for bit depth auto image = - std::make_shared(data, width, height, 1); + util::image::PolychromeAlphaImage(width, height, data, 1); #if DEBUG() - for (unsigned int i = 0; i < image->get_width(); i++) { - for (unsigned int j = 0; j < image->get_height(); j++) { + for (unsigned int i = 0; i < image.get_width(); i++) { + for (unsigned int j = 0; j < image.get_height(); j++) { auto raw_image_color0 = row_pointers[i][j * 4]; auto raw_image_color1 = row_pointers[i][j * 4 + 1]; auto raw_image_color2 = row_pointers[i][j * 4 + 2]; auto raw_image_color3 = row_pointers[i][j * 4 + 3]; auto data_color0 = - reinterpret_cast(data.get())[i * row_bytes + j * 4]; + reinterpret_cast(data.data())[i * row_bytes + j * 4]; auto data_color1 = - reinterpret_cast(data.get())[i * row_bytes + j * 4 + 1]; + reinterpret_cast(data.data())[i * row_bytes + j * 4 + 1]; auto data_color2 = - reinterpret_cast(data.get())[i * row_bytes + j * 4 + 2]; + reinterpret_cast(data.data())[i * row_bytes + j * 4 + 2]; auto data_color3 = - reinterpret_cast(data.get())[i * row_bytes + j * 4 + 3]; + reinterpret_cast(data.data())[i * row_bytes + j * 4 + 3]; if (raw_image_color0 != data_color0 || raw_image_color1 != data_color1 || raw_image_color2 != data_color2 || raw_image_color3 != data_color3) { LOG_WARNING(logging::file_io_logger, "Pixel incorrect at {}{}", i, j); @@ -176,7 +191,7 @@ read_image(std::filesystem::path path) { ); } - auto color = image->get_color(i, j); + auto color = image.get_color(i, j); if (raw_image_color0 != color[0] || raw_image_color1 != color[1] || raw_image_color2 != color[2] || raw_image_color3 != color[3]) { diff --git a/src/util/png_image.hpp b/src/util/png_image.hpp index 4c824bee..065aca79 100644 --- a/src/util/png_image.hpp +++ b/src/util/png_image.hpp @@ -23,6 +23,7 @@ #pragma once #include "files.hpp" +#include "util/image.hpp" #include @@ -94,6 +95,28 @@ class ImageTest { } }; +class PNG_write_info { + public: + png_structp png_ptr = nullptr; + png_infop png_info = nullptr; + + PNG_write_info() { + // Create our write struct + // TODO these nullptr should be function pointers + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + if (!png_ptr) {return ;} + // Create our info struct for this png image + + png_info = png_create_info_struct(png_ptr); + } + + ~PNG_write_info() { + auto temp_ptr_struct = (png_ptr) ? &png_ptr : nullptr; + auto temp_png_info = (png_info) ? &png_info : nullptr; + png_destroy_write_struct(temp_ptr_struct, temp_png_info); + } +}; + namespace { template @@ -122,42 +145,34 @@ write_image_base(T image, const std::filesystem::path& path /*other settings*/) char meta_key[] = "An Image"; char meta_text[] = "Some text"; - // Create png variables - png_structp png_ptr = nullptr; - png_infop info_ptr = nullptr; // Open the file for writing - auto path_str = path.string(); // need to keep this from being free'd - std::FILE* file = fopen(path_str.c_str(), "wb"); + std::unique_ptr file ( + fopen(path.c_str(), "wb"), [](std::FILE* file){ + fclose(file); + } + ); if (!file) { status = WR_FOPEN_FAILED; - goto fopen_failed; + return status; } - // Create our write struct - // TODO these nullptr should be function pointers - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); - if (!png_ptr) { + // Create write struct and info struct + PNG_write_info info; + + if (!info.png_ptr) { status = WR_CREATE_WRITE_STRUCT_FAILED; - goto png_create_write_struct_failed; + return status; } - // Create our info struct for this png image - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { + if (!info.png_info) { status = WR_CREATE_INFO_STRUCT_FAILED; - goto png_create_info_struct_failed; - } - - // Set jump buffer for callbacks - if (setjmp(png_jmpbuf(png_ptr))) { - status = WR_SETJMP_PNG_JMPBUF_FAILED; - goto setjmp_png_jmpbuf_failed; + return status; } // Set up IO for our file - png_init_io(png_ptr, file); + png_init_io(info.png_ptr, file.get()); int color_type; @@ -173,7 +188,7 @@ write_image_base(T image, const std::filesystem::path& path /*other settings*/) // set information about our image png_set_IHDR( - png_ptr, info_ptr, WIDTH, HEIGHT, 8, color_type, PNG_INTERLACE_NONE, + info.png_ptr, info.png_info, WIDTH, HEIGHT, 8, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); @@ -186,25 +201,15 @@ write_image_base(T image, const std::filesystem::path& path /*other settings*/) meta_data.key = meta_key; meta_data.text = meta_text; - png_set_text(png_ptr, info_ptr, &meta_data, 1); - png_write_info(png_ptr, info_ptr); + png_set_text(info.png_ptr, info.png_info, &meta_data, 1); + png_write_info(info.png_ptr, info.png_info); // multiple colors are written in the same row - // not sure how I want to implement this in a template safe way - // https://stackoverflow.com/questions/48757099/write-an-image-row-by-row-with-libpng-using-c - /* * write rows of image */ size_t i, j; - png_bytep row; - - // allocate data for row - row = new (std::nothrow) png_byte[n * WIDTH]; - if (!row) { - status = WR_ROW_MALLOC_FAILED; - goto row_malloc_failed; - } + std::vector row(n * WIDTH); // write row data for (i = 0; i < HEIGHT; i++) { @@ -217,29 +222,15 @@ write_image_base(T image, const std::filesystem::path& path /*other settings*/) } // write the row - png_write_row(png_ptr, row); + png_write_row(info.png_ptr, row.data()); } /* * Cleanups */ - // Free our row data - delete[] row; - -row_malloc_failed: // Finish our write - png_write_end(png_ptr, info_ptr); - -setjmp_png_jmpbuf_failed: -png_create_info_struct_failed: - // Free our write struct - png_destroy_write_struct(&png_ptr, &info_ptr); - -png_create_write_struct_failed: - // Close our file - fclose(file); + png_write_end(info.png_ptr, info.png_info); -fopen_failed: return status; } @@ -287,7 +278,7 @@ class ColorImageTest { // #endif -[[nodiscard]] std::expected, int> +[[nodiscard]] std::expected read_image(std::filesystem::path path); } // namespace image diff --git a/src/world/world.cpp b/src/world/world.cpp index 4d39ef0a..1de10392 100644 --- a/src/world/world.cpp +++ b/src/world/world.cpp @@ -58,7 +58,7 @@ World::World( ) : biome_(biome_name, seed), terrain_main_( x_tiles, y_tiles, macro_tile_size, height, biome_, - std::move(biome_.get_map(x_tiles)) + biome_.get_map(x_tiles) ), controller_(object_handler) {}