Skip to content

Commit f890b8a

Browse files
committed
Fix: MilkdropShader - ignore sampler keywords in shader comments (#958)
1 parent 6b1dc9c commit f890b8a

5 files changed

Lines changed: 1020 additions & 18 deletions

File tree

src/libprojectM/MilkdropPreset/MilkdropShader.cpp

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -341,32 +341,39 @@ void MilkdropShader::PreprocessPresetShader(std::string& program)
341341

342342
// Find "sampler_state" overrides and remove them first, as they're not supported by GLSL.
343343
// The logic isn't totally fool-proof, but should work in general.
344-
found = program.find("sampler_state");
344+
// Use a comment-stripped copy for searching so commented-out sampler_state blocks are skipped.
345+
// StripComments preserves string length, so positions map 1:1 to the original.
346+
std::string stripped = Utils::StripComments(program);
347+
found = stripped.find("sampler_state");
345348
while (found != std::string::npos)
346349
{
347350
// Now go backwards and find the assignment
348-
found = program.rfind('=', found);
351+
found = stripped.rfind('=', found);
349352
auto startPos = found;
350353

351354
// Find closing brace and semicolon
352-
found = program.find('}', found);
353-
found = program.find(';', found);
355+
found = stripped.find('}', found);
356+
found = stripped.find(';', found);
354357

355358
if (found != std::string::npos)
356359
{
357360
program.replace(startPos, found - startPos, "");
361+
// Re-strip after modification since positions have shifted.
362+
stripped = Utils::StripComments(program);
358363
}
359364
else
360365
{
361366
// No closing brace and semicolon.
362367
break;
363368
}
364369

365-
found = program.find("sampler_state");
370+
found = stripped.find("sampler_state");
366371
}
367372

368373
// replace shader_body with entry point function
369-
found = program.find("shader_body");
374+
// Use the stripped copy so a commented-out shader_body is not matched.
375+
stripped = Utils::StripComments(program);
376+
found = stripped.find("shader_body");
370377
if (found != std::string::npos)
371378
{
372379
if (m_type == ShaderType::WarpShader)
@@ -430,7 +437,7 @@ void PS(float4 _vDiffuse : COLOR,
430437
switch (program.at(pos))
431438
{
432439
case '/':
433-
// Skip comments until EoL to prevent false counting
440+
// Skip line comments until EoL to prevent false counting
434441
if (pos < program.length() - 1 && program.at(pos + 1) == '/')
435442
{
436443
for (; pos < program.length(); ++pos)
@@ -441,6 +448,19 @@ void PS(float4 _vDiffuse : COLOR,
441448
}
442449
}
443450
}
451+
// Skip block comments to prevent false counting
452+
else if (pos < program.length() - 1 && program.at(pos + 1) == '*')
453+
{
454+
pos += 2;
455+
for (; pos < program.length() - 1; ++pos)
456+
{
457+
if (program.at(pos) == '*' && program.at(pos + 1) == '/')
458+
{
459+
++pos; // skip past '/'
460+
break;
461+
}
462+
}
463+
}
444464
continue;
445465

446466
case '{':
@@ -492,40 +512,43 @@ void MilkdropShader::GetReferencedSamplers(const std::string& program)
492512
// "main" should always be present.
493513
m_samplerNames.insert("main");
494514

515+
// Strip comments so that commented-out sampler/texsize declarations are not matched.
516+
std::string const stripped = Utils::StripComments(program);
517+
495518
// Search for sampler usage
496-
auto found = program.find("sampler_", 0);
519+
auto found = stripped.find("sampler_", 0);
497520
while (found != std::string::npos)
498521
{
499522
found += 8;
500-
size_t const end = program.find_first_of(" ;,\n\r)", found);
523+
size_t const end = stripped.find_first_of(" ;,\n\r)", found);
501524

502525
if (end != std::string::npos)
503526
{
504-
std::string const sampler = program.substr(static_cast<int>(found), static_cast<int>(end - found));
527+
std::string const sampler = stripped.substr(static_cast<int>(found), static_cast<int>(end - found));
505528
// Skip "sampler_state", as it's a reserved word and not a sampler.
506529
if (sampler != "state")
507530
{
508531
m_samplerNames.insert(sampler);
509532
}
510533
}
511534

512-
found = program.find("sampler_", found);
535+
found = stripped.find("sampler_", found);
513536
}
514537

515538
// Also search for texsize usage, some presets don't reference the sampler.
516-
found = program.find("texsize_", 0);
539+
found = stripped.find("texsize_", 0);
517540
while (found != std::string::npos)
518541
{
519542
found += 8;
520-
size_t const end = program.find_first_of(" ;,.\n\r)", found);
543+
size_t const end = stripped.find_first_of(" ;,.\n\r)", found);
521544

522545
if (end != std::string::npos)
523546
{
524-
std::string const sampler = program.substr(static_cast<int>(found), static_cast<int>(end - found));
547+
std::string const sampler = stripped.substr(static_cast<int>(found), static_cast<int>(end - found));
525548
m_samplerNames.insert(sampler);
526549
}
527550

528-
found = program.find("texsize_", found);
551+
found = stripped.find("texsize_", found);
529552
}
530553

531554
{
@@ -555,15 +578,15 @@ void MilkdropShader::GetReferencedSamplers(const std::string& program)
555578
}
556579
}
557580

558-
if (program.find("GetBlur3") != std::string::npos)
581+
if (stripped.find("GetBlur3") != std::string::npos)
559582
{
560583
UpdateMaxBlurLevel(BlurTexture::BlurLevel::Blur3);
561584
}
562-
else if (program.find("GetBlur2") != std::string::npos)
585+
else if (stripped.find("GetBlur2") != std::string::npos)
563586
{
564587
UpdateMaxBlurLevel(BlurTexture::BlurLevel::Blur2);
565588
}
566-
else if (program.find("GetBlur1") != std::string::npos)
589+
else if (stripped.find("GetBlur1") != std::string::npos)
567590
{
568591
UpdateMaxBlurLevel(BlurTexture::BlurLevel::Blur1);
569592
}

src/libprojectM/Utils.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,53 @@ void ToUpperInPlace(std::string& str)
2929
std::transform(str.begin(), str.end(), str.begin(), ::toupper);
3030
}
3131

32+
auto StripComments(const std::string& source) -> std::string
33+
{
34+
std::string result = source;
35+
size_t i = 0;
36+
37+
while (i < result.size())
38+
{
39+
if (i + 1 < result.size() && result.at(i) == '/' && result.at(i + 1) == '/')
40+
{
41+
// Line comment: replace until end of line
42+
while (i < result.size() && result.at(i) != '\n' && result.at(i) != '\r')
43+
{
44+
result.at(i) = ' ';
45+
i++;
46+
}
47+
}
48+
else if (i + 1 < result.size() && result.at(i) == '/' && result.at(i + 1) == '*')
49+
{
50+
// Block comment: replace until closing */
51+
result.at(i) = ' ';
52+
result.at(i + 1) = ' ';
53+
i += 2;
54+
while (i < result.size())
55+
{
56+
if (i + 1 < result.size() && result.at(i) == '*' && result.at(i + 1) == '/')
57+
{
58+
result.at(i) = ' ';
59+
result.at(i + 1) = ' ';
60+
i += 2;
61+
break;
62+
}
63+
// Preserve newlines to keep line structure intact
64+
if (result.at(i) != '\n' && result.at(i) != '\r')
65+
{
66+
result.at(i) = ' ';
67+
}
68+
i++;
69+
}
70+
}
71+
else
72+
{
73+
i++;
74+
}
75+
}
76+
77+
return result;
78+
}
79+
3280
} // namespace Utils
3381
} // namespace libprojectM

src/libprojectM/Utils.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,16 @@ auto ToUpper(const std::string& str) -> std::string;
1111
void ToLowerInPlace(std::string& str);
1212
void ToUpperInPlace(std::string& str);
1313

14+
/**
15+
* @brief Strips C and C++ style comments from source code.
16+
*
17+
* Replaces // line comments and block comments with spaces, preserving
18+
* string length and newline positions so that character offsets remain valid.
19+
*
20+
* @param source The source code string to strip comments from.
21+
* @return A copy of the source with all comment content replaced by spaces.
22+
*/
23+
auto StripComments(const std::string& source) -> std::string;
24+
1425
} // namespace Utils
1526
} // namespace libprojectM

tests/libprojectM/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ find_package(GTest 1.10 REQUIRED NO_MODULE)
33
add_executable(projectM-unittest
44
WaveformAlignerTest.cpp
55
PresetFileParserTest.cpp
6+
MilkdropShaderCommentParsingTest.cpp
67

78
$<TARGET_OBJECTS:Audio>
89
$<TARGET_OBJECTS:MilkdropPreset>

0 commit comments

Comments
 (0)