Effect.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  1. #include "Base.h"
  2. #include "Effect.h"
  3. #include "FileSystem.h"
  4. #define OPENGL_ES_DEFINE "#define OPENGL_ES\n"
  5. namespace gameplay
  6. {
  7. // Cache of unique effects.
  8. static std::map<std::string, Effect*> __effectCache;
  9. static Effect* __currentEffect = NULL;
  10. Effect::Effect() : _program(0)
  11. {
  12. }
  13. Effect::~Effect()
  14. {
  15. // Remove this effect from the cache.
  16. __effectCache.erase(_id);
  17. // Free uniforms.
  18. for (std::map<std::string, Uniform*>::iterator itr = _uniforms.begin(); itr != _uniforms.end(); ++itr)
  19. {
  20. SAFE_DELETE(itr->second);
  21. }
  22. if (_program)
  23. {
  24. // If our program object is currently bound, unbind it before we're destroyed.
  25. if (__currentEffect == this)
  26. {
  27. GL_ASSERT( glUseProgram(0) );
  28. __currentEffect = NULL;
  29. }
  30. GL_ASSERT( glDeleteProgram(_program) );
  31. _program = 0;
  32. }
  33. }
  34. Effect* Effect::createFromFile(const char* vshPath, const char* fshPath, const char* defines)
  35. {
  36. GP_ASSERT(vshPath);
  37. GP_ASSERT(fshPath);
  38. // Search the effect cache for an identical effect that is already loaded.
  39. std::string uniqueId = vshPath;
  40. uniqueId += ';';
  41. uniqueId += fshPath;
  42. uniqueId += ';';
  43. if (defines)
  44. {
  45. uniqueId += defines;
  46. }
  47. std::map<std::string, Effect*>::const_iterator itr = __effectCache.find(uniqueId);
  48. if (itr != __effectCache.end())
  49. {
  50. // Found an exiting effect with this id, so increase its ref count and return it.
  51. GP_ASSERT(itr->second);
  52. itr->second->addRef();
  53. return itr->second;
  54. }
  55. // Read source from file.
  56. char* vshSource = FileSystem::readAll(vshPath);
  57. if (vshSource == NULL)
  58. {
  59. GP_ERROR("Failed to read vertex shader from file '%s'.", vshPath);
  60. return NULL;
  61. }
  62. char* fshSource = FileSystem::readAll(fshPath);
  63. if (fshSource == NULL)
  64. {
  65. GP_ERROR("Failed to read fragment shader from file '%s'.", fshPath);
  66. SAFE_DELETE_ARRAY(vshSource);
  67. return NULL;
  68. }
  69. Effect* effect = createFromSource(vshPath, vshSource, fshPath, fshSource, defines);
  70. SAFE_DELETE_ARRAY(vshSource);
  71. SAFE_DELETE_ARRAY(fshSource);
  72. if (effect == NULL)
  73. {
  74. GP_ERROR("Failed to create effect from shaders '%s', '%s'.", vshPath, fshPath);
  75. }
  76. else
  77. {
  78. // Store this effect in the cache.
  79. effect->_id = uniqueId;
  80. __effectCache[uniqueId] = effect;
  81. }
  82. return effect;
  83. }
  84. Effect* Effect::createFromSource(const char* vshSource, const char* fshSource, const char* defines)
  85. {
  86. return createFromSource(NULL, vshSource, NULL, fshSource, defines);
  87. }
  88. static void replaceDefines(const char* defines, std::string& out)
  89. {
  90. if (defines && strlen(defines) != 0)
  91. {
  92. out = defines;
  93. size_t pos;
  94. out.insert(0, "#define ");
  95. while ((pos = out.find(';')) != std::string::npos)
  96. {
  97. out.replace(pos, 1, "\n#define ");
  98. }
  99. out += "\n";
  100. }
  101. #ifdef OPENGL_ES
  102. out.insert(0, OPENGL_ES_DEFINE);
  103. #endif
  104. }
  105. static void replaceIncludes(const char* filepath, const char* source, std::string& out)
  106. {
  107. // Replace the #include "xxxx.xxx" with the sourced file contents of "filepath/xxxx.xxx"
  108. std::string str = source;
  109. size_t lastPos = 0;
  110. size_t headPos = 0;
  111. size_t fileLen = str.length();
  112. size_t tailPos = fileLen;
  113. while (headPos < fileLen)
  114. {
  115. lastPos = headPos;
  116. if (headPos == 0)
  117. {
  118. // find the first "#include"
  119. headPos = str.find("#include");
  120. }
  121. else
  122. {
  123. // find the next "#include"
  124. headPos = str.find("#include", headPos + 1);
  125. }
  126. // If "#include" is found
  127. if (headPos != std::string::npos)
  128. {
  129. // append from our last position for the legth (head - last position)
  130. out.append(str.substr(lastPos, headPos - lastPos));
  131. // find the start quote "
  132. size_t startQuote = str.find("\"", headPos) + 1;
  133. if (startQuote == std::string::npos)
  134. {
  135. // We have started an "#include" but missing the leading quote "
  136. GP_ERROR("Compile failed for shader '%s' missing leading \".", filepath);
  137. return;
  138. }
  139. // find the end quote "
  140. size_t endQuote = str.find("\"", startQuote);
  141. if (endQuote == std::string::npos)
  142. {
  143. // We have a start quote but missing the trailing quote "
  144. GP_ERROR("Compile failed for shader '%s' missing trailing \".", filepath);
  145. return;
  146. }
  147. // jump the head position past the end quote
  148. headPos = endQuote + 1;
  149. // File path to include and 'stitch' in the value in the quotes to the file path and source it.
  150. std::string filepathStr = filepath;
  151. std::string directoryPath = filepathStr.substr(0, filepathStr.rfind('/') + 1);
  152. size_t len = endQuote - (startQuote);
  153. std::string includeStr = str.substr(startQuote, len);
  154. directoryPath.append(includeStr);
  155. const char* includedSource = FileSystem::readAll(directoryPath.c_str());
  156. if (includedSource == NULL)
  157. {
  158. GP_ERROR("Compile failed for shader '%s' invalid filepath.", filepathStr.c_str());
  159. return;
  160. }
  161. else
  162. {
  163. // Valid file so lets attempt to see if we need to append anything to it too (recurse...)
  164. replaceIncludes(directoryPath.c_str(), includedSource, out);
  165. SAFE_DELETE_ARRAY(includedSource);
  166. }
  167. }
  168. else
  169. {
  170. // Append the remaining
  171. out.append(str.c_str(), lastPos, tailPos);
  172. }
  173. }
  174. }
  175. static void writeShaderToErrorFile(const char* filePath, const char* source)
  176. {
  177. std::string path = filePath;
  178. path += ".err";
  179. std::auto_ptr<Stream> stream(FileSystem::open(path.c_str(), FileSystem::WRITE));
  180. if (stream.get() != NULL && stream->canWrite())
  181. {
  182. stream->write(source, 1, strlen(source));
  183. }
  184. }
  185. Effect* Effect::createFromSource(const char* vshPath, const char* vshSource, const char* fshPath, const char* fshSource, const char* defines)
  186. {
  187. GP_ASSERT(vshSource);
  188. GP_ASSERT(fshSource);
  189. const unsigned int SHADER_SOURCE_LENGTH = 3;
  190. const GLchar* shaderSource[SHADER_SOURCE_LENGTH];
  191. char* infoLog = NULL;
  192. GLuint vertexShader;
  193. GLuint fragmentShader;
  194. GLuint program;
  195. GLint length;
  196. GLint success;
  197. // Replace all comma separated definitions with #define prefix and \n suffix
  198. std::string definesStr = "";
  199. replaceDefines(defines, definesStr);
  200. shaderSource[0] = definesStr.c_str();
  201. shaderSource[1] = "\n";
  202. std::string vshSourceStr = "";
  203. if (vshPath)
  204. {
  205. // Replace the #include "xxxxx.xxx" with the sources that come from file paths
  206. replaceIncludes(vshPath, vshSource, vshSourceStr);
  207. if (vshSource && strlen(vshSource) != 0)
  208. vshSourceStr += "\n";
  209. //writeShaderToErrorFile(vshPath, vshSourceStr.c_str()); // Debugging
  210. }
  211. shaderSource[2] = vshPath ? vshSourceStr.c_str() : vshSource;
  212. GL_ASSERT( vertexShader = glCreateShader(GL_VERTEX_SHADER) );
  213. GL_ASSERT( glShaderSource(vertexShader, SHADER_SOURCE_LENGTH, shaderSource, NULL) );
  214. GL_ASSERT( glCompileShader(vertexShader) );
  215. GL_ASSERT( glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success) );
  216. if (success != GL_TRUE)
  217. {
  218. GL_ASSERT( glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &length) );
  219. if (length == 0)
  220. {
  221. length = 4096;
  222. }
  223. if (length > 0)
  224. {
  225. infoLog = new char[length];
  226. GL_ASSERT( glGetShaderInfoLog(vertexShader, length, NULL, infoLog) );
  227. infoLog[length-1] = '\0';
  228. }
  229. // Write out the expanded shader file.
  230. if (vshPath)
  231. writeShaderToErrorFile(vshPath, shaderSource[2]);
  232. GP_ERROR("Compile failed for vertex shader '%s' with error '%s'.", vshPath == NULL ? vshSource : vshPath, infoLog == NULL ? "" : infoLog);
  233. SAFE_DELETE_ARRAY(infoLog);
  234. // Clean up.
  235. GL_ASSERT( glDeleteShader(vertexShader) );
  236. return NULL;
  237. }
  238. // Compile the fragment shader.
  239. std::string fshSourceStr;
  240. if (fshPath)
  241. {
  242. // Replace the #include "xxxxx.xxx" with the sources that come from file paths
  243. replaceIncludes(fshPath, fshSource, fshSourceStr);
  244. if (fshSource && strlen(fshSource) != 0)
  245. fshSourceStr += "\n";
  246. //writeShaderToErrorFile(fshPath, fshSourceStr.c_str()); // Debugging
  247. }
  248. shaderSource[2] = fshPath ? fshSourceStr.c_str() : fshSource;
  249. GL_ASSERT( fragmentShader = glCreateShader(GL_FRAGMENT_SHADER) );
  250. GL_ASSERT( glShaderSource(fragmentShader, SHADER_SOURCE_LENGTH, shaderSource, NULL) );
  251. GL_ASSERT( glCompileShader(fragmentShader) );
  252. GL_ASSERT( glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success) );
  253. if (success != GL_TRUE)
  254. {
  255. GL_ASSERT( glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &length) );
  256. if (length == 0)
  257. {
  258. length = 4096;
  259. }
  260. if (length > 0)
  261. {
  262. infoLog = new char[length];
  263. GL_ASSERT( glGetShaderInfoLog(fragmentShader, length, NULL, infoLog) );
  264. infoLog[length-1] = '\0';
  265. }
  266. // Write out the expanded shader file.
  267. if (fshPath)
  268. writeShaderToErrorFile(fshPath, shaderSource[2]);
  269. GP_ERROR("Compile failed for fragment shader (%s): %s", fshPath == NULL ? fshSource : fshPath, infoLog == NULL ? "" : infoLog);
  270. SAFE_DELETE_ARRAY(infoLog);
  271. // Clean up.
  272. GL_ASSERT( glDeleteShader(vertexShader) );
  273. GL_ASSERT( glDeleteShader(fragmentShader) );
  274. return NULL;
  275. }
  276. // Link program.
  277. GL_ASSERT( program = glCreateProgram() );
  278. GL_ASSERT( glAttachShader(program, vertexShader) );
  279. GL_ASSERT( glAttachShader(program, fragmentShader) );
  280. GL_ASSERT( glLinkProgram(program) );
  281. GL_ASSERT( glGetProgramiv(program, GL_LINK_STATUS, &success) );
  282. // Delete shaders after linking.
  283. GL_ASSERT( glDeleteShader(vertexShader) );
  284. GL_ASSERT( glDeleteShader(fragmentShader) );
  285. // Check link status.
  286. if (success != GL_TRUE)
  287. {
  288. GL_ASSERT( glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length) );
  289. if (length == 0)
  290. {
  291. length = 4096;
  292. }
  293. if (length > 0)
  294. {
  295. infoLog = new char[length];
  296. GL_ASSERT( glGetProgramInfoLog(program, length, NULL, infoLog) );
  297. infoLog[length-1] = '\0';
  298. }
  299. GP_ERROR("Linking program failed (%s,%s): %s", vshPath == NULL ? "NULL" : vshPath, fshPath == NULL ? "NULL" : fshPath, infoLog == NULL ? "" : infoLog);
  300. SAFE_DELETE_ARRAY(infoLog);
  301. // Clean up.
  302. GL_ASSERT( glDeleteProgram(program) );
  303. return NULL;
  304. }
  305. // Create and return the new Effect.
  306. Effect* effect = new Effect();
  307. effect->_program = program;
  308. // Query and store vertex attribute meta-data from the program.
  309. // NOTE: Rather than using glBindAttribLocation to explicitly specify our own
  310. // preferred attribute locations, we're going to query the locations that were
  311. // automatically bound by the GPU. While it can sometimes be convenient to use
  312. // glBindAttribLocation, some vendors actually reserve certain attribute indices
  313. // and therefore using this function can create compatibility issues between
  314. // different hardware vendors.
  315. GLint activeAttributes;
  316. GL_ASSERT( glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &activeAttributes) );
  317. if (activeAttributes > 0)
  318. {
  319. GL_ASSERT( glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &length) );
  320. if (length > 0)
  321. {
  322. GLchar* attribName = new GLchar[length + 1];
  323. GLint attribSize;
  324. GLenum attribType;
  325. GLint attribLocation;
  326. for (int i = 0; i < activeAttributes; ++i)
  327. {
  328. // Query attribute info.
  329. GL_ASSERT( glGetActiveAttrib(program, i, length, NULL, &attribSize, &attribType, attribName) );
  330. attribName[length] = '\0';
  331. // Query the pre-assigned attribute location.
  332. GL_ASSERT( attribLocation = glGetAttribLocation(program, attribName) );
  333. // Assign the vertex attribute mapping for the effect.
  334. effect->_vertexAttributes[attribName] = attribLocation;
  335. }
  336. SAFE_DELETE_ARRAY(attribName);
  337. }
  338. }
  339. // Query and store uniforms from the program.
  340. GLint activeUniforms;
  341. GL_ASSERT( glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &activeUniforms) );
  342. if (activeUniforms > 0)
  343. {
  344. GL_ASSERT( glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &length) );
  345. if (length > 0)
  346. {
  347. GLchar* uniformName = new GLchar[length + 1];
  348. GLint uniformSize;
  349. GLenum uniformType;
  350. GLint uniformLocation;
  351. unsigned int samplerIndex = 0;
  352. for (int i = 0; i < activeUniforms; ++i)
  353. {
  354. // Query uniform info.
  355. GL_ASSERT( glGetActiveUniform(program, i, length, NULL, &uniformSize, &uniformType, uniformName) );
  356. uniformName[length] = '\0'; // null terminate
  357. if (length > 3)
  358. {
  359. // If this is an array uniform, strip array indexers off it since GL does not
  360. // seem to be consistent across different drivers/implementations in how it returns
  361. // array uniforms. On some systems it will return "u_matrixArray", while on others
  362. // it will return "u_matrixArray[0]".
  363. char* c = strrchr(uniformName, '[');
  364. if (c)
  365. {
  366. *c = '\0';
  367. }
  368. }
  369. // Query the pre-assigned uniform location.
  370. GL_ASSERT( uniformLocation = glGetUniformLocation(program, uniformName) );
  371. Uniform* uniform = new Uniform();
  372. uniform->_effect = effect;
  373. uniform->_name = uniformName;
  374. uniform->_location = uniformLocation;
  375. uniform->_type = uniformType;
  376. if (uniformType == GL_SAMPLER_2D)
  377. {
  378. uniform->_index = samplerIndex;
  379. samplerIndex += uniformSize;
  380. }
  381. else
  382. {
  383. uniform->_index = 0;
  384. }
  385. effect->_uniforms[uniformName] = uniform;
  386. }
  387. SAFE_DELETE_ARRAY(uniformName);
  388. }
  389. }
  390. return effect;
  391. }
  392. const char* Effect::getId() const
  393. {
  394. return _id.c_str();
  395. }
  396. VertexAttribute Effect::getVertexAttribute(const char* name) const
  397. {
  398. std::map<std::string, VertexAttribute>::const_iterator itr = _vertexAttributes.find(name);
  399. return (itr == _vertexAttributes.end() ? -1 : itr->second);
  400. }
  401. Uniform* Effect::getUniform(const char* name) const
  402. {
  403. std::map<std::string, Uniform*>::const_iterator itr = _uniforms.find(name);
  404. return (itr == _uniforms.end() ? NULL : itr->second);
  405. }
  406. Uniform* Effect::getUniform(unsigned int index) const
  407. {
  408. unsigned int i = 0;
  409. for (std::map<std::string, Uniform*>::const_iterator itr = _uniforms.begin(); itr != _uniforms.end(); ++itr, ++i)
  410. {
  411. if (i == index)
  412. {
  413. return itr->second;
  414. }
  415. }
  416. return NULL;
  417. }
  418. unsigned int Effect::getUniformCount() const
  419. {
  420. return (unsigned int)_uniforms.size();
  421. }
  422. void Effect::setValue(Uniform* uniform, float value)
  423. {
  424. GP_ASSERT(uniform);
  425. GL_ASSERT( glUniform1f(uniform->_location, value) );
  426. }
  427. void Effect::setValue(Uniform* uniform, const float* values, unsigned int count)
  428. {
  429. GP_ASSERT(uniform);
  430. GP_ASSERT(values);
  431. GL_ASSERT( glUniform1fv(uniform->_location, count, values) );
  432. }
  433. void Effect::setValue(Uniform* uniform, int value)
  434. {
  435. GP_ASSERT(uniform);
  436. GL_ASSERT( glUniform1i(uniform->_location, value) );
  437. }
  438. void Effect::setValue(Uniform* uniform, const int* values, unsigned int count)
  439. {
  440. GP_ASSERT(uniform);
  441. GP_ASSERT(values);
  442. GL_ASSERT( glUniform1iv(uniform->_location, count, values) );
  443. }
  444. void Effect::setValue(Uniform* uniform, const Matrix& value)
  445. {
  446. GP_ASSERT(uniform);
  447. GL_ASSERT( glUniformMatrix4fv(uniform->_location, 1, GL_FALSE, value.m) );
  448. }
  449. void Effect::setValue(Uniform* uniform, const Matrix* values, unsigned int count)
  450. {
  451. GP_ASSERT(uniform);
  452. GP_ASSERT(values);
  453. GL_ASSERT( glUniformMatrix4fv(uniform->_location, count, GL_FALSE, (GLfloat*)values) );
  454. }
  455. void Effect::setValue(Uniform* uniform, const Vector2& value)
  456. {
  457. GP_ASSERT(uniform);
  458. GL_ASSERT( glUniform2f(uniform->_location, value.x, value.y) );
  459. }
  460. void Effect::setValue(Uniform* uniform, const Vector2* values, unsigned int count)
  461. {
  462. GP_ASSERT(uniform);
  463. GP_ASSERT(values);
  464. GL_ASSERT( glUniform2fv(uniform->_location, count, (GLfloat*)values) );
  465. }
  466. void Effect::setValue(Uniform* uniform, const Vector3& value)
  467. {
  468. GP_ASSERT(uniform);
  469. GL_ASSERT( glUniform3f(uniform->_location, value.x, value.y, value.z) );
  470. }
  471. void Effect::setValue(Uniform* uniform, const Vector3* values, unsigned int count)
  472. {
  473. GP_ASSERT(uniform);
  474. GP_ASSERT(values);
  475. GL_ASSERT( glUniform3fv(uniform->_location, count, (GLfloat*)values) );
  476. }
  477. void Effect::setValue(Uniform* uniform, const Vector4& value)
  478. {
  479. GP_ASSERT(uniform);
  480. GL_ASSERT( glUniform4f(uniform->_location, value.x, value.y, value.z, value.w) );
  481. }
  482. void Effect::setValue(Uniform* uniform, const Vector4* values, unsigned int count)
  483. {
  484. GP_ASSERT(uniform);
  485. GP_ASSERT(values);
  486. GL_ASSERT( glUniform4fv(uniform->_location, count, (GLfloat*)values) );
  487. }
  488. void Effect::setValue(Uniform* uniform, const Texture::Sampler* sampler)
  489. {
  490. GP_ASSERT(uniform);
  491. GP_ASSERT(uniform->_type == GL_SAMPLER_2D);
  492. GP_ASSERT(sampler);
  493. GL_ASSERT( glActiveTexture(GL_TEXTURE0 + uniform->_index) );
  494. // Bind the sampler - this binds the texture and applies sampler state
  495. const_cast<Texture::Sampler*>(sampler)->bind();
  496. GL_ASSERT( glUniform1i(uniform->_location, uniform->_index) );
  497. }
  498. void Effect::setValue(Uniform* uniform, const Texture::Sampler** values, unsigned int count)
  499. {
  500. GP_ASSERT(uniform);
  501. GP_ASSERT(uniform->_type == GL_SAMPLER_2D);
  502. GP_ASSERT(values);
  503. // Set samplers as active and load texture unit array
  504. GLint units[32];
  505. for (unsigned int i = 0; i < count; ++i)
  506. {
  507. GL_ASSERT( glActiveTexture(GL_TEXTURE0 + uniform->_index + i) );
  508. // Bind the sampler - this binds the texture and applies sampler state
  509. const_cast<Texture::Sampler*>(values[i])->bind();
  510. units[i] = uniform->_index + i;
  511. }
  512. // Pass texture unit array to GL
  513. GL_ASSERT( glUniform1iv(uniform->_location, count, units) );
  514. }
  515. void Effect::bind()
  516. {
  517. GL_ASSERT( glUseProgram(_program) );
  518. __currentEffect = this;
  519. }
  520. Effect* Effect::getCurrentEffect()
  521. {
  522. return __currentEffect;
  523. }
  524. Uniform::Uniform() :
  525. _location(-1), _type(0), _index(0)
  526. {
  527. }
  528. Uniform::~Uniform()
  529. {
  530. // hidden
  531. }
  532. Effect* Uniform::getEffect() const
  533. {
  534. return _effect;
  535. }
  536. const char* Uniform::getName() const
  537. {
  538. return _name.c_str();
  539. }
  540. const GLenum Uniform::getType() const
  541. {
  542. return _type;
  543. }
  544. }