#include #include #include "../load_ktx.hpp" #include "file.hpp" namespace gli{ namespace detail { inline texture::size_type compute_ktx_storage_size(texture const & Texture) { texture::size_type const BlockSize = block_size(Texture.format()); texture::size_type TotalSize = sizeof(detail::FOURCC_KTX10) + sizeof(detail::ktx_header10); for(texture::size_type Level = 0, Levels = Texture.levels(); Level < Levels; ++Level) { TotalSize += sizeof(std::uint32_t); for(texture::size_type Layer = 0, Layers = Texture.layers(); Layer < Layers; ++Layer) for(texture::size_type Face = 0, Faces = Texture.faces(); Face < Faces; ++Face) { texture::size_type const FaceSize = Texture.size(Level); texture::size_type const PaddedSize = std::max(BlockSize, glm::ceilMultiple(FaceSize, static_cast(4))); TotalSize += PaddedSize; } } return TotalSize; } }//namespace detail inline bool save_ktx(texture const& Texture, std::vector& Memory) { if(Texture.empty()) return false; gl GL(gl::PROFILE_KTX); gl::format const& Format = GL.translate(Texture.format(), Texture.swizzles()); target const Target = Texture.target(); detail::formatInfo const& Desc = detail::get_format_info(Texture.format()); Memory.resize(detail::compute_ktx_storage_size(Texture)); std::memcpy(&Memory[0], detail::FOURCC_KTX10, sizeof(detail::FOURCC_KTX10)); std::size_t Offset = sizeof(detail::FOURCC_KTX10); detail::ktx_header10& Header = *reinterpret_cast(&Memory[0] + Offset); Header.Endianness = 0x04030201; Header.GLType = Format.Type; Header.GLTypeSize = Format.Type == gl::TYPE_NONE ? 1 : Desc.BlockSize; Header.GLFormat = Format.External; Header.GLInternalFormat = Format.Internal; Header.GLBaseInternalFormat = Format.External; Header.PixelWidth = static_cast(Texture.extent().x); Header.PixelHeight = !is_target_1d(Target) ? static_cast(Texture.extent().y) : 0; Header.PixelDepth = Target == TARGET_3D ? static_cast(Texture.extent().z) : 0; Header.NumberOfArrayElements = is_target_array(Target) ? static_cast(Texture.layers()) : 0; Header.NumberOfFaces = is_target_cube(Target) ? static_cast(Texture.faces()) : 1; Header.NumberOfMipmapLevels = static_cast(Texture.levels()); Header.BytesOfKeyValueData = 0; Offset += sizeof(detail::ktx_header10); for(texture::size_type Level = 0, Levels = Texture.levels(); Level < Levels; ++Level) { std::uint32_t& ImageSize = *reinterpret_cast(&Memory[0] + Offset); Offset += sizeof(std::uint32_t); for(texture::size_type Layer = 0, Layers = Texture.layers(); Layer < Layers; ++Layer) for(texture::size_type Face = 0, Faces = Texture.faces(); Face < Faces; ++Face) { texture::size_type const FaceSize = Texture.size(Level); std::memcpy(&Memory[0] + Offset, Texture.data(Layer, Face, Level), FaceSize); texture::size_type const PaddedSize = glm::ceilMultiple(FaceSize, static_cast(4)); ImageSize += static_cast(PaddedSize); Offset += PaddedSize; GLI_ASSERT(Offset <= Memory.size()); } ImageSize = glm::ceilMultiple(ImageSize, static_cast(4)); } return true; } inline bool save_ktx(texture const& Texture, char const* Filename) { if(Texture.empty()) return false; FILE* File = detail::open_file(Filename, "wb"); if(!File) return false; std::vector Memory; bool const Result = save_ktx(Texture, Memory); std::fwrite(&Memory[0], 1, Memory.size(), File); std::fclose(File); return Result; } inline bool save_ktx(texture const& Texture, std::string const& Filename) { return save_ktx(Texture, Filename.c_str()); } }//namespace gli