Material.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. #include "Material.h"
  2. #include "MaterialVariable.h"
  3. #include "Misc/PropertyTree.h"
  4. #include "MaterialShaderProgramCreator.h"
  5. #include "Core/App.h"
  6. #include "Core/Globals.h"
  7. #include "ShaderProgram.h"
  8. #include <boost/foreach.hpp>
  9. #include <boost/property_tree/ptree.hpp>
  10. #include <boost/property_tree/xml_parser.hpp>
  11. #include <boost/assign/list_of.hpp>
  12. #include <boost/functional/hash.hpp>
  13. #include <algorithm>
  14. //==============================================================================
  15. // Statics =
  16. //==============================================================================
  17. // Dont make idiotic mistakes
  18. #define TXT_AND_ENUM(x) \
  19. (#x, x)
  20. ConstCharPtrHashMap<GLenum>::Type Material::txtToBlengGlEnum =
  21. boost::assign::map_list_of
  22. TXT_AND_ENUM(GL_ZERO)
  23. TXT_AND_ENUM(GL_ONE)
  24. TXT_AND_ENUM(GL_DST_COLOR)
  25. TXT_AND_ENUM(GL_ONE_MINUS_DST_COLOR)
  26. TXT_AND_ENUM(GL_SRC_ALPHA)
  27. TXT_AND_ENUM(GL_ONE_MINUS_SRC_ALPHA)
  28. TXT_AND_ENUM(GL_DST_ALPHA)
  29. TXT_AND_ENUM(GL_ONE_MINUS_DST_ALPHA)
  30. TXT_AND_ENUM(GL_SRC_ALPHA_SATURATE)
  31. TXT_AND_ENUM(GL_SRC_COLOR)
  32. TXT_AND_ENUM(GL_ONE_MINUS_SRC_COLOR);
  33. //==============================================================================
  34. // Constructor =
  35. //==============================================================================
  36. Material::Material()
  37. {
  38. renderInBlendingStageFlag = false;
  39. blendingSfactor = GL_ONE;
  40. blendingDfactor = GL_ZERO;
  41. depthTesting = true;
  42. wireframe = false;
  43. castsShadowFlag = true;
  44. // Reset tha array
  45. std::fill(buildinsArr.begin(), buildinsArr.end(),
  46. static_cast<MaterialBuildinVariable*>(NULL));
  47. }
  48. //==============================================================================
  49. // Destructor =
  50. //==============================================================================
  51. Material::~Material()
  52. {}
  53. //==============================================================================
  54. // load =
  55. //==============================================================================
  56. void Material::load(const char* filename)
  57. {
  58. try
  59. {
  60. using namespace boost::property_tree;
  61. ptree pt;
  62. read_xml(filename, pt);
  63. parseMaterialTag(pt.get_child("material"));
  64. }
  65. catch(std::exception& e)
  66. {
  67. throw EXCEPTION("File \"" + filename + "\" failed: " + e.what());
  68. }
  69. }
  70. //==============================================================================
  71. // parseMaterialTag =
  72. //==============================================================================
  73. void Material::parseMaterialTag(const boost::property_tree::ptree& pt)
  74. {
  75. using namespace boost::property_tree;
  76. //
  77. // castsShadow
  78. //
  79. boost::optional<bool> shadow =
  80. PropertyTree::getBoolOptional(pt, "castsShadow");
  81. if(shadow)
  82. {
  83. castsShadowFlag = shadow.get();
  84. }
  85. //
  86. // renderInBlendingStage
  87. //
  88. boost::optional<bool> bs =
  89. PropertyTree::getBoolOptional(pt, "renderInBlendingStage");
  90. if(bs)
  91. {
  92. renderInBlendingStageFlag = bs.get();
  93. }
  94. //
  95. // blendFunctions
  96. //
  97. boost::optional<const ptree&> blendFuncsTree =
  98. pt.get_child_optional("blendFunctions");
  99. if(blendFuncsTree)
  100. {
  101. // sFactor
  102. {
  103. const std::string& tmp =
  104. blendFuncsTree.get().get<std::string>("sFactor");
  105. ConstCharPtrHashMap<GLenum>::Type::const_iterator it =
  106. txtToBlengGlEnum.find(tmp.c_str());
  107. if(it == txtToBlengGlEnum.end())
  108. {
  109. throw EXCEPTION("Incorrect blend enum: " + tmp);
  110. }
  111. blendingSfactor = it->second;
  112. }
  113. // dFactor
  114. {
  115. const std::string& tmp =
  116. blendFuncsTree.get().get<std::string>("dFactor");
  117. ConstCharPtrHashMap<GLenum>::Type::const_iterator it =
  118. txtToBlengGlEnum.find(tmp.c_str());
  119. if(it == txtToBlengGlEnum.end())
  120. {
  121. throw EXCEPTION("Incorrect blend enum: " + tmp);
  122. }
  123. blendingDfactor = it->second;
  124. }
  125. }
  126. //
  127. // depthTesting
  128. //
  129. boost::optional<bool> dp =
  130. PropertyTree::getBoolOptional(pt, "depthTesting");
  131. if(dp)
  132. {
  133. depthTesting = dp.get();
  134. }
  135. //
  136. // wireframe
  137. //
  138. boost::optional<bool> wf =
  139. PropertyTree::getBoolOptional(pt, "wireframe");
  140. if(wf)
  141. {
  142. wireframe = wf.get();
  143. }
  144. //
  145. // shaderProgram
  146. //
  147. MaterialShaderProgramCreator mspc(pt.get_child("shaderProgram"));
  148. for(uint i = 0; i < PASS_TYPES_NUM; i++)
  149. {
  150. std::string src = std::string("#define ") + passNames[i] + "\n" +
  151. mspc.getShaderProgramSource();
  152. std::string filename = createShaderProgSourceToCache(src);
  153. sProgs[i].loadRsrc(filename.c_str());
  154. }
  155. populateVariables(pt.get_child("shaderProgram.inputs"));
  156. }
  157. //==============================================================================
  158. // createShaderProgSourceToCache =
  159. //==============================================================================
  160. std::string Material::createShaderProgSourceToCache(const std::string& source)
  161. {
  162. // Create the hash
  163. boost::hash<std::string> stringHash;
  164. std::size_t h = stringHash(source);
  165. std::string prefix = boost::lexical_cast<std::string>(h);
  166. // Create path
  167. boost::filesystem::path newfPathName =
  168. AppSingleton::getInstance().getCachePath() / (prefix + ".glsl");
  169. // If file not exists write it
  170. if(!boost::filesystem::exists(newfPathName))
  171. {
  172. // If not create it
  173. std::ofstream f(newfPathName.string().c_str());
  174. if(!f.is_open())
  175. {
  176. throw EXCEPTION("Cannot open file for writing: " +
  177. newfPathName.string());
  178. }
  179. f.write(source.c_str(), source.length());
  180. f.close();
  181. }
  182. return newfPathName.string();
  183. }
  184. //==============================================================================
  185. // populateVariables =
  186. //==============================================================================
  187. void Material::populateVariables(const boost::property_tree::ptree& pt)
  188. {
  189. using namespace boost::property_tree;
  190. //
  191. // Get all names of all shader prog vars. Dont duplicate
  192. //
  193. std::map<std::string, GLenum> allVarNames;
  194. BOOST_FOREACH(const RsrcPtr<ShaderProgram>& sProg, sProgs)
  195. {
  196. BOOST_FOREACH(const ShaderProgramVariable& v, sProg->getVariables())
  197. {
  198. allVarNames[v.getName()] = v.getGlDataType();
  199. }
  200. }
  201. //
  202. // Iterate shader program variables
  203. //
  204. MaterialVariable::ShaderPrograms sProgs_;
  205. for(uint i = 0; i < PASS_TYPES_NUM; i++)
  206. {
  207. sProgs_[i] = sProgs[i].get();
  208. }
  209. std::map<std::string, GLenum>::const_iterator it = allVarNames.begin();
  210. for(; it != allVarNames.end(); it++)
  211. {
  212. const char* svName = it->first.c_str();
  213. GLenum dataType = it->second;
  214. // Buildin?
  215. if(MaterialBuildinVariable::isBuildin(svName))
  216. {
  217. MaterialBuildinVariable* v =
  218. new MaterialBuildinVariable(svName, sProgs_);
  219. mtlVars.push_back(v);
  220. buildinsArr[v->getMatchingVariable()] = v;
  221. }
  222. // User defined
  223. else
  224. {
  225. // Find the ptree that contains the value
  226. const ptree* valuePt = NULL;
  227. BOOST_FOREACH(const ptree::value_type& v, pt)
  228. {
  229. if(v.first != "input")
  230. {
  231. throw EXCEPTION("Expecting <input> and not: " + v.first);
  232. }
  233. if(v.second.get<std::string>("name") == svName)
  234. {
  235. valuePt = &v.second.get_child("value");
  236. break;
  237. }
  238. }
  239. if(valuePt == NULL)
  240. {
  241. throw EXCEPTION("Variable not buildin and not found: " +
  242. svName);
  243. }
  244. MaterialUserVariable* v = NULL;
  245. // Get the value
  246. switch(dataType)
  247. {
  248. // sampler2D
  249. case GL_SAMPLER_2D:
  250. v = new MaterialUserVariable(svName, sProgs_,
  251. valuePt->get<std::string>("sampler2D").c_str());
  252. break;
  253. // float
  254. case GL_FLOAT:
  255. v = new MaterialUserVariable(svName, sProgs_,
  256. PropertyTree::getFloat(*valuePt));
  257. break;
  258. // vec2
  259. case GL_FLOAT_VEC2:
  260. v = new MaterialUserVariable(svName, sProgs_,
  261. PropertyTree::getVec2(*valuePt));
  262. break;
  263. // vec3
  264. case GL_FLOAT_VEC3:
  265. v = new MaterialUserVariable(svName, sProgs_,
  266. PropertyTree::getVec3(*valuePt));
  267. break;
  268. // vec4
  269. case GL_FLOAT_VEC4:
  270. v = new MaterialUserVariable(svName, sProgs_,
  271. PropertyTree::getVec4(*valuePt));
  272. break;
  273. // default is error
  274. default:
  275. ASSERT(0);
  276. }
  277. mtlVars.push_back(v);
  278. userMtlVars.push_back(v);
  279. }
  280. } // end for all sprog vars
  281. }