Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/api/include/projectM-4/parameters.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,34 @@ PROJECTM_EXPORT void projectm_set_mesh_size(projectm_handle instance, size_t wid
*/
PROJECTM_EXPORT void projectm_get_mesh_size(projectm_handle instance, size_t* width, size_t* height);

/**
* @brief Applies a sub-texel offset for main texture lookups in the warp shader.
*
* Original Milkdrop uses 0.5 here, but it doesn't seem to be required in OpenGL as this value
* introduces a slight warp drift to the top left. As this may be vendor-specific, this value can
* be configured externally to fix any possible drift.
*
* @param instance The projectM instance handle.
* @param offset_X The offset in texels in the horizontal direction. Milkdrop uses 0.5, default in projectM is 0.0.
* @param offset_y The offset in texels in the vertical direction. Milkdrop uses 0.5, default in projectM is 0.0.
* @since 4.2.0
*/
PROJECTM_EXPORT void projectm_set_texel_offset(projectm_handle instance, float offset_X, float offset_y);

/**
* @brief Retrieves the current sub-texel offsets for main texture lookups in the warp shader.
*
* Original Milkdrop uses 0.5 here, but it doesn't seem to be required in OpenGL as this value
* introduces a slight warp drift to the top left. As this may be vendor-specific, this value can
* be configured externally to fix any possible drift.
*
* @param instance The projectM instance handle.
* @param offset_X A valid pointer to a float variable that will receive the currently set horizontal texel offset.
* @param offset_y A valid pointer to a float variable that will receive the currently set vertical texel offset.
* @since 4.2.0
*/
PROJECTM_EXPORT void projectm_get_texel_offset(projectm_handle instance, float* offset_X, float* offset_y);

/**
* @brief Sets the current/average frames per second.
*
Expand Down
1 change: 1 addition & 0 deletions src/libprojectM/MilkdropPreset/Border.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ void Border::Draw(const PerFrameContext& presetPerFrameContext)
auto shader = m_presetState.untexturedShader.lock();
shader->Bind();
shader->SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjection);
shader->SetUniformFloat("vertex_point_size", 1.0f);

m_borderMesh.Bind();

Expand Down
3 changes: 1 addition & 2 deletions src/libprojectM/MilkdropPreset/CustomShape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,7 @@ void CustomShape::Draw()
auto shader = m_presetState.untexturedShader.lock();
shader->Bind();
shader->SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjection);

m_outlineMesh.Bind();
shader->SetUniformFloat("vertex_point_size", 1.0f);

glVertexAttrib4f(1,
static_cast<float>(*m_perFrameContext.border_r),
Expand Down
9 changes: 6 additions & 3 deletions src/libprojectM/MilkdropPreset/CustomWaveform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,17 @@ void CustomWaveform::Draw(const PerFrameContext& presetPerFrameContext)

int const maxSampleCount{m_spectrum ? Audio::SpectrumSamples : Audio::WaveformSamples};

int sampleCount = std::min(maxSampleCount, static_cast<int>(*m_perFrameContext.samples));
sampleCount -= m_sep;

// Initialize and execute per-frame code
LoadPerFrameEvaluationVariables(presetPerFrameContext);
m_perFrameContext.ExecutePerFrameCode();

// Copy Q and T vars to per-point context
InitPerPointEvaluationVariables();

int sampleCount = std::min(maxSampleCount, static_cast<int>(*m_perFrameContext.samples));
sampleCount -= m_sep;
sampleCount = std::min(maxSampleCount, static_cast<int>(*m_perFrameContext.samples));

// If there aren't enough samples to draw a single line or dot, skip drawing the waveform.
if ((m_useDots && sampleCount < 1) || sampleCount < 2)
Expand All @@ -104,7 +106,7 @@ void CustomWaveform::Draw(const PerFrameContext& presetPerFrameContext)
// PCM data smoothing
const int offset1 = m_spectrum ? 0 : (maxSampleCount - sampleCount) / 2 - m_sep / 2;
const int offset2 = m_spectrum ? 0 : (maxSampleCount - sampleCount) / 2 + m_sep / 2;
const int t = m_spectrum ? static_cast<int>(static_cast<float>(maxSampleCount - m_sep) / static_cast<float>(sampleCount)) : 1;
const float t = m_spectrum ? static_cast<float>(maxSampleCount - m_sep) / static_cast<float>(sampleCount) : 1.0f;
const float mix1 = std::pow(m_smoothing * 0.98f, 0.5f);
const float mix2 = 1.0f - mix1;

Expand Down Expand Up @@ -175,6 +177,7 @@ void CustomWaveform::Draw(const PerFrameContext& presetPerFrameContext)
auto shader = m_presetState.untexturedShader.lock();
shader->Bind();
shader->SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjection);
shader->SetUniformFloat("vertex_point_size", m_drawThick ? 2.0f : 1.0f);

auto iterations = (m_drawThick && !m_useDots) ? 4 : 1;

Expand Down
1 change: 1 addition & 0 deletions src/libprojectM/MilkdropPreset/DarkenCenter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ void DarkenCenter::Draw()
auto shader = m_presetState.untexturedShader.lock();
shader->Bind();
shader->SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjection);
shader->SetUniformFloat("vertex_point_size", 1.0f);

m_mesh.Draw();

Expand Down
1 change: 1 addition & 0 deletions src/libprojectM/MilkdropPreset/Filters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ void Filters::Draw()
auto shader = m_presetState.untexturedShader.lock();
shader->Bind();
shader->SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjection);
shader->SetUniformFloat("vertex_point_size", 1.0f);

glVertexAttrib4f(1, 1.0, 1.0, 1.0, 1.0);

Expand Down
15 changes: 13 additions & 2 deletions src/libprojectM/MilkdropPreset/MilkdropShader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -371,11 +371,22 @@ void MilkdropShader::PreprocessPresetShader(std::string& program)
{
if (m_type == ShaderType::WarpShader)
{
program.replace(int(found), 11, "void PS(float4 _vDiffuse : COLOR, float4 _uv : TEXCOORD0, float2 _rad_ang : TEXCOORD1, out float4 _return_value : COLOR0, out float4 _mv_tex_coords : COLOR1)\n");
program.replace(int(found), 11, R"(
void PS(float4 _vDiffuse : COLOR,
float4 _uv : TEXCOORD0,
float2 _rad_ang : TEXCOORD1,
out float4 _return_value : COLOR0,
out float4 _mv_tex_coords : COLOR1)
)");
}
else
{
program.replace(int(found), 11, "void PS(float4 _vDiffuse : COLOR, float2 _uv : TEXCOORD0, float2 _rad_ang : TEXCOORD1, out float4 _return_value : COLOR)\n");
program.replace(int(found), 11, R"(
void PS(float4 _vDiffuse : COLOR,
float2 _uv : TEXCOORD0,
float2 _rad_ang : TEXCOORD1,
out float4 _return_value : COLOR)
)");
}
}
else
Expand Down
4 changes: 2 additions & 2 deletions src/libprojectM/MilkdropPreset/PerPixelMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -308,8 +308,8 @@ void PerPixelMesh::WarpedBlit(const PresetState& presetState,
};

// Texel alignment
glm::vec2 const texelOffsets{0.5f / static_cast<float>(presetState.renderContext.viewportSizeX),
0.5f / static_cast<float>(presetState.renderContext.viewportSizeY)};
glm::vec2 const texelOffsets{presetState.renderContext.texelOffsetX / static_cast<float>(presetState.renderContext.viewportSizeX),
presetState.renderContext.texelOffsetY / static_cast<float>(presetState.renderContext.viewportSizeY)};

// Decay
float decay = std::min(static_cast<float>(*perFrameContext.decay), 1.0f);
Expand Down
3 changes: 2 additions & 1 deletion src/libprojectM/MilkdropPreset/Waveform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ void Waveform::Draw(const PerFrameContext& presetPerFrameContext)

auto shader = m_presetState.untexturedShader.lock();
shader->Bind();
shader->SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjection);
shader->SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjectionFlipped);
shader->SetUniformFloat("vertex_point_size", 1.0f);

// Additive wave drawing (vice overwrite)
if (m_presetState.additiveWaves)
Expand Down
2 changes: 1 addition & 1 deletion src/libprojectM/MilkdropPreset/Waveforms/Line.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ void Line::GenerateVertices(const PresetState& presetState, const PerFrameContex

m_wave1Vertices.resize(m_samples);

ClipWaveformEdges(1.57f + m_mysteryWaveParam);
ClipWaveformEdges(1.57f * m_mysteryWaveParam);

for (int i = 0; i < m_samples; i++)
{
Expand Down
2 changes: 1 addition & 1 deletion src/libprojectM/MilkdropPreset/Waveforms/WaveformMath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ auto WaveformMath::GetVertices(const PresetState& presetState,

m_mysteryWaveParam = static_cast<float>(*presetPerFrameContext.wave_mystery);

if (UsesNormalizedMysteryParam() && (m_mysteryWaveParam < 1.0f || m_mysteryWaveParam > 1.0f))
if (UsesNormalizedMysteryParam() && (m_mysteryWaveParam < -1.0f || m_mysteryWaveParam > 1.0f))
{
m_mysteryWaveParam = m_mysteryWaveParam * 0.5f + 0.5f;
m_mysteryWaveParam -= std::floor(m_mysteryWaveParam);
Expand Down
17 changes: 17 additions & 0 deletions src/libprojectM/ProjectM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,18 @@ void ProjectM::SetMeshSize(uint32_t meshResolutionX, uint32_t meshResolutionY)
m_meshY = std::max(8u, std::min(400u, m_meshY));
}

void ProjectM::TexelOffsets(float& texelOffsetX, float& texelOffsetY) const
{
texelOffsetX = m_texelOffsetX;
texelOffsetY = m_texelOffsetY;
}

void ProjectM::SetTexelOffsets(float texelOffsetX, float texelOffsetY)
{
m_texelOffsetX = texelOffsetX;
m_texelOffsetY = texelOffsetY;
}

auto ProjectM::PCM() -> libprojectM::Audio::PCM&
{
return m_audioStorage;
Expand Down Expand Up @@ -493,8 +505,13 @@ auto ProjectM::GetRenderContext() -> Renderer::RenderContext
ctx.aspectY = (m_windowWidth > m_windowHeight) ? static_cast<float>(m_windowHeight) / static_cast<float>(m_windowWidth) : 1.0f;
ctx.invAspectX = 1.0f / ctx.aspectX;
ctx.invAspectY = 1.0f / ctx.aspectY;

ctx.perPixelMeshX = static_cast<int>(m_meshX);
ctx.perPixelMeshY = static_cast<int>(m_meshY);

ctx.texelOffsetX = m_texelOffsetX;
ctx.texelOffsetY = m_texelOffsetY;

ctx.textureManager = m_textureManager.get();
ctx.shaderCache = m_shaderCache.get();

Expand Down
6 changes: 6 additions & 0 deletions src/libprojectM/ProjectM.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ class PROJECTM_EXPORT ProjectM

void SetMeshSize(uint32_t meshResolutionX, uint32_t meshResolutionY);

void TexelOffsets(float& texelOffsetX, float& texelOffsetY) const;

void SetTexelOffsets(float texelOffsetX, float texelOffsetY);

void Touch(float touchX, float touchY, int pressure, int touchType);

void TouchDrag(float touchX, float touchY, int pressure);
Expand Down Expand Up @@ -265,6 +269,8 @@ class PROJECTM_EXPORT ProjectM
bool m_aspectCorrection{true}; //!< If true, corrects aspect ratio for non-rectangular windows.
float m_easterEgg{1.0}; //!< Random preset duration modifier. See TimeKeeper class.
float m_previousFrameVolume{}; //!< Volume in previous frame, used for hard cuts.
float m_texelOffsetX{0.0}; //!< Horizontal warp shader texel offset
float m_texelOffsetY{0.0}; //!< Vertical warp shader texel offset

std::vector<std::string> m_textureSearchPaths; ///!< List of paths to search for texture files

Expand Down
12 changes: 12 additions & 0 deletions src/libprojectM/ProjectMCWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,18 @@ void projectm_get_mesh_size(projectm_handle instance, size_t* width, size_t* hei
*height = static_cast<size_t>(h);
}

void projectm_set_texel_offsete(projectm_handle instance, float offset_X, float offset_y)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->SetTexelOffsets(offset_X, offset_y);
}

void projectm_get_texel_offsete(projectm_handle instance, float* offset_X, float* offset_y)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->TexelOffsets(*offset_X, *offset_y);
}

void projectm_set_mesh_size(projectm_handle instance, size_t width, size_t height)
{
auto projectMInstance = handle_to_instance(instance);
Expand Down
3 changes: 3 additions & 0 deletions src/libprojectM/Renderer/RenderContext.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ class RenderContext
int perPixelMeshX{64}; //!< Per-pixel/per-vertex mesh X resolution.
int perPixelMeshY{48}; //!< Per-pixel/per-vertex mesh Y resolution.

float texelOffsetX{0.0f}; //!< Horizontal texel offset in the warp shader.
float texelOffsetY{0.0f}; //!< Vertical texel offset in the warp shader.

TextureManager* textureManager{nullptr}; //!< Holds all loaded textures for shader access.
ShaderCache* shaderCache{nullptr}; //!< The shader chace of this projectM instance.
};
Expand Down
50 changes: 24 additions & 26 deletions src/libprojectM/Renderer/TextureSamplerDescriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,71 +20,71 @@ TextureSamplerDescriptor::TextureSamplerDescriptor(const std::shared_ptr<class T

auto TextureSamplerDescriptor::Empty() const -> bool
{
return m_texture.expired() || m_sampler.expired();
return m_texture->Empty();
}

void TextureSamplerDescriptor::Bind(GLint unit, const Shader& shader) const
{
auto texture = m_texture.lock();
auto sampler = m_sampler.lock();

if (texture && sampler)
if (m_texture && m_sampler)
{
texture->Bind(unit, sampler);
m_texture->Bind(unit, m_sampler);

shader.SetUniformInt(std::string("sampler_" + m_samplerName).c_str(), unit);
// Might be setting this more than once if the texture is used with different wrap/filter modes, but this rarely happens.
shader.SetUniformFloat4(std::string("texsize_" + m_sizeName).c_str(), {texture->Width(),
texture->Height(),
1.0f / static_cast<float>(texture->Width()),
1.0f / static_cast<float>(texture->Height())});
shader.SetUniformFloat4(std::string("texsize_" + m_sizeName).c_str(), {m_texture->Width(),
m_texture->Height(),
1.0f / static_cast<float>(m_texture->Width()),
1.0f / static_cast<float>(m_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())});
shader.SetUniformFloat4(std::string("texsize_" + m_sizeName.substr(0, 6)).c_str(), {m_texture->Width(),
m_texture->Height(),
1.0f / static_cast<float>(m_texture->Width()),
1.0f / static_cast<float>(m_texture->Height())});
}
}
}

void TextureSamplerDescriptor::Unbind(GLint unit)
{
auto texture = m_texture.lock();
if (texture)
if (m_texture)
{
texture->Unbind(unit);
m_texture->Unbind(unit);
}
Sampler::Unbind(unit);
}

auto TextureSamplerDescriptor::Texture() const -> std::shared_ptr<class Texture>
{
return m_texture.lock();
return m_texture;
}

void TextureSamplerDescriptor::Texture(std::weak_ptr<class Texture> texture)
void TextureSamplerDescriptor::Texture(const std::shared_ptr<Renderer::Texture>& texture)
{
m_texture = texture;
}

void TextureSamplerDescriptor::Texture(const std::weak_ptr<Renderer::Texture>& texture)
{
m_texture = texture.lock();
}

auto TextureSamplerDescriptor::Sampler() const -> std::shared_ptr<class Sampler>
{
return m_sampler.lock();
return m_sampler;
}

auto TextureSamplerDescriptor::SamplerDeclaration() const -> std::string
{
auto texture = m_texture.lock();
auto sampler = m_sampler.lock();
if (!texture || !sampler)
if (!m_texture || !m_sampler)
{
return {};
}

std::string declaration = "uniform ";
if (texture->Type() == GL_TEXTURE_3D)
if (m_texture->Type() == GL_TEXTURE_3D)
{
declaration.append("sampler3D sampler_");
}
Expand All @@ -109,9 +109,7 @@ auto TextureSamplerDescriptor::SamplerDeclaration() const -> std::string

auto TextureSamplerDescriptor::TexSizeDeclaration() const -> std::string
{
auto texture = m_texture.lock();
auto sampler = m_sampler.lock();
if (!texture || !sampler)
if (!m_texture || !m_sampler)
{
return {};
}
Expand Down
16 changes: 13 additions & 3 deletions src/libprojectM/Renderer/TextureSamplerDescriptor.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#pragma once

#include "Renderer/Sampler.hpp"
#include "Renderer/Shader.hpp"
#include "Renderer/Texture.hpp"

#include <memory>

namespace libprojectM {
namespace Renderer {
Expand Down Expand Up @@ -65,11 +69,17 @@ class TextureSamplerDescriptor
*/
auto Texture() const -> std::shared_ptr<class Texture>;

/**
* @brief Updates the internal texture with a new one.
* @param texture A shared pointer to the new texture.
*/
void Texture(const std::shared_ptr<class Texture>& texture);

/**
* @brief Updates the internal texture with a new one.
* @param texture A weak pointer to the new texture.
*/
void Texture(std::weak_ptr<class Texture> texture);
void Texture(const std::weak_ptr<class Texture>& texture);

/**
* @brief Returns a pointer to the stored sampler.
Expand All @@ -96,8 +106,8 @@ class TextureSamplerDescriptor
void TryUpdate(TextureManager& textureManager);

private:
std::weak_ptr<class Texture> m_texture; //!< A weak reference to the texture.
std::weak_ptr<class Sampler> m_sampler; //!< A weak reference to the sampler.
std::shared_ptr<class Texture> m_texture; //!< A reference to the texture.
std::shared_ptr<class Sampler> m_sampler; //!< A reference to the sampler.
std::string m_samplerName; //!< The name of the texture sampler as referenced in the shader.
std::string m_sizeName; //!< The name of the "texsize_" uniform as referenced in the shader.
bool m_updateFailed{false}; //!< Set to true if the update try failed, e.g. texture could not be loaded.
Expand Down
Loading
Loading