MaterialShaderProgramCreator.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. #include "MaterialShaderProgramCreator.h"
  2. #include "Util/Scanner/Scanner.h"
  3. #include "Misc/Parser.h"
  4. #include "MaterialBuildinVariable.h"
  5. #include <boost/assign/list_of.hpp>
  6. #include <boost/foreach.hpp>
  7. #include <boost/property_tree/ptree.hpp>
  8. //==============================================================================
  9. // Statics =
  10. //==============================================================================
  11. boost::unordered_map<GLenum, const char*>
  12. MaterialShaderProgramCreator::glTypeToTxt = boost::assign::map_list_of
  13. (GL_FLOAT, "float")
  14. (GL_FLOAT_VEC2, "vec2")
  15. (GL_FLOAT_VEC3, "vec3")
  16. (GL_FLOAT_VEC4, "vec4")
  17. (GL_SAMPLER_2D, "sampler2D")
  18. (GL_FLOAT_MAT3, "mat3")
  19. (GL_FLOAT_MAT4, "mat4")
  20. (GL_NONE, "void");
  21. ConstCharPtrHashMap<GLenum>::Type MaterialShaderProgramCreator::txtToGlType =
  22. boost::assign::map_list_of
  23. ("float", GL_FLOAT)
  24. ("vec2", GL_FLOAT_VEC2)
  25. ("vec3", GL_FLOAT_VEC3)
  26. ("vec4", GL_FLOAT_VEC4)
  27. ("sampler2D", GL_SAMPLER_2D)
  28. ("mat3", GL_FLOAT_MAT3)
  29. ("mat4", GL_FLOAT_MAT4)
  30. ("void", GL_NONE);
  31. boost::unordered_map<MaterialShaderProgramCreator::ArgQualifier, const char*>
  32. MaterialShaderProgramCreator::argQualifierToTxt = boost::assign::map_list_of
  33. (AQ_IN, "in")
  34. (AQ_OUT, "out")
  35. (AQ_INOUT, "inout");
  36. ConstCharPtrHashMap<MaterialShaderProgramCreator::ArgQualifier>::Type
  37. MaterialShaderProgramCreator::txtToArgQualifier = boost::assign::map_list_of
  38. ("in", AQ_IN)
  39. ("out", AQ_OUT)
  40. ("inout", AQ_INOUT);
  41. ConstCharPtrHashMap<GLenum>::Type
  42. MaterialShaderProgramCreator::varyingNameToGlType =
  43. boost::assign::map_list_of
  44. ("vTexCoords", GL_FLOAT_VEC2)
  45. ("vNormal", GL_FLOAT_VEC3)
  46. ("vTangent", GL_FLOAT_VEC3)
  47. ("vTangentW", GL_FLOAT)
  48. ("vVertPosViewSpace", GL_FLOAT_VEC3);
  49. //==============================================================================
  50. // Constructor =
  51. //==============================================================================
  52. MaterialShaderProgramCreator::MaterialShaderProgramCreator(
  53. const boost::property_tree::ptree& pt)
  54. {
  55. parseShaderProgramTag(pt);
  56. }
  57. //==============================================================================
  58. // Destructor =
  59. //==============================================================================
  60. MaterialShaderProgramCreator::~MaterialShaderProgramCreator()
  61. {}
  62. //==============================================================================
  63. // parseShaderFileForFunctionDefinitions =
  64. //==============================================================================
  65. void MaterialShaderProgramCreator::parseShaderFileForFunctionDefinitions(
  66. const char* filename)
  67. {
  68. Scanner::Scanner scanner(filename, false);
  69. const Scanner::Token* token = &scanner.getCrntToken();
  70. // Forever
  71. while(true)
  72. {
  73. getNextTokenAndSkipNewlines(scanner);
  74. FuncDefinition* funcDef = NULL;
  75. // EOF
  76. if(token->getCode() == Scanner::TC_EOF)
  77. {
  78. break;
  79. }
  80. // #
  81. else if(token->getCode() == Scanner::TC_SHARP)
  82. {
  83. parseUntilNewline(scanner);
  84. continue;
  85. }
  86. // Return type
  87. else if(token->getCode() == Scanner::TC_IDENTIFIER)
  88. {
  89. funcDef = new FuncDefinition;
  90. funcDefs.push_back(funcDef);
  91. try
  92. {
  93. funcDef->returnDataType =
  94. txtToGlType.at(token->getValue().getString());
  95. }
  96. catch(std::exception& e)
  97. {
  98. throw PARSER_EXCEPTION("Unsupported type: " +
  99. token->getValue().getString());
  100. }
  101. funcDef->returnDataTypeTxt = token->getValue().getString();
  102. }
  103. else
  104. {
  105. throw PARSER_EXCEPTION_EXPECTED("identifier");
  106. }
  107. // Function name
  108. getNextTokenAndSkipNewlines(scanner);
  109. if(token->getCode() != Scanner::TC_IDENTIFIER)
  110. {
  111. throw PARSER_EXCEPTION_EXPECTED("identifier");
  112. }
  113. funcDef->name = token->getValue().getString();
  114. funcNameToDef[funcDef->name.c_str()] = funcDef;
  115. // (
  116. getNextTokenAndSkipNewlines(scanner);
  117. if(token->getCode() != Scanner::TC_LPAREN)
  118. {
  119. throw PARSER_EXCEPTION_EXPECTED("(");
  120. }
  121. // Arguments
  122. while(true)
  123. {
  124. ArgDefinition* argDef = new ArgDefinition;
  125. funcDef->argDefinitions.push_back(argDef);
  126. // Argument qualifier
  127. getNextTokenAndSkipNewlines(scanner);
  128. if(token->getCode() != Scanner::TC_IDENTIFIER)
  129. {
  130. throw PARSER_EXCEPTION_EXPECTED("identifier");
  131. }
  132. // For now accept only "in"
  133. if(strcmp(token->getValue().getString(), "in"))
  134. {
  135. throw PARSER_EXCEPTION("Incorrect qualifier: " +
  136. token->getValue().getString());
  137. }
  138. try
  139. {
  140. argDef->argQualifier = txtToArgQualifier.at(
  141. token->getValue().getString());
  142. }
  143. catch(std::exception& e)
  144. {
  145. throw PARSER_EXCEPTION("Unsupported qualifier: " +
  146. token->getValue().getString());
  147. }
  148. argDef->argQualifierTxt = token->getValue().getString();
  149. // Type
  150. getNextTokenAndSkipNewlines(scanner);
  151. if(token->getCode() != Scanner::TC_IDENTIFIER)
  152. {
  153. throw PARSER_EXCEPTION_EXPECTED("identifier");
  154. }
  155. try
  156. {
  157. argDef->dataType = txtToGlType.at(
  158. token->getValue().getString());
  159. }
  160. catch(std::exception& e)
  161. {
  162. throw PARSER_EXCEPTION("Unsupported type: " +
  163. token->getValue().getString());
  164. }
  165. argDef->dataTypeTxt = token->getValue().getString();
  166. // Name
  167. getNextTokenAndSkipNewlines(scanner);
  168. if(token->getCode() != Scanner::TC_IDENTIFIER)
  169. {
  170. throw PARSER_EXCEPTION_EXPECTED("identifier");
  171. }
  172. argDef->name = token->getValue().getString();
  173. // ,
  174. getNextTokenAndSkipNewlines(scanner);
  175. if(token->getCode() == Scanner::TC_COMMA)
  176. {
  177. continue;
  178. }
  179. // )
  180. else if(token->getCode() == Scanner::TC_RPAREN)
  181. {
  182. break;
  183. }
  184. else
  185. {
  186. throw PARSER_EXCEPTION_UNEXPECTED();
  187. }
  188. } // End arguments
  189. // {
  190. getNextTokenAndSkipNewlines(scanner);
  191. if(token->getCode() != Scanner::TC_LBRACKET)
  192. {
  193. throw PARSER_EXCEPTION_EXPECTED("{");
  194. }
  195. // Skip until closing bracket
  196. int bracketsNum = 0;
  197. while(true)
  198. {
  199. getNextTokenAndSkipNewlines(scanner);
  200. if(token->getCode() == Scanner::TC_RBRACKET)
  201. {
  202. if(bracketsNum == 0)
  203. {
  204. break;
  205. }
  206. --bracketsNum;
  207. }
  208. else if(token->getCode() == Scanner::TC_LBRACKET)
  209. {
  210. ++bracketsNum;
  211. }
  212. else if(token->getCode() == Scanner::TC_EOF)
  213. {
  214. throw PARSER_EXCEPTION_UNEXPECTED();
  215. }
  216. else
  217. {
  218. continue;
  219. }
  220. } // End until closing bracket
  221. /*std::stringstream ss;
  222. ss << "Func def: " << funcDef->returnArg << " " << funcDef->name << " ";
  223. BOOST_FOREACH(const ArgDefinition& adef, funcDef->argDefinitions)
  224. {
  225. ss << adef.callType << " " << adef.dataType << " " <<
  226. adef.name << ", ";
  227. }
  228. std::cout << ss.str() << std::endl;*/
  229. } // End for all functions
  230. }
  231. //==============================================================================
  232. // parseUntilNewline =
  233. //==============================================================================
  234. void MaterialShaderProgramCreator::parseUntilNewline(Scanner::Scanner& scanner)
  235. {
  236. const Scanner::Token* token = &scanner.getCrntToken();
  237. Scanner::TokenCode prevTc;
  238. while(true)
  239. {
  240. prevTc = token->getCode();
  241. scanner.getNextToken();
  242. if(token->getCode() == Scanner::TC_EOF)
  243. {
  244. break;
  245. }
  246. else if(token->getCode() == Scanner::TC_NEWLINE &&
  247. prevTc != Scanner::TC_BACK_SLASH)
  248. {
  249. break;
  250. }
  251. }
  252. }
  253. //==============================================================================
  254. // getNextTokenAndSkipNewlines =
  255. //==============================================================================
  256. void MaterialShaderProgramCreator::getNextTokenAndSkipNewlines(
  257. Scanner::Scanner& scanner)
  258. {
  259. const Scanner::Token* token;
  260. while(true)
  261. {
  262. token = &scanner.getNextToken();
  263. if(token->getCode() != Scanner::TC_NEWLINE)
  264. {
  265. break;
  266. }
  267. }
  268. }
  269. //==============================================================================
  270. // parseShaderProgramTag =
  271. //==============================================================================
  272. void MaterialShaderProgramCreator::parseShaderProgramTag(
  273. const boost::property_tree::ptree& pt)
  274. {
  275. usingTexCoordsAttrib = usingNormalAttrib = usingTangentAttrib = false;
  276. using namespace boost::property_tree;
  277. srcLines.push_back(
  278. "#pragma anki start vertexShader\n"
  279. "#pragma anki include \"shaders/MaterialVertex.glsl\"\n"
  280. "#pragma anki start fragmentShader\n"
  281. "#pragma anki include \"shaders/MaterialFragmentVariables.glsl\"");
  282. //
  283. // <includes></includes>
  284. //
  285. boost::ptr_vector<FuncDefinition> funcDefs;
  286. Vec<std::string> includeLines;
  287. const ptree& includesPt = pt.get_child("includes");
  288. BOOST_FOREACH(const ptree::value_type& v, includesPt)
  289. {
  290. if(v.first != "include")
  291. {
  292. throw EXCEPTION("Expected include and not: " + v.first);
  293. }
  294. const std::string& fname = v.second.data();
  295. parseShaderFileForFunctionDefinitions(fname.c_str());
  296. includeLines.push_back("#pragma anki include \"" + fname + "\"");
  297. }
  298. std::sort(includeLines.begin(), includeLines.end(), compareStrings);
  299. srcLines.insert(srcLines.end(), includeLines.begin(), includeLines.end());
  300. //
  301. // <ins></ins>
  302. //
  303. Vec<std::string> uniformsLines; // Store the source of the uniform vars
  304. boost::optional<const ptree&> insPt = pt.get_child_optional("inputs");
  305. if(insPt)
  306. {
  307. BOOST_FOREACH(const ptree::value_type& v, insPt.get())
  308. {
  309. if(v.first != "input")
  310. {
  311. throw EXCEPTION("Expected in and not: " + v.first);
  312. }
  313. const ptree& inPt = v.second;
  314. std::string line;
  315. parseInputTag(inPt, line);
  316. uniformsLines.push_back(line);
  317. } // end for all ins
  318. srcLines.push_back("");
  319. std::sort(uniformsLines.begin(), uniformsLines.end(), compareStrings);
  320. srcLines.insert(srcLines.end(), uniformsLines.begin(),
  321. uniformsLines.end());
  322. }
  323. //
  324. // <operators></operators>
  325. //
  326. srcLines.push_back("\nvoid main()\n{");
  327. const ptree& opsPt = pt.get_child("operators");
  328. BOOST_FOREACH(const ptree::value_type& v, opsPt)
  329. {
  330. if(v.first != "operator")
  331. {
  332. throw EXCEPTION("Expected operator and not: " + v.first);
  333. }
  334. const ptree& opPt = v.second;
  335. parseOperatorTag(opPt);
  336. } // end for all operators
  337. srcLines.push_back("}\n");
  338. //
  339. // Create the output
  340. //
  341. if(usingTexCoordsAttrib)
  342. {
  343. srcLines.insert(srcLines.begin(), "#define USING_TEX_COORDS_ATTRIB");
  344. }
  345. if(usingNormalAttrib)
  346. {
  347. srcLines.insert(srcLines.begin(), "#define USING_NORMAL_ATTRIB");
  348. }
  349. if(usingTangentAttrib)
  350. {
  351. srcLines.insert(srcLines.begin(), "#define USING_TANGENT_ATTRIB");
  352. }
  353. BOOST_FOREACH(const std::string& line, srcLines)
  354. {
  355. source += line + "\n";
  356. }
  357. //std::cout << source << std::endl;
  358. }
  359. //==============================================================================
  360. // parseInputTag =
  361. //==============================================================================
  362. void MaterialShaderProgramCreator::parseInputTag(
  363. const boost::property_tree::ptree& pt, std::string& line)
  364. {
  365. using namespace boost::property_tree;
  366. const std::string& name = pt.get<std::string>("name");
  367. boost::optional<const ptree&> valuePt = pt.get_child_optional("value");
  368. GLenum glType;
  369. // Buildin or varying
  370. if(!valuePt)
  371. {
  372. MaterialBuildinVariable::BuildinEnum tmp;
  373. if(MaterialBuildinVariable::isBuildin(name.c_str(), &tmp, &glType))
  374. {
  375. const char* glTypeTxt = glTypeToTxt.at(glType);
  376. line += "uniform ";
  377. line += glTypeTxt;
  378. }
  379. else if(varyingNameToGlType.find(name.c_str()) !=
  380. varyingNameToGlType.end())
  381. {
  382. glType = varyingNameToGlType.at(name.c_str());
  383. const char* glTypeTxt = glTypeToTxt.at(glType);
  384. line += "in ";
  385. line += glTypeTxt;
  386. // Set a few flags
  387. if(name == "vTexCoords")
  388. {
  389. usingTexCoordsAttrib = true;
  390. }
  391. else if(name == "vNormal")
  392. {
  393. usingNormalAttrib = true;
  394. }
  395. else if(name == "vTangent" || name == "vTangentW")
  396. {
  397. usingTangentAttrib = true;
  398. }
  399. }
  400. else
  401. {
  402. throw EXCEPTION("The variable is not build-in or varying: " + name);
  403. }
  404. }
  405. else
  406. {
  407. if(valuePt.get().size() != 1)
  408. {
  409. throw EXCEPTION("Bad value for in: " + name);
  410. }
  411. const ptree::value_type& v = valuePt.get().front();
  412. // Wrong tag
  413. if(txtToGlType.find(v.first.c_str()) == txtToGlType.end())
  414. {
  415. throw EXCEPTION("Wrong type \"" + v.first + "\" for in: " +
  416. name);
  417. }
  418. const std::string& typeTxt = v.first;
  419. line += "uniform " + typeTxt;
  420. glType = txtToGlType.at(typeTxt.c_str());
  421. }
  422. line += " " + name + ";";
  423. }
  424. //==============================================================================
  425. // parseOperatorTag =
  426. //==============================================================================
  427. void MaterialShaderProgramCreator::parseOperatorTag(
  428. const boost::property_tree::ptree& pt)
  429. {
  430. using namespace boost::property_tree;
  431. int id = pt.get<int>("id");
  432. const std::string& funcName = pt.get<std::string>("function");
  433. const ptree& argsPt = pt.get_child("arguments");
  434. std::stringstream line;
  435. // Find func def
  436. const FuncDefinition* def = NULL;
  437. try
  438. {
  439. def = funcNameToDef.at(funcName.c_str());
  440. }
  441. catch(std::exception& e)
  442. {
  443. throw EXCEPTION("Function is not defined in any include file: " +
  444. funcName);
  445. }
  446. // Check args size
  447. if(argsPt.size() != def->argDefinitions.size())
  448. {
  449. throw EXCEPTION("Incorrect number of arguments for: " + funcName);
  450. }
  451. // Write return value
  452. if(def->returnDataType != GL_NONE)
  453. {
  454. line << def->returnDataTypeTxt << " operatorOut" << id << " = ";
  455. }
  456. // Func name
  457. line << funcName + "(";
  458. // Write all arguments
  459. size_t i = 0;
  460. BOOST_FOREACH(const ptree::value_type& v, argsPt)
  461. {
  462. if(v.first != "argument")
  463. {
  464. throw EXCEPTION("Unexpected tag \"" + v.first +
  465. "\" for operator: " + boost::lexical_cast<std::string>(id));
  466. }
  467. const std::string& argName = v.second.data();
  468. line << argName;
  469. // Add a comma
  470. ++i;
  471. if(i != argsPt.size())
  472. {
  473. line << ", ";
  474. }
  475. }
  476. line << ");";
  477. srcLines.push_back("\t" + line.str());
  478. }
  479. //==============================================================================
  480. // compareStrings =
  481. //==============================================================================
  482. bool MaterialShaderProgramCreator::compareStrings(
  483. const std::string& a, const std::string& b)
  484. {
  485. return a < b;
  486. }