/* * Copyright (C) 2023 Christopher J. Howard * * This file is part of Antkeeper source code. * * Antkeeper source code 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. * * Antkeeper source code 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 Antkeeper source code. If not, see . */ #include #include #include #include #include namespace { enum texture_type: std::uint8_t { texture_type_1d, texture_type_1d_array, texture_type_2d, texture_type_2d_array, texture_type_3d, texture_type_cube, texture_type_cube_array }; [[nodiscard]] std::unique_ptr load_texture(::resource_manager& resource_manager, deserialize_context& ctx, std::uint8_t texture_type) { // Read file format identifier std::uint32_t format_identifier{0}; ctx.read32_le(reinterpret_cast(&format_identifier), 1); // Validate file format identifier (U+1F5BC = framed picture) if (format_identifier != 0xbc969ff0) { throw deserialize_error("Invalid texture file."); } // Read file format version std::uint32_t format_version{0}; ctx.read32_le(reinterpret_cast(&format_version), 1); // Validate file format version if (format_version != 1) { throw deserialize_error("Unsupported texture file version."); } // Read image path std::uint32_t image_path_length{0}; ctx.read32_le(reinterpret_cast(&image_path_length), 1); std::string image_path(image_path_length, '\0'); ctx.read8(reinterpret_cast(image_path.data()), image_path_length); // Load image std::shared_ptr image; switch (texture_type) { case texture_type_1d: case texture_type_1d_array: image = resource_manager.load(image_path); break; case texture_type_2d: case texture_type_2d_array: image = resource_manager.load(image_path); break; case texture_type_3d: image = resource_manager.load(image_path); break; case texture_type_cube: case texture_type_cube_array: image = resource_manager.load(image_path); break; default: throw deserialize_error("Invalid texture type."); } // Read image view parameters gl::format format; std::uint32_t first_mip_level; std::uint32_t mip_level_count; std::uint32_t first_array_layer; std::uint32_t array_layer_count; ctx.read32_le(reinterpret_cast(&format), 1); ctx.read32_le(reinterpret_cast(&first_mip_level), 1); ctx.read32_le(reinterpret_cast(&mip_level_count), 1); ctx.read32_le(reinterpret_cast(&first_array_layer), 1); ctx.read32_le(reinterpret_cast(&array_layer_count), 1); // Handle automatic mip level count (`0`) if (!mip_level_count) { mip_level_count = image->get_mip_levels(); } // Handle automatic array layer count (`0`) if (!array_layer_count) { array_layer_count = image->get_array_layers(); } // Read sampler parameters gl::sampler_filter mag_filter; gl::sampler_filter min_filter; gl::sampler_mipmap_mode mipmap_mode; gl::sampler_address_mode address_mode_u; gl::sampler_address_mode address_mode_v; gl::sampler_address_mode address_mode_w; float mip_lod_bias; float max_anisotropy; std::uint8_t compare_enabled; gl::compare_op compare_op; float min_lod; float max_lod; std::array border_color; ctx.read8(reinterpret_cast(&mag_filter), 1); ctx.read8(reinterpret_cast(&min_filter), 1); ctx.read8(reinterpret_cast(&mipmap_mode), 1); ctx.read8(reinterpret_cast(&address_mode_u), 1); ctx.read8(reinterpret_cast(&address_mode_v), 1); ctx.read8(reinterpret_cast(&address_mode_w), 1); ctx.read32_le(reinterpret_cast(&mip_lod_bias), 1); ctx.read32_le(reinterpret_cast(&max_anisotropy), 1); ctx.read8(reinterpret_cast(&compare_enabled), 1); ctx.read8(reinterpret_cast(&compare_op), 1); ctx.read32_le(reinterpret_cast(&min_lod), 1); ctx.read32_le(reinterpret_cast(&max_lod), 1); ctx.read32_le(reinterpret_cast(border_color.data()), 4); // Construct sampler std::shared_ptr sampler = std::make_shared ( mag_filter, min_filter, mipmap_mode, address_mode_u, address_mode_v, address_mode_w, mip_lod_bias, max_anisotropy, compare_enabled, compare_op, min_lod, max_lod, border_color ); // Construct image view and texture switch (texture_type) { case texture_type_1d: { auto image_view = std::make_shared(image, format, first_mip_level, mip_level_count, first_array_layer); return std::make_unique(std::move(image_view), std::move(sampler)); } case texture_type_1d_array: { auto image_view = std::make_shared(image, format, first_mip_level, mip_level_count, first_array_layer, array_layer_count); return std::make_unique(std::move(image_view), std::move(sampler)); } case texture_type_2d: { auto image_view = std::make_shared(image, format, first_mip_level, mip_level_count, first_array_layer); return std::make_unique(std::move(image_view), std::move(sampler)); } case texture_type_2d_array: { auto image_view = std::make_shared(image, format, first_mip_level, mip_level_count, first_array_layer, array_layer_count); return std::make_unique(std::move(image_view), std::move(sampler)); } case texture_type_3d: { auto image_view = std::make_shared(image, format, first_mip_level, mip_level_count); return std::make_unique(std::move(image_view), std::move(sampler)); } case texture_type_cube: { auto image_view = std::make_shared(image, format, first_mip_level, mip_level_count, first_array_layer); return std::make_unique(std::move(image_view), std::move(sampler)); } case texture_type_cube_array: { auto image_view = std::make_shared(image, format, first_mip_level, mip_level_count, first_array_layer, array_layer_count); return std::make_unique(std::move(image_view), std::move(sampler)); } default: return nullptr; } } } template <> std::unique_ptr resource_loader::load(::resource_manager& resource_manager, deserialize_context& ctx) { return std::unique_ptr(static_cast(load_texture(resource_manager, ctx, texture_type_1d).release())); } template <> std::unique_ptr resource_loader::load(::resource_manager& resource_manager, deserialize_context& ctx) { return std::unique_ptr(static_cast(load_texture(resource_manager, ctx, texture_type_1d_array).release())); } template <> std::unique_ptr resource_loader::load(::resource_manager& resource_manager, deserialize_context& ctx) { return std::unique_ptr(static_cast(load_texture(resource_manager, ctx, texture_type_2d).release())); } template <> std::unique_ptr resource_loader::load(::resource_manager& resource_manager, deserialize_context& ctx) { return std::unique_ptr(static_cast(load_texture(resource_manager, ctx, texture_type_2d_array).release())); } template <> std::unique_ptr resource_loader::load(::resource_manager& resource_manager, deserialize_context& ctx) { return std::unique_ptr(static_cast(load_texture(resource_manager, ctx, texture_type_3d).release())); } template <> std::unique_ptr resource_loader::load(::resource_manager& resource_manager, deserialize_context& ctx) { return std::unique_ptr(static_cast(load_texture(resource_manager, ctx, texture_type_cube).release())); } template <> std::unique_ptr resource_loader::load(::resource_manager& resource_manager, deserialize_context& ctx) { return std::unique_ptr(static_cast(load_texture(resource_manager, ctx, texture_type_cube_array).release())); }