File indexing completed on 2024-03-24 15:18:27
0001 /* 0002 SPDX-FileCopyrightText: 2010 Henry de Valence <hdevalence@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "texturemanager.h" 0008 0009 #include "kspaths.h" 0010 #include "auxiliary/kspaths.h" 0011 0012 #include <QDirIterator> 0013 0014 #ifdef KSTARS_LITE 0015 #include <QStandardPaths> 0016 #include <QImage> 0017 #else 0018 #include "skymap.h" 0019 #include "kstars.h" 0020 #endif 0021 0022 #ifdef HAVE_OPENGL 0023 #include <QGLWidget> 0024 #endif 0025 0026 // We returning reference to image. We refer to this image when search 0027 // for image fails 0028 const static QImage emptyImage; 0029 0030 TextureManager *TextureManager::m_p = nullptr; 0031 0032 TextureManager *TextureManager::Create() 0033 { 0034 if (!m_p) 0035 { 0036 m_p = new TextureManager(); 0037 discoverTextureDirs(); 0038 } 0039 return m_p; 0040 } 0041 0042 void TextureManager::Release() 0043 { 0044 delete m_p; 0045 m_p = nullptr; 0046 } 0047 0048 const QImage &TextureManager::getImage(const QString &name) 0049 { 0050 Create(); 0051 if (name.isEmpty()) 0052 return emptyImage; 0053 CacheIter it = findTexture(name); 0054 if (it != m_p->m_textures.constEnd()) 0055 { 0056 return *it; 0057 } 0058 else 0059 { 0060 return emptyImage; 0061 } 0062 } 0063 0064 TextureManager::CacheIter TextureManager::findTexture(const QString &name) 0065 { 0066 Create(); 0067 // Lookup in cache first 0068 CacheIter it = m_p->m_textures.constFind(name); 0069 if (it != m_p->m_textures.constEnd()) 0070 { 0071 return it; 0072 } 0073 0074 for (const auto &dir : m_p->m_texture_directories) 0075 { 0076 const auto &filename = QString("%1/%2.png").arg(dir).arg(name); 0077 QFile file{ filename }; 0078 if (file.exists()) 0079 return (TextureManager::CacheIter)m_p->m_textures.insert( 0080 name, QImage(filename, "PNG")); 0081 } 0082 0083 //Try to load from the file in 'skycultures/western' subdirectory for western constellation art 0084 QString filename = KSPaths::locate(QStandardPaths::AppLocalDataLocation, 0085 QString("skycultures/western/%1.png").arg(name)); 0086 if (!filename.isNull()) 0087 { 0088 return (TextureManager::CacheIter)m_p->m_textures.insert(name, 0089 QImage(filename, "PNG")); 0090 } 0091 0092 //Try to load from the file in 'skycultures/inuit' subdirectory for Inuit constellation art 0093 filename = KSPaths::locate(QStandardPaths::AppLocalDataLocation, 0094 QString("skycultures/inuit/%1.png").arg(name)); 0095 if (!filename.isNull()) 0096 { 0097 return (TextureManager::CacheIter)m_p->m_textures.insert(name, 0098 QImage(filename, "PNG")); 0099 } 0100 0101 // Try to load from file in main data directory 0102 filename = KSPaths::locate(QStandardPaths::AppLocalDataLocation, 0103 QString("textures/%1.png").arg(name)); 0104 0105 if (!filename.isNull()) 0106 { 0107 return (TextureManager::CacheIter)m_p->m_textures.insert(name, 0108 QImage(filename, "PNG")); 0109 } 0110 0111 return (TextureManager::CacheIter)m_p->m_textures.insert(name, QImage()); 0112 } 0113 0114 #ifdef HAVE_OPENGL 0115 static void bindImage(const QImage &img, QGLWidget *cxt) 0116 { 0117 GLuint tid = cxt->bindTexture(img, GL_TEXTURE_2D, GL_RGBA, QGLContext::DefaultBindOption); 0118 glBindTexture(GL_TEXTURE_2D, tid); 0119 } 0120 0121 // FIXME: should we check that image have appropriate size as bindFromImage do? 0122 void TextureManager::bindTexture(const QString &name, QGLWidget *cxt) 0123 { 0124 Create(); 0125 Q_ASSERT("Must be called only with valid GL context" && cxt); 0126 0127 CacheIter it = findTexture(name); 0128 if (it != m_p->m_textures.constEnd()) 0129 bindImage(*it, cxt); 0130 } 0131 0132 void TextureManager::bindFromImage(const QImage &image, QGLWidget *cxt) 0133 { 0134 Create(); 0135 Q_ASSERT("Must be called only with valid GL context" && cxt); 0136 0137 if (image.width() != image.height() || (image.width() & (image.width() - 1))) 0138 { 0139 // Compute texture size 0140 int longest = qMax(image.width(), image.height()); 0141 int tex_size = 2; 0142 while (tex_size < longest) 0143 { 0144 tex_size *= 2; 0145 } 0146 // FIXME: Check if Qt does this for us already. [Note that it does scale to the nearest power of two] 0147 bindImage(image.scaled(tex_size, tex_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), cxt); 0148 } 0149 else 0150 { 0151 bindImage(image, cxt); 0152 } 0153 } 0154 #endif 0155 0156 TextureManager::TextureManager(QObject *parent) : QObject(parent) {} 0157 0158 void TextureManager::discoverTextureDirs() 0159 { 0160 // clear the cache 0161 m_p->m_textures = {}; 0162 0163 const auto &base = KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation); 0164 QDirIterator search(base, QStringList() << "textures_*", QDir::Dirs); 0165 0166 auto &dirs = m_p->m_texture_directories; 0167 while (search.hasNext()) 0168 { 0169 dirs.push_back(search.next()); 0170 } 0171 0172 dirs.push_back(base); 0173 };