mirror of
https://github.com/projectM-visualizer/projectm.git
synced 2026-02-04 18:55:44 +00:00
Reimplement random texture selection.
Use the same basic logic as Milkdrop. Also automatically declare a shorthand "texsize_randXX" uniform for prefixed random texture names as preset authors expect.
This commit is contained in:
@ -55,6 +55,8 @@ void MilkdropShader::LoadCode(const std::string& presetShaderCode)
|
||||
|
||||
void MilkdropShader::LoadTexturesAndCompile(PresetState& presetState)
|
||||
{
|
||||
std::locale loc;
|
||||
|
||||
// Now request the textures and descriptors from the texture manager.
|
||||
for (const auto& name : m_samplerNames)
|
||||
{
|
||||
@ -95,6 +97,43 @@ void MilkdropShader::LoadTexturesAndCompile(PresetState& presetState)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Random textures need special treatment.
|
||||
if (lowerCaseName.length() >= 6 &&
|
||||
lowerCaseName.substr(0, 4) == "rand"
|
||||
&& std::isdigit(lowerCaseName.at(4), loc)
|
||||
&& std::isdigit(lowerCaseName.at(5), loc)
|
||||
)
|
||||
{
|
||||
// First look up the random texture index in the preset state so the texture matches between warp and composite shaders
|
||||
int randomSlot = -1;
|
||||
try {
|
||||
randomSlot = std::stoi(lowerCaseName.substr(4, 2));
|
||||
}
|
||||
catch (...) // Ignore any conversion errors.
|
||||
{}
|
||||
|
||||
if (randomSlot >= 0 && randomSlot <= 15)
|
||||
{
|
||||
if (presetState.randomTextureDescriptors.find(randomSlot) != presetState.randomTextureDescriptors.end())
|
||||
{
|
||||
// Use existing texture descriptor.
|
||||
m_textureSamplerDescriptors.push_back(presetState.randomTextureDescriptors.at(randomSlot));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Slot empty, request a new random texture.
|
||||
auto desc = presetState.renderContext.textureManager->GetRandomTexture(name);
|
||||
|
||||
// Also store a copy in preset state!
|
||||
presetState.randomTextureDescriptors.insert({randomSlot, desc});
|
||||
|
||||
m_textureSamplerDescriptors.push_back(std::move(desc));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Fall through if slot number is out of range and treat as normal texture.
|
||||
}
|
||||
|
||||
auto desc = presetState.renderContext.textureManager->GetTexture(name);
|
||||
m_textureSamplerDescriptors.push_back(std::move(desc));
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
#include <vector>
|
||||
|
||||
// Missing in macOS SDK. Query will most certainly fail, but then use the default format.
|
||||
@ -218,15 +219,7 @@ TextureSamplerDescriptor TextureManager::TryLoadingTexture(const std::string& na
|
||||
|
||||
ExtractTextureSettings(name, wrapMode, filterMode, unqualifiedName);
|
||||
|
||||
if (!m_filesScanned)
|
||||
{
|
||||
FileScanner fileScanner = FileScanner(m_textureSearchPaths, m_extensions);
|
||||
|
||||
// scan for textures
|
||||
using namespace std::placeholders;
|
||||
fileScanner.scan(std::bind(&TextureManager::AddTextureFile, this, _1, _2));
|
||||
m_filesScanned = true;
|
||||
}
|
||||
ScanTextures();
|
||||
|
||||
std::string lowerCaseFileName(name);
|
||||
std::transform(lowerCaseFileName.begin(), lowerCaseFileName.end(), lowerCaseFileName.begin(), tolower);
|
||||
@ -292,47 +285,64 @@ TextureSamplerDescriptor TextureManager::LoadTexture(const std::string& fileName
|
||||
return {newTexture, sampler, name, unqualifiedName};
|
||||
}
|
||||
|
||||
TextureSamplerDescriptor TextureManager::GetRandomTexture(const std::string& randomName)
|
||||
auto TextureManager::GetRandomTexture(const std::string& randomName) -> TextureSamplerDescriptor
|
||||
{
|
||||
GLint wrapMode;
|
||||
GLint filterMode;
|
||||
std::string unqualifiedName;
|
||||
std::string selectedFilename;
|
||||
|
||||
ExtractTextureSettings(randomName, wrapMode, filterMode, unqualifiedName);
|
||||
std::random_device rndDevice;
|
||||
std::default_random_engine rndEngine(rndDevice());
|
||||
|
||||
std::vector<std::string> user_texture_names;
|
||||
size_t separator = unqualifiedName.find('_');
|
||||
std::string textureNameFilter;
|
||||
ScanTextures();
|
||||
|
||||
if (separator != std::string::npos)
|
||||
std::string lowerCaseName(randomName);
|
||||
std::transform(lowerCaseName.begin(), lowerCaseName.end(), lowerCaseName.begin(), tolower);
|
||||
|
||||
if (m_scannedTextureFiles.empty())
|
||||
{
|
||||
textureNameFilter = unqualifiedName.substr(separator + 1);
|
||||
unqualifiedName = unqualifiedName.substr(0, separator);
|
||||
return {};
|
||||
}
|
||||
|
||||
for (auto& texture : m_textures)
|
||||
std::string prefix;
|
||||
if (lowerCaseName.length() > 7 && lowerCaseName.at(6) == '_')
|
||||
{
|
||||
if (texture.second->IsUserTexture())
|
||||
prefix = lowerCaseName.substr(7);
|
||||
}
|
||||
|
||||
if (prefix.empty())
|
||||
{
|
||||
// Just pick a random index.
|
||||
std::uniform_int_distribution<size_t> distribution(0, m_scannedTextureFiles.size() - 1);
|
||||
selectedFilename = m_scannedTextureFiles.at(distribution(rndEngine)).lowerCaseBaseName;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
std::vector<ScannedFile> filteredFiles;
|
||||
auto prefixLength = prefix.length();
|
||||
std::copy_if(m_scannedTextureFiles.begin(), m_scannedTextureFiles.end(),
|
||||
std::back_inserter(filteredFiles),
|
||||
[&prefix, prefixLength](const ScannedFile& file) {
|
||||
return file.lowerCaseBaseName.substr(0, prefixLength) == prefix;
|
||||
});
|
||||
|
||||
if (!filteredFiles.empty())
|
||||
{
|
||||
if (textureNameFilter.empty() || texture.first.find(textureNameFilter) == 0)
|
||||
{
|
||||
user_texture_names.push_back(texture.first);
|
||||
}
|
||||
std::uniform_int_distribution<size_t> distribution(0, filteredFiles.size() - 1);
|
||||
selectedFilename = filteredFiles.at(distribution(rndEngine)).lowerCaseBaseName;
|
||||
}
|
||||
}
|
||||
|
||||
if (!user_texture_names.empty())
|
||||
// If a prefix was set and no file matched, filename can be empty.
|
||||
if (selectedFilename.empty())
|
||||
{
|
||||
std::string random_name = user_texture_names[rand() % user_texture_names.size()];
|
||||
m_randomTextures.push_back(randomName);
|
||||
|
||||
auto randomTexture = m_textures[random_name];
|
||||
auto sampler = m_samplers.at({wrapMode, filterMode});
|
||||
|
||||
return {randomTexture, sampler, randomName, unqualifiedName};
|
||||
return {};
|
||||
}
|
||||
|
||||
return {};
|
||||
// Use selected filename to load the texture.
|
||||
auto desc = GetTexture(selectedFilename);
|
||||
|
||||
// Create new descriptor with the original "rand00[_prefix]" name.
|
||||
return {desc.Texture(), desc.Sampler(), randomName, randomName};
|
||||
}
|
||||
|
||||
void TextureManager::AddTextureFile(const std::string& fileName, const std::string& baseName)
|
||||
@ -395,3 +405,15 @@ void TextureManager::ExtractTextureSettings(const std::string& qualifiedName, GL
|
||||
wrapMode = GL_REPEAT;
|
||||
}
|
||||
}
|
||||
|
||||
void TextureManager::ScanTextures()
|
||||
{
|
||||
if (!m_filesScanned)
|
||||
{
|
||||
FileScanner fileScanner = FileScanner(m_textureSearchPaths, m_extensions);
|
||||
|
||||
using namespace std::placeholders;
|
||||
fileScanner.scan(std::bind(&TextureManager::AddTextureFile, this, _1, _2));
|
||||
m_filesScanned = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,13 +31,21 @@ public:
|
||||
void SetCurrentPresetPath(const std::string& path);
|
||||
|
||||
/**
|
||||
* @brief Requests a texture and sampler with the given name.
|
||||
* @brief Loads a texture and returns a descriptor with the given name.
|
||||
* Resets the texture age to zero.
|
||||
* @param fullName
|
||||
* @return
|
||||
*/
|
||||
auto GetTexture(const std::string& fullName) -> TextureSamplerDescriptor;
|
||||
|
||||
/**
|
||||
* @brief Returns a random texture descriptor, optionally using a prefix (after the `randXX_` name).
|
||||
* Will use the default texture loading logic by calling GetTexture() if a texture was selected.
|
||||
* @param randomName The filename prefix to filter. If empty, all available textures are matches. Case-insensitive.
|
||||
* @return A texture descriptor with the random texture and a default sampler, or an empty sampler if no texture could be matched.
|
||||
*/
|
||||
auto GetRandomTexture(const std::string& randomName) -> TextureSamplerDescriptor;
|
||||
|
||||
/**
|
||||
* @brief Returns a sampler for the given name.
|
||||
* Does not load any texture, only analyzes the prefix.
|
||||
@ -74,8 +82,6 @@ private:
|
||||
|
||||
auto TryLoadingTexture(const std::string& name) -> TextureSamplerDescriptor;
|
||||
|
||||
auto GetRandomTexture(const std::string& randomName) -> TextureSamplerDescriptor;
|
||||
|
||||
void Preload();
|
||||
|
||||
TextureSamplerDescriptor LoadTexture(const std::string& fileName, const std::string& name);
|
||||
@ -84,6 +90,8 @@ private:
|
||||
|
||||
static void ExtractTextureSettings(const std::string& qualifiedName, GLint& wrapMode, GLint& filterMode, std::string& name);
|
||||
|
||||
void ScanTextures();
|
||||
|
||||
std::vector<std::string> m_textureSearchPaths; //!< Search paths to scan for textures.
|
||||
std::string m_currentPresetDir; //!< Path of the current preset to add to the search list.
|
||||
std::vector<ScannedFile> m_scannedTextureFiles; //!< The cached list with scanned texture files.
|
||||
|
||||
@ -24,6 +24,7 @@ void TextureSamplerDescriptor::Bind(GLint unit, const Shader& shader) const
|
||||
{
|
||||
auto texture = m_texture.lock();
|
||||
auto sampler = m_sampler.lock();
|
||||
|
||||
if (texture && sampler)
|
||||
{
|
||||
texture->Bind(unit, sampler);
|
||||
@ -34,6 +35,14 @@ void TextureSamplerDescriptor::Bind(GLint unit, const Shader& shader) const
|
||||
texture->Height(),
|
||||
1.0f / static_cast<float>(texture->Width()),
|
||||
1.0f / static_cast<float>(texture->Height())});
|
||||
// Bind shorthand random texture size uniform
|
||||
if (m_sizeName.substr(0, 4) == "rand" && m_sizeName.length() > 7 && m_sizeName.at(6) == '_')
|
||||
{
|
||||
shader.SetUniformFloat4(std::string("texsize_" + m_sizeName.substr(0, 6)).c_str(), {texture->Width(),
|
||||
texture->Height(),
|
||||
1.0f / static_cast<float>(texture->Width()),
|
||||
1.0f / static_cast<float>(texture->Height())});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,6 +110,15 @@ auto TextureSamplerDescriptor::TexSizeDeclaration() const -> std::string
|
||||
declaration.append("uniform float4 texsize_");
|
||||
declaration.append(m_sizeName);
|
||||
declaration.append(";\n");
|
||||
|
||||
// Add short texsize uniform for prefixed random textures.
|
||||
// E.g. "texsize_rand00" if a sampler "sampler_rand00_smalltiled" was declared
|
||||
if (m_sizeName.substr(0, 4) == "rand" && m_sizeName.length() > 7 && m_sizeName.at(6) == '_')
|
||||
{
|
||||
declaration.append("uniform float4 texsize_");
|
||||
declaration.append(m_sizeName.substr(0, 6));
|
||||
declaration.append(";\n");
|
||||
}
|
||||
}
|
||||
|
||||
return declaration;
|
||||
|
||||
Reference in New Issue
Block a user