// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Utility module" // For conditions of distribution and use, see copyright notice in Config.hpp #include #include #include #include #include #include #include #define STB_IMAGE_IMPLEMENTATION #include #include namespace Nz { namespace { int Eof(void* userdata) { Stream* stream = static_cast(userdata); return stream->GetCursorPos() >= stream->GetSize(); } int Read(void* userdata, char* data, int size) { Stream* stream = static_cast(userdata); return static_cast(stream->Read(data, size)); } void Skip(void* userdata, int size) { Stream* stream = static_cast(userdata); stream->SetCursorPos(static_cast(stream->GetCursorPos()) + static_cast(size)); } static stbi_io_callbacks callbacks = {Read, Skip, Eof}; bool IsSupported(const std::string_view& extension) { static std::unordered_set supportedExtensions = {"bmp", "gif", "hdr", "jpg", "jpeg", "pic", "png", "ppm", "pgm", "psd", "tga"}; return supportedExtensions.find(extension) != supportedExtensions.end(); } Ternary Check(Stream& stream, const ImageParams& parameters) { bool skip; if (parameters.custom.GetBooleanParameter("SkipNativeSTBLoader", &skip) && skip) return Ternary::False; int width, height, bpp; if (stbi_info_from_callbacks(&callbacks, &stream, &width, &height, &bpp)) return Ternary::True; else return Ternary::False; } std::shared_ptr Load(Stream& stream, const ImageParams& parameters) { // Je charge tout en RGBA8 et je converti ensuite via la méthode Convert // Ceci à cause d'un bug de STB lorsqu'il s'agit de charger certaines images (ex: JPG) en "default" int width, height, bpp; UInt8* ptr = stbi_load_from_callbacks(&callbacks, &stream, &width, &height, &bpp, STBI_rgb_alpha); if (!ptr) { NazaraError("Failed to load image: " + std::string(stbi_failure_reason())); return {}; } CallOnExit freeStbiImage([ptr]() { stbi_image_free(ptr); }); std::shared_ptr image = std::make_shared(); if (!image->Create(ImageType::E2D, PixelFormat::RGBA8, width, height, 1, (parameters.levelCount > 0) ? parameters.levelCount : 1)) { NazaraError("Failed to create image"); return {}; } image->Update(ptr); freeStbiImage.CallAndReset(); if (parameters.loadFormat != PixelFormat::Undefined) { if (!image->Convert(parameters.loadFormat)) { NazaraError("Failed to convert image to required format"); return {}; } } return image; } } namespace Loaders { ImageLoader::Entry GetImageLoader_STB() { ImageLoader::Entry loaderEntry; loaderEntry.extensionSupport = IsSupported; loaderEntry.streamChecker = Check; loaderEntry.streamLoader = Load; return loaderEntry; } } }