Skip to content

Commit bdebafb

Browse files
committed
Implement a mesh class for rendering geometry
1 parent b3e7e8c commit bdebafb

File tree

11 files changed

+1178
-0
lines changed

11 files changed

+1178
-0
lines changed

src/libprojectM/Renderer/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,19 @@ generate_shader_resources(${CMAKE_CURRENT_BINARY_DIR}/BuiltInTransitionsResource
1717

1818
add_library(Renderer OBJECT
1919
${CMAKE_CURRENT_BINARY_DIR}/BuiltInTransitionsResources.hpp
20+
Color.hpp
2021
CopyTexture.cpp
2122
CopyTexture.hpp
2223
FileScanner.cpp
2324
FileScanner.hpp
2425
Framebuffer.cpp
2526
Framebuffer.hpp
2627
IdleTextures.hpp
28+
Mesh.cpp
29+
Mesh.hpp
2730
MilkdropNoise.cpp
2831
MilkdropNoise.hpp
32+
Point.hpp
2933
PresetTransition.cpp
3034
PresetTransition.hpp
3135
RenderContext.hpp
@@ -45,8 +49,14 @@ add_library(Renderer OBJECT
4549
TextureManager.hpp
4650
TextureSamplerDescriptor.cpp
4751
TextureSamplerDescriptor.hpp
52+
TextureUV.hpp
4853
TransitionShaderManager.cpp
4954
TransitionShaderManager.hpp
55+
VertexBuffer.hpp
56+
VertexIndexArray.cpp
57+
VertexIndexArray.hpp
58+
VertexBufferUsage.hpp
59+
VertexArray.hpp
5060
)
5161

5262
target_include_directories(Renderer

src/libprojectM/Renderer/Color.hpp

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
#pragma once
2+
3+
#include <projectM-opengl.h>
4+
5+
#include <cstdint>
6+
#include <cmath>
7+
8+
namespace libprojectM {
9+
namespace Renderer {
10+
11+
/**
12+
* @brief A color with RGBA channels.
13+
*/
14+
class Color
15+
{
16+
public:
17+
Color() = default;
18+
19+
/**
20+
* Constructs a color with the given values.
21+
* @param r The color's r value.
22+
* @param g The color's g value.
23+
* @param b The color's b value.
24+
* @param a The color's a value.
25+
*/
26+
Color(float r, float g, float b, float a)
27+
: m_r(r)
28+
, m_g(g)
29+
, m_b(b)
30+
, m_a(a) {};
31+
32+
/**
33+
* Returns the color's r value.
34+
* @return The color's r value.
35+
*/
36+
auto R() const -> float
37+
{
38+
return m_r;
39+
}
40+
41+
/**
42+
* Sets the color's r value.
43+
* @param r The new r value.
44+
*/
45+
void SetR(float r)
46+
{
47+
m_r = r;
48+
}
49+
50+
/**
51+
* Returns the color's g value.
52+
* @return The color's g value.
53+
*/
54+
auto G() const -> float
55+
{
56+
return m_g;
57+
}
58+
59+
/**
60+
* Sets the color's g value.
61+
* @param g The new g value.
62+
*/
63+
void SetG(float g)
64+
{
65+
m_g = g;
66+
}
67+
68+
/**
69+
* Returns the color's b value.
70+
* @return The color's b value.
71+
*/
72+
auto B() const -> float
73+
{
74+
return m_b;
75+
}
76+
77+
/**
78+
* Sets the color's b value.
79+
* @param b The new b value.
80+
*/
81+
void SetB(float b)
82+
{
83+
m_b = b;
84+
}
85+
86+
/**
87+
* Returns the color's a value.
88+
* @return The color's a value.
89+
*/
90+
auto A() const -> float
91+
{
92+
return m_a;
93+
}
94+
95+
/**
96+
* Sets the color's a value.
97+
* @param a The new a value.
98+
*/
99+
void SetA(float a)
100+
{
101+
m_a = a;
102+
}
103+
104+
/**
105+
* @brief Computes the modulus to wrap float values into the range of [0.0, 1.0].
106+
*
107+
* This code mimics the following equations used by the original Milkdrop code:
108+
*
109+
* v[0].Diffuse =
110+
* ((((int)(*pState->m_shape[i].var_pf_a * 255 * alpha_mult)) & 0xFF) << 24) |
111+
* ((((int)(*pState->m_shape[i].var_pf_r * 255)) & 0xFF) << 16) |
112+
* ((((int)(*pState->m_shape[i].var_pf_g * 255)) & 0xFF) << 8) |
113+
* ((((int)(*pState->m_shape[i].var_pf_b * 255)) & 0xFF) );
114+
*
115+
* In projectM, we use float values when drawing primitives or configuring vertices.
116+
* Converting the above back to a float looks like this:
117+
*
118+
* d = (f * 255.0) & 0xFF = int((f * 255.0) % 256.0); *
119+
* f' = float(d)/255.0;
120+
*
121+
* * Here % represents the Euclidean modulus, not the traditional (signed) fractional
122+
* remainder.
123+
*
124+
* To avoid limiting ourselves to 8 bits, we combine the above equations into one that
125+
* does not discard any information:
126+
*
127+
* f' = ((f * 255.0) % 256.0) / 255.0;
128+
* = f % (256.0/255.0);
129+
*
130+
* Since we're using the Euclidean modulus we need to generate it from the fractional
131+
* remainder using a standard equation.
132+
* @param x The color channel value to clamp.
133+
* @return The color value clamped to the range of [0.0, 1.0].
134+
*/
135+
static auto Modulo(float x) -> float
136+
{
137+
const float m = 256.0f / 255.0f;
138+
return std::fmod(std::fmod(x, m) + m, m);
139+
}
140+
141+
/**
142+
* @brief Computes the modulus to wrap float values into the range of [0.0, 1.0].
143+
* @param x The color channel value to clamp.
144+
* @return The color value clamped to the range of [0.0, 1.0].
145+
*/
146+
static auto Modulo(double x) -> float
147+
{
148+
// Convert the input to float before performing the computation.
149+
return Modulo(static_cast<float>(x));
150+
}
151+
152+
/**
153+
* @brief Computes the modulus to wrap float values into the range of [0.0, 1.0].
154+
* @param col The Color instance to clamp.
155+
* @return The color value clamped to the range of [0.0, 1.0].
156+
*/
157+
static auto Modulo(Color col) -> Color
158+
{
159+
return Color(Modulo(col.R()),
160+
Modulo(col.G()),
161+
Modulo(col.B()),
162+
Modulo(col.A()));
163+
}
164+
165+
static void InitializeAttributePointer(uint32_t attributeIndex)
166+
{
167+
glVertexAttribPointer(attributeIndex, sizeof(Color) / sizeof(float), GL_FLOAT, GL_FALSE, sizeof(Color), nullptr);
168+
}
169+
170+
private:
171+
float m_r{}; //!< The color's r value.
172+
float m_g{}; //!< The color's g value.
173+
float m_b{}; //!< The color's b value.
174+
float m_a{}; //!< The color's a value.
175+
};
176+
177+
} // namespace Renderer
178+
} // namespace libprojectM

src/libprojectM/Renderer/Mesh.cpp

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
#include "Mesh.hpp"
2+
3+
namespace libprojectM {
4+
namespace Renderer {
5+
6+
Mesh::Mesh()
7+
{
8+
Initialize();
9+
}
10+
11+
Mesh::Mesh(VertexBufferUsage usage)
12+
: m_vertices(usage)
13+
, m_colors(usage)
14+
, m_textureUVs(usage)
15+
{
16+
Initialize();
17+
}
18+
19+
Mesh::Mesh(VertexBufferUsage usage, bool useColor, bool useTextureUVs)
20+
: m_vertices(usage)
21+
, m_colors(usage)
22+
, m_textureUVs(usage)
23+
, m_useColorAttributes(useColor)
24+
, m_useUVAttributes(useTextureUVs)
25+
{
26+
Initialize();
27+
}
28+
29+
void Mesh::SetVertexCount(uint32_t vertexCount)
30+
{
31+
m_vertices.Resize(vertexCount);
32+
33+
if (m_useColorAttributes)
34+
{
35+
m_colors.Resize(vertexCount);
36+
}
37+
38+
if (m_useUVAttributes)
39+
{
40+
m_textureUVs.Resize(vertexCount);
41+
}
42+
}
43+
44+
void Mesh::SetUseColor(bool useColor)
45+
{
46+
m_useColorAttributes = useColor;
47+
if (m_useColorAttributes)
48+
{
49+
m_colors.Resize(m_vertices.Size());
50+
}
51+
else
52+
{
53+
m_colors.Resize(0);
54+
}
55+
}
56+
57+
void Mesh::SetUseUV(bool useUV)
58+
{
59+
m_useUVAttributes = useUV;
60+
if (m_useUVAttributes)
61+
{
62+
m_textureUVs.Resize(m_vertices.Size());
63+
}
64+
else
65+
{
66+
m_textureUVs.Resize(0);
67+
}
68+
}
69+
70+
auto Mesh::Indices() -> VertexIndexArray&
71+
{
72+
return m_indices;
73+
}
74+
75+
auto Mesh::Indices() const -> const VertexIndexArray&
76+
{
77+
return m_indices;
78+
}
79+
80+
void Mesh::Bind() const
81+
{
82+
m_vertexArray.Bind();
83+
}
84+
85+
void Mesh::Unbind()
86+
{
87+
VertexArray::Unbind();
88+
VertexBuffer<Point>::Unbind();
89+
VertexIndexArray::Unbind();
90+
}
91+
92+
void Mesh::Update()
93+
{
94+
m_vertexArray.Bind();
95+
m_vertices.Update();
96+
m_colors.Update();
97+
m_textureUVs.Update();
98+
99+
VertexBuffer<class Color>::SetEnableAttributeArray(1, m_useColorAttributes);
100+
VertexBuffer<TextureUV>::SetEnableAttributeArray(2, m_useUVAttributes);
101+
102+
m_indices.Update();
103+
}
104+
105+
void Mesh::Draw()
106+
{
107+
m_vertexArray.Bind();
108+
109+
// Assume each vertex is drawn once, in order.
110+
if (m_indices.Empty())
111+
{
112+
m_indices.Resize(m_vertices.Size());
113+
for (size_t index = 0; index < m_vertices.Size(); index++)
114+
{
115+
m_indices[index] = index;
116+
}
117+
m_indices.Update();
118+
}
119+
120+
GLuint primitiveType{GL_LINES};
121+
switch (m_primitiveType)
122+
{
123+
case PrimitiveType::Points:
124+
primitiveType = GL_POINTS;
125+
break;
126+
case PrimitiveType::Lines:
127+
primitiveType = GL_LINES;
128+
break;
129+
case PrimitiveType::LineLoop:
130+
primitiveType = GL_LINE_LOOP;
131+
break;
132+
case PrimitiveType::LineStrip:
133+
primitiveType = GL_LINE_STRIP;
134+
break;
135+
case PrimitiveType::Triangles:
136+
primitiveType = GL_TRIANGLES;
137+
break;
138+
case PrimitiveType::TriangleStrip:
139+
primitiveType = GL_TRIANGLE_STRIP;
140+
break;
141+
case PrimitiveType::TriangleFan:
142+
primitiveType = GL_TRIANGLE_FAN;
143+
break;
144+
}
145+
146+
glDrawElements(primitiveType, m_indices.Size(), GL_UNSIGNED_INT, nullptr);
147+
148+
VertexArray::Unbind();
149+
}
150+
151+
void Mesh::Initialize()
152+
{
153+
m_vertexArray.Bind();
154+
155+
// Set up the attribute pointers for use in shaders
156+
m_vertices.InitializeAttributePointer(0);
157+
m_colors.InitializeAttributePointer(1);
158+
m_textureUVs.InitializeAttributePointer(2);
159+
160+
VertexBuffer<Point>::SetEnableAttributeArray(0, true);
161+
162+
m_indices.Bind();
163+
164+
VertexArray::Unbind();
165+
VertexBuffer<Point>::Unbind();
166+
}
167+
168+
} // namespace Renderer
169+
} // namespace libprojectM

0 commit comments

Comments
 (0)