Skip to content

Commit

Permalink
Mimic Milkdrop code when handling RGBA values outside [0.0, 1.0]
Browse files Browse the repository at this point in the history
  • Loading branch information
dpw13 authored and kblaschke committed Feb 21, 2024
1 parent db89e54 commit 0c27e81
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 13 deletions.
25 changes: 16 additions & 9 deletions src/libprojectM/MilkdropPreset/CustomShape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "PresetFileParser.hpp"

#include <Renderer/TextureManager.hpp>
#include <Renderer/RenderItem.hpp>

#include <vector>

Expand Down Expand Up @@ -155,15 +156,21 @@ void CustomShape::Draw()
vertexData[0].u = 0.5f;
vertexData[0].v = 0.5f;

vertexData[0].r = static_cast<float>(*m_perFrameContext.r);
vertexData[0].g = static_cast<float>(*m_perFrameContext.g);
vertexData[0].b = static_cast<float>(*m_perFrameContext.b);
vertexData[0].a = static_cast<float>(*m_perFrameContext.a);

vertexData[1].r = static_cast<float>(*m_perFrameContext.r2);
vertexData[1].g = static_cast<float>(*m_perFrameContext.g2);
vertexData[1].b = static_cast<float>(*m_perFrameContext.b2);
vertexData[1].a = static_cast<float>(*m_perFrameContext.a2);
// x = f*255.0 & 0xFF = (f*255.0) % 256
// f' = x/255.0 = f % (256/255)
// 1.0 -> 255 (0xFF)
// 2.0 -> 254 (0xFE)
// -1.0 -> 0x01

vertexData[0].r = Renderer::color_modulo(*m_perFrameContext.r);
vertexData[0].g = Renderer::color_modulo(*m_perFrameContext.g);
vertexData[0].b = Renderer::color_modulo(*m_perFrameContext.b);
vertexData[0].a = Renderer::color_modulo(*m_perFrameContext.a);

vertexData[1].r = Renderer::color_modulo(*m_perFrameContext.r2);
vertexData[1].g = Renderer::color_modulo(*m_perFrameContext.g2);
vertexData[1].b = Renderer::color_modulo(*m_perFrameContext.b2);
vertexData[1].a = Renderer::color_modulo(*m_perFrameContext.a2);

for (int i = 1; i < sides + 1; i++)
{
Expand Down
8 changes: 4 additions & 4 deletions src/libprojectM/MilkdropPreset/CustomWaveform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,10 @@ void CustomWaveform::Draw(const PerFrameContext& presetPerFrameContext)
pointsTransformed[sample].x = static_cast<float>((*m_perPointContext.x * 2.0 - 1.0) * m_presetState.renderContext.invAspectX);
pointsTransformed[sample].y = static_cast<float>((*m_perPointContext.y * -2.0 + 1.0) * m_presetState.renderContext.invAspectY);

pointsTransformed[sample].r = static_cast<float>(*m_perPointContext.r);
pointsTransformed[sample].g = static_cast<float>(*m_perPointContext.g);
pointsTransformed[sample].b = static_cast<float>(*m_perPointContext.b);
pointsTransformed[sample].a = static_cast<float>(*m_perPointContext.a);
pointsTransformed[sample].r = Renderer::color_modulo(*m_perPointContext.r);
pointsTransformed[sample].g = Renderer::color_modulo(*m_perPointContext.g);
pointsTransformed[sample].b = Renderer::color_modulo(*m_perPointContext.b);
pointsTransformed[sample].a = Renderer::color_modulo(*m_perPointContext.a);
}

std::vector<ColoredPoint> pointsSmoothed(sampleCount * 2);
Expand Down
42 changes: 42 additions & 0 deletions src/libprojectM/Renderer/RenderItem.hpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,52 @@
#pragma once

#include <projectM-opengl.h>
#include <cmath>

namespace libprojectM {
namespace Renderer {

/**
* @brief Computes the modulus to wrap float values into the range of [0.0, 1.0].
*
* This code mimics the following equations used by the original Milkdrop code:
*
* v[0].Diffuse =
* ((((int)(*pState->m_shape[i].var_pf_a * 255 * alpha_mult)) & 0xFF) << 24) |
* ((((int)(*pState->m_shape[i].var_pf_r * 255)) & 0xFF) << 16) |
* ((((int)(*pState->m_shape[i].var_pf_g * 255)) & 0xFF) << 8) |
* ((((int)(*pState->m_shape[i].var_pf_b * 255)) & 0xFF) );
*
* In projectM, we use float values when drawing primitives or configuring vertices.
* Converting the above back to a float looks like this:
*
* d = (f * 255.0) & 0xFF = int((f * 255.0) % 256.0); *
* f' = float(d)/255.0;
*
* * Here % represents the Euclidean modulus, not the traditional (signed) fractional
* remainder.
*
* To avoid limiting ourselves to 8 bits, we combine the above equations into one that
* does not discard any information:
*
* f' = ((f * 255.0) % 256.0) / 255.0;
* = f % (256.0/255.0);
*
* Since we're using the Euclidean modulus we need to generate it from the fractional
* remainder using a standard equation.
*/
inline float color_modulo(float x)
{
const float m = 256.0f / 255.0f;
return std::fmod(std::fmod(x, m) + m, m);
}

inline float color_modulo(double x)
{
// Convert the input to float before performing the computation.
return color_modulo(static_cast<float>(x));
}

/**
* @brief Base class for render meshes.
* Also defines a few standard vertex attribute structures for use with the shaders.
Expand Down

0 comments on commit 0c27e81

Please sign in to comment.