Skip to content

Commit 537cf07

Browse files
committed
Fix: MilkdropShader - ignore sampler keywords in shader comments (#958)
1 parent 3649044 commit 537cf07

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
@@ -346,32 +346,39 @@ void MilkdropShader::PreprocessPresetShader(std::string& program)
346346

347347
// Find "sampler_state" overrides and remove them first, as they're not supported by GLSL.
348348
// The logic isn't totally fool-proof, but should work in general.
349-
found = program.find("sampler_state");
349+
// Use a comment-stripped copy for searching so commented-out sampler_state blocks are skipped.
350+
// StripComments preserves string length, so positions map 1:1 to the original.
351+
std::string stripped = Utils::StripComments(program);
352+
found = stripped.find("sampler_state");
350353
while (found != std::string::npos)
351354
{
352355
// Now go backwards and find the assignment
353-
found = program.rfind('=', found);
356+
found = stripped.rfind('=', found);
354357
auto startPos = found;
355358

356359
// Find closing brace and semicolon
357-
found = program.find('}', found);
358-
found = program.find(';', found);
360+
found = stripped.find('}', found);
361+
found = stripped.find(';', found);
359362

360363
if (found != std::string::npos)
361364
{
362365
program.replace(startPos, found - startPos, "");
366+
// Re-strip after modification since positions have shifted.
367+
stripped = Utils::StripComments(program);
363368
}
364369
else
365370
{
366371
// No closing brace and semicolon.
367372
break;
368373
}
369374

370-
found = program.find("sampler_state");
375+
found = stripped.find("sampler_state");
371376
}
372377

373378
// replace shader_body with entry point function
374-
found = program.find("shader_body");
379+
// Use the stripped copy so a commented-out shader_body is not matched.
380+
stripped = Utils::StripComments(program);
381+
found = stripped.find("shader_body");
375382
if (found != std::string::npos)
376383
{
377384
if (m_type == ShaderType::WarpShader)
@@ -438,7 +445,7 @@ void PS(float4 _vDiffuse : COLOR,
438445
switch (program.at(pos))
439446
{
440447
case '/':
441-
// Skip comments until EoL to prevent false counting
448+
// Skip line comments until EoL to prevent false counting
442449
if (pos < program.length() - 1 && program.at(pos + 1) == '/')
443450
{
444451
for (; pos < program.length(); ++pos)
@@ -449,6 +456,19 @@ void PS(float4 _vDiffuse : COLOR,
449456
}
450457
}
451458
}
459+
// Skip block comments to prevent false counting
460+
else if (pos < program.length() - 1 && program.at(pos + 1) == '*')
461+
{
462+
pos += 2;
463+
for (; pos < program.length() - 1; ++pos)
464+
{
465+
if (program.at(pos) == '*' && program.at(pos + 1) == '/')
466+
{
467+
++pos; // skip past '/'
468+
break;
469+
}
470+
}
471+
}
452472
continue;
453473

454474
case '{':
@@ -500,40 +520,43 @@ void MilkdropShader::GetReferencedSamplers(const std::string& program)
500520
// "main" should always be present.
501521
m_samplerNames.insert("main");
502522

523+
// Strip comments so that commented-out sampler/texsize declarations are not matched.
524+
std::string const stripped = Utils::StripComments(program);
525+
503526
// Search for sampler usage
504-
auto found = program.find("sampler_", 0);
527+
auto found = stripped.find("sampler_", 0);
505528
while (found != std::string::npos)
506529
{
507530
found += 8;
508-
size_t const end = program.find_first_of(" ;,\n\r)", found);
531+
size_t const end = stripped.find_first_of(" ;,\n\r)", found);
509532

510533
if (end != std::string::npos)
511534
{
512-
std::string const sampler = program.substr(static_cast<int>(found), static_cast<int>(end - found));
535+
std::string const sampler = stripped.substr(static_cast<int>(found), static_cast<int>(end - found));
513536
// Skip "sampler_state", as it's a reserved word and not a sampler.
514537
if (sampler != "state")
515538
{
516539
m_samplerNames.insert(sampler);
517540
}
518541
}
519542

520-
found = program.find("sampler_", found);
543+
found = stripped.find("sampler_", found);
521544
}
522545

523546
// Also search for texsize usage, some presets don't reference the sampler.
524-
found = program.find("texsize_", 0);
547+
found = stripped.find("texsize_", 0);
525548
while (found != std::string::npos)
526549
{
527550
found += 8;
528-
size_t const end = program.find_first_of(" ;,.\n\r)", found);
551+
size_t const end = stripped.find_first_of(" ;,.\n\r)", found);
529552

530553
if (end != std::string::npos)
531554
{
532-
std::string const sampler = program.substr(static_cast<int>(found), static_cast<int>(end - found));
555+
std::string const sampler = stripped.substr(static_cast<int>(found), static_cast<int>(end - found));
533556
m_samplerNames.insert(sampler);
534557
}
535558

536-
found = program.find("texsize_", found);
559+
found = stripped.find("texsize_", found);
537560
}
538561

539562
{
@@ -563,15 +586,15 @@ void MilkdropShader::GetReferencedSamplers(const std::string& program)
563586
}
564587
}
565588

566-
if (program.find("GetBlur3") != std::string::npos)
589+
if (stripped.find("GetBlur3") != std::string::npos)
567590
{
568591
UpdateMaxBlurLevel(BlurTexture::BlurLevel::Blur3);
569592
}
570-
else if (program.find("GetBlur2") != std::string::npos)
593+
else if (stripped.find("GetBlur2") != std::string::npos)
571594
{
572595
UpdateMaxBlurLevel(BlurTexture::BlurLevel::Blur2);
573596
}
574-
else if (program.find("GetBlur1") != std::string::npos)
597+
else if (stripped.find("GetBlur1") != std::string::npos)
575598
{
576599
UpdateMaxBlurLevel(BlurTexture::BlurLevel::Blur1);
577600
}

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
@@ -29,6 +29,7 @@ test_api_headers(TestMainAPIHeaders
2929
add_executable(projectM-unittest
3030
HLSLParserTest.cpp
3131
LoggingTest.cpp
32+
MilkdropShaderCommentParsingTest.cpp
3233
PresetFileParserTest.cpp
3334
WaveformAlignerTest.cpp
3435

0 commit comments

Comments
 (0)