ShaderProg.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. #include <boost/filesystem.hpp>
  2. #include <fstream>
  3. #include "ShaderProg.h"
  4. #include "Renderer.h"
  5. #include "ShaderPrePreprocessor.h"
  6. #include "Texture.h"
  7. #include "App.h"
  8. #define SHADER_ERROR(x) ERROR("Shader (" << getRsrcName() << "): " << x)
  9. #define SHADER_WARNING(x) WARNING("Shader (" << getRsrcName() << "): " << x)
  10. //======================================================================================================================
  11. // Statics =
  12. //======================================================================================================================
  13. string ShaderProg::stdSourceCode(
  14. "#version 150 compatibility\n \
  15. precision lowp float;\n \
  16. #pragma optimize(on)\n \
  17. #pragma debug(off)\n"
  18. );
  19. //======================================================================================================================
  20. // set uniforms =
  21. //======================================================================================================================
  22. /**
  23. * Standard set uniform checks
  24. * - Check if initialized
  25. * - if the current shader program is the var's shader program
  26. * - if the GL driver gives the same location as the one the var has
  27. */
  28. #define STD_SET_UNI_CHECK() DEBUG_ERR(getLoc() == -1); \
  29. DEBUG_ERR(ShaderProg::getCurrentProgramGlId() != fatherSProg->getGlId()); \
  30. DEBUG_ERR(glGetUniformLocation(fatherSProg->getGlId(), getName().c_str()) != getLoc());
  31. void ShaderProg::UniVar::setFloat(float f) const
  32. {
  33. STD_SET_UNI_CHECK();
  34. DEBUG_ERR(getGlDataType() != GL_FLOAT);
  35. glUniform1f(getLoc(), f);
  36. }
  37. void ShaderProg::UniVar::setFloatVec(float f[], uint size) const
  38. {
  39. STD_SET_UNI_CHECK();
  40. DEBUG_ERR(getGlDataType() != GL_FLOAT);
  41. glUniform1fv(getLoc(), size, f);
  42. }
  43. void ShaderProg::UniVar::setVec2(const Vec2 v2[], uint size) const
  44. {
  45. STD_SET_UNI_CHECK();
  46. DEBUG_ERR(getGlDataType() != GL_FLOAT_VEC2);
  47. glUniform2fv(getLoc(), size, &(const_cast<Vec2&>(v2[0]))[0]);
  48. }
  49. void ShaderProg::UniVar::setVec3(const Vec3 v3[], uint size) const
  50. {
  51. STD_SET_UNI_CHECK();
  52. DEBUG_ERR(getGlDataType() != GL_FLOAT_VEC3);
  53. glUniform3fv(getLoc(), size, &(const_cast<Vec3&>(v3[0]))[0]);
  54. }
  55. void ShaderProg::UniVar::setVec4(const Vec4 v4[], uint size) const
  56. {
  57. STD_SET_UNI_CHECK();
  58. DEBUG_ERR(getGlDataType() != GL_FLOAT_VEC4);
  59. glUniform4fv(getLoc(), size, &(const_cast<Vec4&>(v4[0]))[0]);
  60. }
  61. void ShaderProg::UniVar::setMat3(const Mat3 m3[], uint size) const
  62. {
  63. STD_SET_UNI_CHECK();
  64. DEBUG_ERR(getGlDataType() != GL_FLOAT_MAT3);
  65. glUniformMatrix3fv(getLoc(), size, true, &(m3[0])[0]);
  66. }
  67. void ShaderProg::UniVar::setMat4(const Mat4 m4[], uint size) const
  68. {
  69. STD_SET_UNI_CHECK();
  70. DEBUG_ERR(getGlDataType() != GL_FLOAT_MAT4);
  71. glUniformMatrix4fv(getLoc(), size, true, &(m4[0])[0]);
  72. }
  73. void ShaderProg::UniVar::setTexture(const Texture& tex, uint texUnit) const
  74. {
  75. STD_SET_UNI_CHECK();
  76. DEBUG_ERR(getGlDataType() != GL_SAMPLER_2D && getGlDataType() != GL_SAMPLER_2D_SHADOW);
  77. tex.bind(texUnit);
  78. glUniform1i(getLoc(), texUnit);
  79. }
  80. //======================================================================================================================
  81. // createAndCompileShader =
  82. //======================================================================================================================
  83. uint ShaderProg::createAndCompileShader(const char* sourceCode, const char* preproc, int type) const
  84. {
  85. uint glId = 0;
  86. const char* sourceStrs[2] = {NULL, NULL};
  87. // create the shader
  88. glId = glCreateShader(type);
  89. // attach the source
  90. sourceStrs[1] = sourceCode;
  91. sourceStrs[0] = preproc;
  92. // compile
  93. glShaderSource(glId, 2, sourceStrs, NULL);
  94. glCompileShader(glId);
  95. int success;
  96. glGetShaderiv(glId, GL_COMPILE_STATUS, &success);
  97. if(!success)
  98. {
  99. // print info log
  100. int infoLen = 0;
  101. int charsWritten = 0;
  102. char* infoLog = NULL;
  103. glGetShaderiv(glId, GL_INFO_LOG_LENGTH, &infoLen);
  104. infoLog = (char*)malloc((infoLen+1)*sizeof(char));
  105. glGetShaderInfoLog(glId, infoLen, &charsWritten, infoLog);
  106. const char* shaderType;
  107. switch(type)
  108. {
  109. case GL_VERTEX_SHADER:
  110. shaderType = "Vertex shader";
  111. break;
  112. case GL_FRAGMENT_SHADER:
  113. shaderType = "Fragment shader";
  114. break;
  115. default:
  116. DEBUG_ERR(1); // Not supported
  117. }
  118. SHADER_ERROR(shaderType << " compiler log follows:\n" << infoLog);
  119. free(infoLog);
  120. return 0;
  121. }
  122. return glId;
  123. }
  124. //======================================================================================================================
  125. // link =
  126. //======================================================================================================================
  127. bool ShaderProg::link()
  128. {
  129. // link
  130. glLinkProgram(glId);
  131. // check if linked correctly
  132. int success;
  133. glGetProgramiv(glId, GL_LINK_STATUS, &success);
  134. if(!success)
  135. {
  136. int info_len = 0;
  137. int charsWritten = 0;
  138. char* infoLogTxt = NULL;
  139. glGetProgramiv(glId, GL_INFO_LOG_LENGTH, &info_len);
  140. infoLogTxt = (char*)malloc((info_len+1)*sizeof(char));
  141. glGetProgramInfoLog(glId, info_len, &charsWritten, infoLogTxt);
  142. SHADER_ERROR("Link log follows:\n" << infoLogTxt);
  143. free(infoLogTxt);
  144. return false;
  145. }
  146. return true;
  147. }
  148. //======================================================================================================================
  149. // getUniAndAttribVars =
  150. //======================================================================================================================
  151. void ShaderProg::getUniAndAttribVars()
  152. {
  153. int num;
  154. char name_[256];
  155. GLsizei length;
  156. GLint size;
  157. GLenum type;
  158. // attrib locations
  159. glGetProgramiv(glId, GL_ACTIVE_ATTRIBUTES, &num);
  160. attribVars.reserve(num);
  161. for(int i=0; i<num; i++) // loop all attributes
  162. {
  163. glGetActiveAttrib(glId, i, sizeof(name_)/sizeof(char), &length, &size, &type, name_);
  164. name_[length] = '\0';
  165. // check if its FFP location
  166. int loc = glGetAttribLocation(glId, name_);
  167. if(loc == -1) // if -1 it means that its an FFP var
  168. {
  169. SHADER_WARNING("You are using FFP vertex attributes (\"" << name_ << "\")");
  170. continue;
  171. }
  172. attribVars.push_back(AttribVar(loc, name_, type, this));
  173. attribNameToVar[name_] = &attribVars.back();
  174. }
  175. // uni locations
  176. glGetProgramiv(glId, GL_ACTIVE_UNIFORMS, &num);
  177. uniVars.reserve(num);
  178. for(int i=0; i<num; i++) // loop all uniforms
  179. {
  180. glGetActiveUniform(glId, i, sizeof(name_)/sizeof(char), &length, &size, &type, name_);
  181. name_[length] = '\0';
  182. // check if its FFP location
  183. int loc = glGetUniformLocation(glId, name_);
  184. if(loc == -1) // if -1 it means that its an FFP var
  185. {
  186. SHADER_WARNING("You are using FFP uniforms (\"" << name_ << "\")");
  187. continue;
  188. }
  189. uniVars.push_back(UniVar(loc, name_, type, this));
  190. uniNameToVar[name_] = &uniVars.back();
  191. }
  192. }
  193. //======================================================================================================================
  194. // bindCustomAttribLocs =
  195. //======================================================================================================================
  196. bool ShaderProg::bindCustomAttribLocs(const ShaderPrePreprocessor& pars) const
  197. {
  198. for(uint i=0; i<pars.getOutput().getAttribLocs().size(); ++i)
  199. {
  200. const string& name = pars.getOutput().getAttribLocs()[i].name;
  201. int loc = pars.getOutput().getAttribLocs()[i].customLoc;
  202. glBindAttribLocation(glId, loc, name.c_str());
  203. // check for error
  204. if(!GL_OK())
  205. {
  206. SHADER_ERROR("Something went wrong for attrib \"" << name << "\" and location " << loc);
  207. return false;
  208. }
  209. }
  210. return true;
  211. }
  212. //======================================================================================================================
  213. // load =
  214. //======================================================================================================================
  215. bool ShaderProg::load(const char* filename)
  216. {
  217. DEBUG_ERR(glId != numeric_limits<uint>::max());
  218. ShaderPrePreprocessor pars;
  219. if(!pars.parseFile(filename)) return false;
  220. // 1) create and compile the shaders
  221. string preprocSource = stdSourceCode;
  222. uint vertGlId = createAndCompileShader(pars.getOutput().getVertShaderSource().c_str(), preprocSource.c_str(),
  223. GL_VERTEX_SHADER);
  224. if(vertGlId == 0) return false;
  225. uint fragGlId = createAndCompileShader(pars.getOutput().getFragShaderSource().c_str(), preprocSource.c_str(),
  226. GL_FRAGMENT_SHADER);
  227. if(fragGlId == 0) return false;
  228. // 2) create program and attach shaders
  229. glId = glCreateProgram();
  230. if(glId == 0)
  231. {
  232. ERROR("glCreateProgram failed");
  233. return false;
  234. }
  235. glAttachShader(glId, vertGlId);
  236. glAttachShader(glId, fragGlId);
  237. // 3) bind the custom attrib locs
  238. if(!bindCustomAttribLocs(pars)) return false;
  239. // 5) set the TRFFB varyings
  240. if(pars.getOutput().getTrffbVaryings().size() > 1)
  241. {
  242. const char* varsArr[128];
  243. for(uint i=0; i<pars.getOutput().getTrffbVaryings().size(); i++)
  244. {
  245. varsArr[i] = pars.getOutput().getTrffbVaryings()[i].name.c_str();
  246. }
  247. glTransformFeedbackVaryings(glId, pars.getOutput().getTrffbVaryings().size(), varsArr, GL_SEPARATE_ATTRIBS);
  248. }
  249. // 6) link
  250. if(!link()) return false;
  251. // init the rest
  252. getUniAndAttribVars();
  253. return true;
  254. }
  255. //======================================================================================================================
  256. // findUniVar =
  257. //======================================================================================================================
  258. const ShaderProg::UniVar* ShaderProg::findUniVar(const char* name) const
  259. {
  260. NameToUniVarIterator it = uniNameToVar.find(name);
  261. if(it == uniNameToVar.end())
  262. {
  263. SHADER_ERROR("Cannot get uniform loc \"" << name << '\"');
  264. return NULL;
  265. }
  266. return it->second;
  267. }
  268. //======================================================================================================================
  269. // findAttribVar =
  270. //======================================================================================================================
  271. const ShaderProg::AttribVar* ShaderProg::findAttribVar(const char* name) const
  272. {
  273. NameToAttribVarIterator it = attribNameToVar.find(name);
  274. if(it == attribNameToVar.end())
  275. {
  276. SHADER_ERROR("Cannot get attribute loc \"" << name << '\"');
  277. return NULL;
  278. }
  279. return it->second;
  280. }
  281. //======================================================================================================================
  282. // uniVarExists =
  283. //======================================================================================================================
  284. bool ShaderProg::uniVarExists(const char* name) const
  285. {
  286. NameToUniVarIterator it = uniNameToVar.find(name);
  287. return it != uniNameToVar.end();
  288. }
  289. //======================================================================================================================
  290. // attribVarExists =
  291. //======================================================================================================================
  292. bool ShaderProg::attribVarExists(const char* name) const
  293. {
  294. NameToAttribVarIterator it = attribNameToVar.find(name);
  295. return it != attribNameToVar.end();
  296. }
  297. //======================================================================================================================
  298. // createSrcCodeToCache =
  299. //======================================================================================================================
  300. string ShaderProg::createSrcCodeToCache(const char* sProgFPathName, const char* preAppendedSrcCode,
  301. const char* newFNamePrefix)
  302. {
  303. filesystem::path newfPathName = app->getCachePath() /
  304. (string(newFNamePrefix) + "_" + filesystem::path(sProgFPathName).filename());
  305. if(filesystem::exists(newfPathName))
  306. {
  307. return newfPathName.string();
  308. }
  309. string src_ = Util::readFile(sProgFPathName);
  310. DEBUG_ERR(src_ == "");
  311. string src = preAppendedSrcCode + src_;
  312. ofstream f(newfPathName.string().c_str());
  313. if(!f.good())
  314. {
  315. ERROR("Cannot open file for writing \"" << newfPathName.string() << "\"");
  316. return newfPathName.string();
  317. }
  318. f.write(src.c_str(), src.length());
  319. return newfPathName.string();
  320. }