add option for texture resize filter to sprite, add functions for finding loudest mixer channel

This commit is contained in:
ohsqueezy 2023-12-27 19:20:20 -08:00
parent 11c8abcc54
commit 1fff973b46
6 changed files with 105 additions and 31 deletions

View File

@ -2,6 +2,39 @@
using namespace sb::audio;
int sb::audio::loudest_channel()
{
int loudest_volume = 0;
int loudest_channel = 0;
int volume = 0;
int count = Mix_GroupCount(-1);
for (int channel = 0; channel < count; channel++)
{
volume = Mix_Volume(channel, -1);
if (volume > loudest_volume)
{
loudest_volume = volume;
loudest_channel = channel;
}
}
return loudest_channel;
}
float sb::audio::loudest_channel_volume()
{
return normalize_volume(Mix_Volume(loudest_channel(), -1));
}
std::uint8_t sb::audio::convert_volume(float volume)
{
return std::clamp(static_cast<int>(std::round(volume * MIX_MAX_VOLUME)), 0, MIX_MAX_VOLUME);
}
float sb::audio::normalize_volume(std::uint8_t volume)
{
return float(volume) / float(MIX_MAX_VOLUME);
}
Chunk::Chunk(const fs::path& path)
{
load(path);
@ -18,11 +51,6 @@ void Chunk::load(const fs::path& path)
}
}
std::uint8_t Chunk::convert_volume(float volume)
{
return std::clamp(static_cast<int>(std::round(volume * MIX_MAX_VOLUME)), 0, MIX_MAX_VOLUME);
}
float Chunk::volume() const
{
if (Mix_QuerySpec(nullptr, nullptr, nullptr) != 0)

View File

@ -24,9 +24,36 @@ namespace sb::audio
{
/*!
* Load audio from an OGG or WAV file and play it on multiple channels.
* @return channel ID of the SDL mixer channel with the loudest volume setting
*/
int loudest_channel();
/*!
* @return volume of the loudest SDL mixer channel, normalized to between 0.0 and 1.0
*/
float loudest_channel_volume();
/*!
* Convert floating point volume between 0.0 and 1.0 to SDL 8-bit unsigned integer volume between 0 and `MIX_MAX_VOLUME`.
*
* @param volume Volume between 0.0 and 1.0
* @return Same volume represented in the range 0 to `MIX_MAX_VOLUME`
*/
std::uint8_t convert_volume(float volume);
/*!
* Convert volume between 0 and `MIX_MAX_VOLUME` to a float between 0.0 and 1.0.
*
* @param volume Volume between 0 and `MIX_MAX_VOLUME`
* @return Same volume represented as a float between 0.0 and 1.0
*/
float normalize_volume(std::uint8_t volume);
/*!
* Load audio from an OGG or WAV file and play it.
*
* This class interfaces with SDL mixer's API and its `Mix_Chunk` audio data struct.
* Each instance contains an SDL `Mix_Chunk` audio data struct and automatically finds a open channel to play it on when play is requested. The chunk
* can be playing on multiple channels simultaneously.
*
* There are some differences between how `Mix_Chunk` and `Mix_Music` can be used with the API, most notably that multiple chunks can be playing on
* multiple channels simultaneously, but only one music object can be playing at a time. This is most likely because `Mix_Music` objects are streamed
@ -42,13 +69,6 @@ namespace sb::audio
/* -1 means loop forever, any other value is the number of times to loop */
int loops = 0;
/*!
* Convert floating point volume between 0.0 and 1.0 to SDL 8-bit unsigned integer volume between 0 and `MIX_MAX_VOLUME`.
*
* @param volume Volume between 0.0 and 1.0
*/
static std::uint8_t convert_volume(float volume);
public:
/*!

View File

@ -104,14 +104,15 @@ namespace sb
*
* @see sb::Texture::load()
*
* @param paths list of paths to images
* @param scale amount to scale
* @param paths List of paths to images
* @param scale Amount to scale
* @param filter Resize filter to use when rendering textures
*/
Sprite(std::initializer_list<fs::path> paths, glm::vec2 scale = glm::vec2{1.0f}) : Sprite(scale)
Sprite(std::initializer_list<fs::path> paths, glm::vec2 scale = glm::vec2{1.0f}, std::optional<GLint> filter = std::nullopt) : Sprite(scale)
{
for (const fs::path& path : paths)
{
this->texture(path);
this->texture(path, filter);
}
}
@ -120,13 +121,11 @@ namespace sb
*
* @see ::Sprite(std::initializer_list<fs::path>, glm::vec2)
*
* @param path path to an image
* @param scale amount to scale
* @param path Path to an image
* @param scale Amount to scale
* @param filter Resize filter to use when rendering textures
*/
Sprite(const fs::path& path, glm::vec2 scale = glm::vec2{1.0f}) : Sprite({path}, scale)
{
this->texture(path);
}
Sprite(const fs::path& path, glm::vec2 scale = glm::vec2{1.0f}, std::optional<GLint> filter = std::nullopt) : Sprite({path}, scale, filter) {};
/*!
* Add a previously constructed sb::Texture to the sprite's plane object.
@ -144,11 +143,16 @@ namespace sb
* The texture is loaded into GPU memory if the GL context is active. Otherwise, the path is just attached to the texture,
* and it must be loaded with a call to Sprite::load.
*
* @param path path to an image
* @param path Path to an image
* @param filter Resize filter to use when rendering the texture
*/
void texture(const fs::path& path)
void texture(const fs::path& path, std::optional<GLint> filter = std::nullopt)
{
sb::Texture texture;
if (filter.has_value())
{
texture.filter(filter.value());
}
if (SDL_GL_GetCurrentContext() != nullptr)
{
texture.load(path);

View File

@ -8,6 +8,7 @@
#include "Model.hpp"
#include "Color.hpp"
#include "Log.hpp"
#include "Texture.hpp"
namespace sb
{

View File

@ -23,12 +23,17 @@ void Texture::associate(fs::path path)
this->path = path;
}
void Texture::filter(GLint value)
{
_filter = value;
}
void Texture::generate()
{
GLObject::generate(glGenTextures);
}
void Texture::generate(glm::vec2 size, GLenum format, GLint filter)
void Texture::generate(glm::vec2 size, GLenum format, std::optional<GLint> filter_value)
{
/* Only generate a new texture ID and reallocate memory if the current texture ID hasn't been registered by this object as having identically
* sized memory with the same format. */
@ -44,8 +49,12 @@ void Texture::generate(glm::vec2 size, GLenum format, GLint filter)
}
/* Set the resizing algorithm of this texture */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
if (!filter_value.has_value())
{
filter_value = _filter;
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter_value.value());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter_value.value());
/* Set the texture wrap of this texture */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);

View File

@ -44,6 +44,10 @@ namespace sb
std::optional<glm::vec2> _size;
std::optional<GLenum> _format;
/* The filter will be applied using glTexParameter whenever Texture::generate(glm::vec2, GLenum, std::optional<GLint>) is called without a filter
* specified. */
GLint _filter = GL_NEAREST;
public:
/*!
@ -66,6 +70,14 @@ namespace sb
*/
void associate(fs::path path);
/*!
* Set the resize filter of the texture. This must be set before Texture::generate(glm::vec2, GLenum, std::optional<GLint>) is called for it
* to be applied.
*
* @param value Resize filter to use (see `glTexParameter` for options)
*/
void filter(GLint value);
/*!
* Forward the GL texture generate function to the base class
*/
@ -76,9 +88,9 @@ namespace sb
*
* @param size Width and height of the texture in texels
* @param format Sized internal format to be used to store texture data (for example, `GL_RGBA8`, `GL_RGB8`)
* @param filter Resize function to use (see `glTexParameter`)
* @param filter Resize function to use (see `glTexParameter`). Overrides the value of Texture::filter.
*/
void generate(glm::vec2 size, GLenum format = GL_RGBA8, GLint filter = GL_NEAREST);
void generate(glm::vec2 size, GLenum format = GL_RGBA8, std::optional<GLint> filter = std::nullopt);
/*!
* Load a texture from the path that was previously set.