From 0e8a5c20b5c4d80ad4cbd6d233c7333344035562 Mon Sep 17 00:00:00 2001 From: Kai Blaschke Date: Mon, 15 Jan 2024 01:23:25 +0100 Subject: [PATCH] Move noise texture creation into MilkdropNoise class. No need to create an instance of the class as all generators are static. Use std::vector instead of C-style pointers as pixel buffer. --- src/libprojectM/Renderer/MilkdropNoise.cpp | 146 ++++++++++++++++---- src/libprojectM/Renderer/MilkdropNoise.hpp | 53 +++++-- src/libprojectM/Renderer/TextureManager.cpp | 74 ++-------- 3 files changed, 167 insertions(+), 106 deletions(-) diff --git a/src/libprojectM/Renderer/MilkdropNoise.cpp b/src/libprojectM/Renderer/MilkdropNoise.cpp index 3126192e6..2f312f01c 100644 --- a/src/libprojectM/Renderer/MilkdropNoise.cpp +++ b/src/libprojectM/Renderer/MilkdropNoise.cpp @@ -1,42 +1,131 @@ #include "MilkdropNoise.hpp" +#include "projectM-opengl.h" + #include #include +// Missing in macOS SDK. Query will most certainly fail, but then use the default format. +#ifndef GL_TEXTURE_IMAGE_FORMAT +#define GL_TEXTURE_IMAGE_FORMAT 0x828F +#endif + namespace libprojectM { namespace Renderer { -MilkdropNoise::MilkdropNoise() +auto MilkdropNoise::LowQuality() -> std::shared_ptr +{ + GLuint texture{}; + { + auto textureData = generate2D(256, 1); + + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GetPreferredInternalFormat(), GL_UNSIGNED_BYTE, textureData.data()); + } + return std::make_shared("noise_lq", texture, GL_TEXTURE_2D, 256, 256, false); +} + +auto MilkdropNoise::LowQualityLite() -> std::shared_ptr +{ + GLuint texture{}; + + { + auto textureData = generate2D(32, 1); + + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 32, 32, 0, GetPreferredInternalFormat(), GL_UNSIGNED_BYTE, textureData.data()); + } + + return std::make_shared("noise_lq_lite", texture, GL_TEXTURE_2D, 32, 32, false); +} + +auto MilkdropNoise::MediumQuality() -> std::shared_ptr +{ + GLuint texture{}; + + { + auto textureData = generate2D(256, 4); + + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GetPreferredInternalFormat(), GL_UNSIGNED_BYTE, textureData.data()); + } + return std::make_shared("noise_mq", texture, GL_TEXTURE_2D, 256, 256, false); +} + +auto MilkdropNoise::HighQuality() -> std::shared_ptr +{ + GLuint texture{}; + + { + auto textureData = generate2D(256, 8); + + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GetPreferredInternalFormat(), GL_UNSIGNED_BYTE, textureData.data()); + } + + return std::make_shared("noise_hq", texture, GL_TEXTURE_2D, 256, 256, false); +} + +auto MilkdropNoise::LowQualityVolume() -> std::shared_ptr +{ + GLuint texture{}; + + { + auto textureData = generate3D(32, 1); + + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_3D, texture); + glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 32, 32, 32, 0, GetPreferredInternalFormat(), GL_UNSIGNED_BYTE, textureData.data()); + } + + return std::make_shared("noisevol_lq", texture, GL_TEXTURE_3D, 32, 32, false); +} + +auto MilkdropNoise::HighQualityVolume() -> std::shared_ptr { - generate2D(256, 1, &noise_lq); - generate2D(32, 1, &noise_lq_lite); - generate2D(256, 4, &noise_mq); - generate2D(256, 8, &noise_hq); + GLuint texture{}; + + { + auto textureData = generate3D(32, 4); + + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_3D, texture); + glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 32, 32, 32, 0, GetPreferredInternalFormat(), GL_UNSIGNED_BYTE, textureData.data()); + } - generate3D(32, 1, &noise_lq_vol); - generate3D(32, 4, &noise_hq_vol); + return std::make_shared("noisevol_hq", texture, GL_TEXTURE_3D, 32, 32, false); } -MilkdropNoise::~MilkdropNoise() +auto MilkdropNoise::GetPreferredInternalFormat() -> int { - delete[] noise_lq; - delete[] noise_lq_lite; - delete[] noise_mq; - delete[] noise_hq; - delete[] noise_lq_vol; - delete[] noise_hq_vol; +#if !USE_GLES + // Query preferred internal texture format. GLES 3 only supports GL_RENDERBUFFER here, no texture targets. + // That's why we use GL_BGRA as default, as this is the best general-use format according to Khronos. + GLint preferredInternalFormat{GL_BGRA}; + glGetInternalformativ(GL_TEXTURE_2D, GL_RGBA8, GL_TEXTURE_IMAGE_FORMAT, sizeof(preferredInternalFormat), &preferredInternalFormat); +#else + // GLES only supports GL_RGB and GL_RGBA, so we always use the latter. + GLint preferredInternalFormat{GL_RGBA}; +#endif + + return preferredInternalFormat; } -void MilkdropNoise::generate2D(int size, int zoomFactor, uint32_t** textureData) +auto MilkdropNoise::generate2D(int size, int zoomFactor) -> std::vector { auto randomSeed = std::chrono::system_clock::now().time_since_epoch().count(); std::default_random_engine randomGenerator(randomSeed); std::uniform_int_distribution randomDistribution(0, INT32_MAX); - *textureData = new uint32_t[size * size](); + std::vector textureData; + textureData.resize(size * size); // write to the bits... - auto dst = *textureData; + auto dst = textureData.data(); auto RANGE = (zoomFactor > 1) ? 216 : 256; for (auto y = 0; y < size; y++) { @@ -62,7 +151,7 @@ void MilkdropNoise::generate2D(int size, int zoomFactor, uint32_t** textureData) // smoothing if (zoomFactor > 1) { - dst = *textureData; + dst = textureData.data(); // first go ACROSS, blending cubically on X, but only on the main lines. for (auto y = 0; y < size; y += zoomFactor) @@ -78,7 +167,7 @@ void MilkdropNoise::generate2D(int size, int zoomFactor, uint32_t** textureData) auto y2 = dst[base_y + ((base_x + zoomFactor) % size)]; auto y3 = dst[base_y + ((base_x + zoomFactor * 2) % size)]; - auto t = static_cast(x % zoomFactor) / static_cast( zoomFactor); + auto t = static_cast(x % zoomFactor) / static_cast(zoomFactor); auto result = dwCubicInterpolate(y0, y1, y2, y3, t); @@ -108,23 +197,26 @@ void MilkdropNoise::generate2D(int size, int zoomFactor, uint32_t** textureData) } } } - } + + return textureData; } -void MilkdropNoise::generate3D(int size, int zoomFactor, uint32_t** textureData) +auto MilkdropNoise::generate3D(int size, int zoomFactor) -> std::vector { auto randomSeed = std::chrono::system_clock::now().time_since_epoch().count(); std::default_random_engine randomGenerator(randomSeed); std::uniform_int_distribution randomDistribution(0, INT32_MAX); - *textureData = new uint32_t[size * size * size](); + + std::vector textureData; + textureData.resize(size * size * size); // write to the bits... int RANGE = (zoomFactor > 1) ? 216 : 256; for (auto z = 0; z < size; z++) { - auto dst = (*textureData) + z * size * size; + auto dst = (textureData.data()) + z * size * size; for (auto y = 0; y < size; y++) { for (auto x = 0; x < size; x++) @@ -151,7 +243,7 @@ void MilkdropNoise::generate3D(int size, int zoomFactor, uint32_t** textureData) if (zoomFactor > 1) { // first go ACROSS, blending cubically on X, but only on the main lines. - auto dst = *textureData; + auto dst = textureData.data(); for (auto z = 0; z < size; z += zoomFactor) { for (auto y = 0; y < size; y += zoomFactor) @@ -228,8 +320,9 @@ void MilkdropNoise::generate3D(int size, int zoomFactor, uint32_t** textureData) } } } - } + + return textureData; } float MilkdropNoise::fCubicInterpolate(float y0, float y1, float y2, float y3, float t) @@ -254,8 +347,7 @@ uint32_t MilkdropNoise::dwCubicInterpolate(uint32_t y0, uint32_t y1, uint32_t y2 static_cast((y1 >> shift) & 0xFF) / 255.0f, static_cast((y2 >> shift) & 0xFF) / 255.0f, static_cast((y3 >> shift) & 0xFF) / 255.0f, - t - ); + t); if (f < 0) { f = 0; diff --git a/src/libprojectM/Renderer/MilkdropNoise.hpp b/src/libprojectM/Renderer/MilkdropNoise.hpp index 08fb473a0..b0af87a68 100644 --- a/src/libprojectM/Renderer/MilkdropNoise.hpp +++ b/src/libprojectM/Renderer/MilkdropNoise.hpp @@ -1,6 +1,9 @@ #pragma once +#include + #include +#include #include namespace libprojectM { @@ -24,26 +27,48 @@ namespace Renderer { class MilkdropNoise { public: + MilkdropNoise() = delete; + /** - * Constructor. Generates all noise textures. + * Low-quality (high frequency) 2D noise texture, 256x256 with zoom level 1 + * @return A new noise texture ready for use in rendering. */ - MilkdropNoise(); + static auto LowQuality() -> std::shared_ptr; /** - * Destructor. Deletes the allocated noise textures. + * Low-quality (high frequency) 2D noise texture, 32x32 with zoom level 1 + * @return A new noise texture ready for use in rendering. */ - ~MilkdropNoise(); + static auto LowQualityLite() -> std::shared_ptr; - uint32_t* noise_lq{ nullptr }; //!< Low-quality (high frequency) 2D noise texture, 256x256 with zoom level 1 - uint32_t* noise_lq_lite{ nullptr }; //!< Low-quality (high frequency) 2D noise texture, 32x32 with zoom level 1 - uint32_t* noise_mq{ nullptr }; //!< Medium-quality (medium frequency) 2D noise texture, 256x256 with zoom level 4 - uint32_t* noise_hq{ nullptr }; //!< High-quality (low frequency) 2D noise texture, 256x256 with zoom level 8 + /** + * Medium-quality (medium frequency) 2D noise texture, 256x256 with zoom level 4 + * @return A new noise texture ready for use in rendering. + */ + static auto MediumQuality() -> std::shared_ptr; - uint32_t* noise_lq_vol{ nullptr }; //!< Low-quality (high frequency) 3D noise texture, 32x32 with zoom level 1 - uint32_t* noise_hq_vol{ nullptr }; //!< High-quality (low frequency) 3D noise texture, 32x32 with zoom level 4 + /** + * High-quality (low frequency) 2D noise texture, 256x256 with zoom level 8 + * @return A new noise texture ready for use in rendering. + */ + static auto HighQuality() -> std::shared_ptr; + + /** + * Low-quality (high frequency) 3D noise texture, 32x32 with zoom level 1 + * @return A new noise texture ready for use in rendering. + */ + static auto LowQualityVolume() -> std::shared_ptr; + + /** + * High-quality (low frequency) 3D noise texture, 32x32 with zoom level 4 + * @return A new noise texture ready for use in rendering. + */ + static auto HighQualityVolume() -> std::shared_ptr; protected: + static auto GetPreferredInternalFormat() -> int; + /** * @brief Milkdrop 2D noise algorithm * @@ -51,9 +76,9 @@ class MilkdropNoise * * @param size Texture size in pixels. * @param zoomFactor Zoom factor. Higher values give a more smoothed/interpolated look. - * @param textureData A pointer to the data structure that will receive the texture data. Must have size² elements. + * @return A vector with the texture data. Contains size² elements. */ - static void generate2D(int size, int zoomFactor, uint32_t** textureData); + static auto generate2D(int size, int zoomFactor) -> std::vector; /** * @brief Milkdrop §D noise algorithm @@ -62,9 +87,9 @@ class MilkdropNoise * * @param size Texture size in pixels. * @param zoomFactor Zoom factor. Higher values give a more smoothed/interpolated look. - * @param textureData A pointer to the data structure that will receive the texture data. Must have size³ elements. + * @return A vector with the texture data. Contains size³ elements. */ - static void generate3D(int size, int zoomFactor, uint32_t** textureData); + static auto generate3D(int size, int zoomFactor) -> std::vector; static float fCubicInterpolate(float y0, float y1, float y2, float y3, float t); diff --git a/src/libprojectM/Renderer/TextureManager.cpp b/src/libprojectM/Renderer/TextureManager.cpp index c7851732d..f6fa919ba 100644 --- a/src/libprojectM/Renderer/TextureManager.cpp +++ b/src/libprojectM/Renderer/TextureManager.cpp @@ -14,11 +14,6 @@ #include #include -// Missing in macOS SDK. Query will most certainly fail, but then use the default format. -#ifndef GL_TEXTURE_IMAGE_FORMAT -#define GL_TEXTURE_IMAGE_FORMAT 0x828F -#endif - namespace libprojectM { namespace Renderer { @@ -59,7 +54,6 @@ auto TextureManager::GetSampler(const std::string& fullName) -> std::shared_ptr< return m_samplers.at({wrapMode, filterMode}); } - void TextureManager::Preload() { // Create samplers @@ -78,9 +72,7 @@ void TextureManager::Preload() SOIL_CREATE_NEW_ID, SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MULTIPLY_ALPHA, &width, &height); - - auto newTex = std::make_shared("idlem", tex, GL_TEXTURE_2D, width, height, false); - m_textures["idlem"] = newTex; + m_textures["idlem"] = std::make_shared("idlem", tex, GL_TEXTURE_2D, width, height, false);; tex = SOIL_load_OGL_texture_from_memory( headphones_data, @@ -89,63 +81,15 @@ void TextureManager::Preload() SOIL_CREATE_NEW_ID, SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MULTIPLY_ALPHA, &width, &height); - newTex = std::make_shared("idleheadphones", tex, GL_TEXTURE_2D, width, height, false); - m_textures["idleheadphones"] = newTex; - - auto noise = std::make_unique(); - -#if !USE_GLES - // Query preferred internal texture format. GLES 3 only supports GL_RENDERBUFFER here, no texture targets. - // That's why we use GL_BGRA as default, as this is the best general-use format according to Khronos. - GLint preferredInternalFormat{GL_BGRA}; - glGetInternalformativ(GL_TEXTURE_2D, GL_RGBA8, GL_TEXTURE_IMAGE_FORMAT, sizeof(preferredInternalFormat), &preferredInternalFormat); -#else - // GLES only supports GL_RGB and GL_RGBA, so we always use the latter. - GLint preferredInternalFormat{GL_RGBA}; -#endif + m_textures["idleheadphones"] = std::make_shared("idleheadphones", tex, GL_TEXTURE_2D, width, height, false);; - GLuint noise_texture_lq_lite; - glGenTextures(1, &noise_texture_lq_lite); - glBindTexture(GL_TEXTURE_2D, noise_texture_lq_lite); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 32, 32, 0, preferredInternalFormat, GL_UNSIGNED_BYTE, noise->noise_lq_lite); - auto textureNoise_lq_lite = std::make_shared("noise_lq_lite", noise_texture_lq_lite, GL_TEXTURE_2D, 32, 32, false); - m_textures["noise_lq_lite"] = textureNoise_lq_lite; - - GLuint noise_texture_lq; - glGenTextures(1, &noise_texture_lq); - glBindTexture(GL_TEXTURE_2D, noise_texture_lq); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, preferredInternalFormat, GL_UNSIGNED_BYTE, noise->noise_lq); - auto textureNoise_lq = std::make_shared("noise_lq", noise_texture_lq, GL_TEXTURE_2D, 256, 256, false); - m_textures["noise_lq"] = textureNoise_lq; - - GLuint noise_texture_mq; - glGenTextures(1, &noise_texture_mq); - glBindTexture(GL_TEXTURE_2D, noise_texture_mq); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, preferredInternalFormat, GL_UNSIGNED_BYTE, noise->noise_mq); - auto textureNoise_mq = std::make_shared("noise_mq", noise_texture_mq, GL_TEXTURE_2D, 256, 256, false); - m_textures["noise_mq"] = textureNoise_mq; - - GLuint noise_texture_hq; - glGenTextures(1, &noise_texture_hq); - glBindTexture(GL_TEXTURE_2D, noise_texture_hq); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, preferredInternalFormat, GL_UNSIGNED_BYTE, noise->noise_hq); - auto textureNoise_hq = std::make_shared("noise_hq", noise_texture_hq, GL_TEXTURE_2D, 256, 256, false); - m_textures["noise_hq"] = textureNoise_hq; - - GLuint noise_texture_lq_vol; - glGenTextures(1, &noise_texture_lq_vol); - glBindTexture(GL_TEXTURE_3D, noise_texture_lq_vol); - glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 32, 32, 32, 0, preferredInternalFormat, GL_UNSIGNED_BYTE, noise->noise_lq_vol); - auto textureNoise_lq_vol = std::make_shared("noisevol_lq", noise_texture_lq_vol, GL_TEXTURE_3D, 32, 32, false); - m_textures["noisevol_lq"] = textureNoise_lq_vol; - - GLuint noise_texture_hq_vol; - glGenTextures(1, &noise_texture_hq_vol); - glBindTexture(GL_TEXTURE_3D, noise_texture_hq_vol); - glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 32, 32, 32, 0, preferredInternalFormat, GL_UNSIGNED_BYTE, noise->noise_hq_vol); - - auto textureNoise_hq_vol = std::make_shared("noisevol_hq", noise_texture_hq_vol, GL_TEXTURE_3D, 32, 32, false); - m_textures["noisevol_hq"] = textureNoise_hq_vol; + // Noise textures + m_textures["noise_lq_lite"] = MilkdropNoise::LowQualityLite(); + m_textures["noise_lq"] = MilkdropNoise::LowQuality(); + m_textures["noise_mq"] = MilkdropNoise::MediumQuality(); + m_textures["noise_hq"] = MilkdropNoise::HighQuality(); + m_textures["noisevol_lq"] = MilkdropNoise::LowQualityVolume(); + m_textures["noisevol_hq"] = MilkdropNoise::HighQualityVolume(); } void TextureManager::PurgeTextures()