ProgramPrePreprocessor.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. // Copyright (C) 2014, Panagiotis Christopoulos Charitos.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include "anki/resource/ProgramPrePreprocessor.h"
  6. #include "anki/resource/ResourceManager.h"
  7. #include "anki/util/Exception.h"
  8. #include "anki/util/Functions.h"
  9. #include "anki/util/File.h"
  10. #include "anki/util/Array.h"
  11. #include <iomanip>
  12. #include <cstring>
  13. namespace anki {
  14. //==============================================================================
  15. // Keep the strings in that order so that the start pragmas will match to the
  16. // ShaderType enums
  17. static Array<const char*, 7> commands = {{
  18. "#pragma anki type vert",
  19. "#pragma anki type tesc",
  20. "#pragma anki type tese",
  21. "#pragma anki type geom",
  22. "#pragma anki type frag",
  23. "#pragma anki type comp",
  24. "#pragma anki include"}};
  25. const U32 MAX_DEPTH = 8;
  26. //==============================================================================
  27. void ProgramPrePreprocessor::printSourceLines() const
  28. {
  29. for(U i = 0; i < m_sourceLines.size(); ++i)
  30. {
  31. printf("%4lu %s\n", i + 1, m_sourceLines[i].c_str());
  32. }
  33. }
  34. //==============================================================================
  35. void ProgramPrePreprocessor::parseFile(const char* filename)
  36. {
  37. try
  38. {
  39. auto alloc = m_shaderSource.get_allocator();
  40. // Parse files recursively
  41. parseFileForPragmas(
  42. PPPString(filename, alloc),
  43. 0);
  44. m_shaderSource = m_sourceLines.join("\n");
  45. }
  46. catch(Exception& e)
  47. {
  48. throw ANKI_EXCEPTION("Loading file failed: %s", filename) << e;
  49. }
  50. }
  51. //==============================================================================
  52. void ProgramPrePreprocessor::parseFileForPragmas(
  53. const PPPString& filename, U32 depth)
  54. {
  55. // first check the depth
  56. if(depth > MAX_DEPTH)
  57. {
  58. throw ANKI_EXCEPTION("The include depth is too high. "
  59. "Probably circular includance");
  60. }
  61. // load file in lines
  62. auto alloc = m_shaderSource.get_allocator();
  63. PPPString txt(alloc);
  64. PPPStringList lines(alloc);
  65. File(filename.c_str(), File::OpenFlag::READ).readAllText(txt);
  66. lines = PPPStringList::splitString(txt.c_str(), '\n', alloc);
  67. if(lines.size() < 1)
  68. {
  69. throw ANKI_EXCEPTION("File is empty: %s", filename.c_str());
  70. }
  71. for(const PPPString& line : lines)
  72. {
  73. PPPString::size_type npos = 0;
  74. Bool expectPragmaAnki = false;
  75. Bool gotPragmaAnki = true;
  76. if(line.find("#pragma anki") == 0)
  77. {
  78. expectPragmaAnki = true;
  79. }
  80. if(parseType(line))
  81. {
  82. // Do nothing
  83. }
  84. else if((npos = line.find(commands[6])) == 0)
  85. {
  86. // Include
  87. PPPString filen(
  88. line, std::strlen(commands[6]), PPPString::npos);
  89. trimString(filen, " \"", filen);
  90. filen = m_manager->fixResourceFilename(filen.c_str());
  91. parseFileForPragmas(filen, depth + 1);
  92. }
  93. else
  94. {
  95. gotPragmaAnki = false;
  96. m_sourceLines.push_back(line);
  97. }
  98. // Sanity check
  99. if(expectPragmaAnki && !gotPragmaAnki)
  100. {
  101. throw ANKI_EXCEPTION("Malformed pragma anki: %s", line.c_str());
  102. }
  103. }
  104. // Sanity checks
  105. if(m_type == ShaderType::COUNT)
  106. {
  107. throw ANKI_EXCEPTION("Shader is missing the type");
  108. }
  109. }
  110. //==============================================================================
  111. Bool ProgramPrePreprocessor::parseType(const PPPString& line)
  112. {
  113. U i;
  114. Bool found = false;
  115. for(i = 0; i < static_cast<U>(ShaderType::COUNT); i++)
  116. {
  117. if(line.find(commands[i]) == 0)
  118. {
  119. found = true;
  120. break;
  121. }
  122. }
  123. if(found)
  124. {
  125. if(m_type != ShaderType::COUNT)
  126. {
  127. throw ANKI_EXCEPTION("The shader type is already set. Line %s",
  128. line.c_str());
  129. }
  130. m_type = static_cast<ShaderType>(i);
  131. }
  132. return found;
  133. }
  134. } // end namespace anki