#include "AlbumTexture.h" #include "RenderContext.h" #include "WallpaperEngine/Assets/AssetLoadException.h" #include "WallpaperEngine/Data/Utils/ScopeGuard.h" #include "WallpaperEngine/Media/MediaSource.h" #include "stb_image.h" using namespace WallpaperEngine::Render; int albumtexture_read (void* user, char* data, int size) { auto* stream = static_cast (user); stream->read (data, size); return stream->gcount (); } void albumtexture_skip (void* user, int n) { auto* stream = static_cast (user); stream->seekg (n, std::ios::cur); } int albumtexture_eof (void* user) { return static_cast (user)->eof (); } stbi_io_callbacks album_texture_callbacks = { .read = albumtexture_read, .skip = albumtexture_skip, .eof = albumtexture_eof }; AlbumTexture::AlbumTexture (RenderContext& context) : Helpers::ContextAware (context) { this->m_resolution = glm::vec4 (1.0f, 1.0f, 1.0f, 1.0f); glGenTextures (1, &this->m_textureID); glBindTexture (GL_TEXTURE_2D, this->m_textureID); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, 8.0f); } AlbumTexture::~AlbumTexture () { glDeleteTextures (1, &this->m_textureID); } GLuint AlbumTexture::getTextureID (uint32_t imageIndex) const { return this->m_textureID; } uint32_t AlbumTexture::getTextureWidth (uint32_t imageIndex) const { return this->m_width; } uint32_t AlbumTexture::getTextureHeight (uint32_t imageIndex) const { return this->m_height; } uint32_t AlbumTexture::getRealWidth () const { return this->m_width; } uint32_t AlbumTexture::getRealHeight () const { return this->m_height; } TextureFormat AlbumTexture::getFormat () const { return TextureFormat_ARGB8888; } uint32_t AlbumTexture::getFlags () const { return TextureFlags_NoFlags; } const std::vector& AlbumTexture::getFrames () const { return this->m_frames; } const glm::vec4* AlbumTexture::getResolution () const { return &this->m_resolution; } bool AlbumTexture::isAnimated () const { return false; } uint32_t AlbumTexture::getSpritesheetCols () const { return 1; } uint32_t AlbumTexture::getSpritesheetRows () const { return 1; } uint32_t AlbumTexture::getSpritesheetFrames () const { return 1; } float AlbumTexture::getSpritesheetDuration () const { return 0.0f; } void AlbumTexture::incrementUsageCount () const { } void AlbumTexture::decrementUsageCount () const { } void AlbumTexture::update () const { } void AlbumTexture::copyContents (const TextureProvider& other) const noexcept { // gpu -> cpu -> gpu fallback copy; RGBA8 texture, 4 bytes per pixel size_t bufferSize = other.getTextureWidth (0) * other.getTextureHeight (0) * 4; uint8_t* buffer = new uint8_t[bufferSize]; glBindTexture (GL_TEXTURE_2D, other.getTextureID (0)); glGetnTexImage (GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, bufferSize, buffer); glBindTexture (GL_TEXTURE_2D, this->m_textureID); glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGBA8, other.getTextureWidth (0), other.getTextureHeight (0), 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer ); delete[] buffer; this->m_width = other.getTextureWidth (0); this->m_height = other.getTextureHeight (0); this->m_resolution = *other.getResolution (); } void AlbumTexture::load () const { this->m_width = 0; this->m_height = 0; for (const auto& project : this->getContext ().getApp ().getBackgrounds () | std::views::values) { try { auto contents = project->assetLocator->read ("$mediaThumbnail"); int width, height, channels; auto* dataptr = stbi_load_from_callbacks (&album_texture_callbacks, contents.get (), &width, &height, &channels, 4); if (dataptr == nullptr) { continue; } ScopeGuard guard ([dataptr] { stbi_image_free (dataptr); }); if (width == 0 || height == 0) { continue; } this->m_width = width; this->m_height = height; this->m_resolution = glm::vec4 (this->m_width, this->m_height, this->m_width, this->m_height); glBindTexture (GL_TEXTURE_2D, this->m_textureID); glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, dataptr); return; } catch (AssetLoadException&) { // this is expected if the thumbnail is not available } } } bool AlbumTexture::isReady () const { return this->m_width > 0 && this->m_height > 0; }