Effect.cpp 21 KB

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