CCGLProgramState.cpp 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019
  1. /****************************************************************************
  2. Copyright 2011 Jeff Lamarche
  3. Copyright 2012 Goffredo Marocchi
  4. Copyright 2012 Ricardo Quesada
  5. Copyright 2012 cocos2d-x.org
  6. Copyright (c) 2013-2016 Chukong Technologies Inc.
  7. Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
  8. http://www.cocos2d-x.org
  9. Permission is hereby granted, free of charge, to any person obtaining a copy
  10. of this software and associated documentation files (the "Software"), to deal
  11. in the Software without restriction, including without limitation the rights
  12. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. copies of the Software, and to permit persons to whom the Software is
  14. furnished to do so, subject to the following conditions:
  15. The above copyright notice and this permission notice shall be included in
  16. all copies or substantial portions of the Software.
  17. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN false EVENT SHALL THE
  20. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. THE SOFTWARE.
  24. ****************************************************************************/
  25. #include "renderer/CCGLProgramState.h"
  26. #include "renderer/CCGLProgram.h"
  27. #include "renderer/CCGLProgramStateCache.h"
  28. #include "renderer/CCGLProgramCache.h"
  29. #include "renderer/ccGLStateCache.h"
  30. #include "renderer/CCTexture2D.h"
  31. #include "base/CCEventCustom.h"
  32. #include "base/CCEventListenerCustom.h"
  33. #include "base/CCEventType.h"
  34. #include "base/CCDirector.h"
  35. #include "base/CCEventDispatcher.h"
  36. #include "2d/CCCamera.h"
  37. NS_CC_BEGIN
  38. // static vector with all the registered custom binding resolvers
  39. std::vector<GLProgramState::AutoBindingResolver*> GLProgramState::_customAutoBindingResolvers;
  40. //
  41. //
  42. // UniformValue
  43. //
  44. //
  45. UniformValue::UniformValue()
  46. : _uniform(nullptr)
  47. , _glprogram(nullptr)
  48. , _type(Type::VALUE)
  49. {
  50. }
  51. UniformValue::UniformValue(Uniform *uniform, GLProgram* glprogram)
  52. : _uniform(uniform)
  53. , _glprogram(glprogram)
  54. , _type(Type::VALUE)
  55. {
  56. }
  57. UniformValue::UniformValue(const UniformValue& o)
  58. {
  59. *this = o;
  60. }
  61. UniformValue::~UniformValue()
  62. {
  63. if (_type == Type::CALLBACK_FN)
  64. delete _value.callback;
  65. if (_uniform->type == GL_SAMPLER_2D)
  66. {
  67. CC_SAFE_RELEASE(_value.tex.texture);
  68. }
  69. }
  70. void UniformValue::apply()
  71. {
  72. if (_type == Type::CALLBACK_FN)
  73. {
  74. (*_value.callback)(_glprogram, _uniform);
  75. }
  76. else if (_type == Type::POINTER)
  77. {
  78. switch (_uniform->type) {
  79. case GL_FLOAT:
  80. _glprogram->setUniformLocationWith1fv(_uniform->location, _value.floatv.pointer, _value.floatv.size);
  81. break;
  82. case GL_FLOAT_VEC2:
  83. _glprogram->setUniformLocationWith2fv(_uniform->location, _value.v2f.pointer, _value.v2f.size);
  84. break;
  85. case GL_FLOAT_VEC3:
  86. _glprogram->setUniformLocationWith3fv(_uniform->location, _value.v3f.pointer, _value.v3f.size);
  87. break;
  88. case GL_FLOAT_VEC4:
  89. _glprogram->setUniformLocationWith4fv(_uniform->location, _value.v4f.pointer, _value.v4f.size);
  90. break;
  91. default:
  92. CCASSERT(false, "Unsupported type");
  93. break;
  94. }
  95. }
  96. else /* _type == VALUE */
  97. {
  98. switch (_uniform->type) {
  99. case GL_SAMPLER_2D:
  100. _glprogram->setUniformLocationWith1i(_uniform->location, _value.tex.textureUnit);
  101. GL::bindTexture2DN(_value.tex.textureUnit, _value.tex.textureId);
  102. break;
  103. case GL_SAMPLER_CUBE:
  104. _glprogram->setUniformLocationWith1i(_uniform->location, _value.tex.textureUnit);
  105. GL::bindTextureN(_value.tex.textureUnit, _value.tex.textureId, GL_TEXTURE_CUBE_MAP);
  106. break;
  107. case GL_INT:
  108. _glprogram->setUniformLocationWith1i(_uniform->location, _value.intValue);
  109. break;
  110. case GL_FLOAT:
  111. _glprogram->setUniformLocationWith1f(_uniform->location, _value.floatValue);
  112. break;
  113. case GL_FLOAT_VEC2:
  114. _glprogram->setUniformLocationWith2f(_uniform->location, _value.v2Value[0], _value.v2Value[1]);
  115. break;
  116. case GL_FLOAT_VEC3:
  117. _glprogram->setUniformLocationWith3f(_uniform->location, _value.v3Value[0], _value.v3Value[1], _value.v3Value[2]);
  118. break;
  119. case GL_FLOAT_VEC4:
  120. _glprogram->setUniformLocationWith4f(_uniform->location, _value.v4Value[0], _value.v4Value[1], _value.v4Value[2], _value.v4Value[3]);
  121. break;
  122. case GL_FLOAT_MAT4:
  123. _glprogram->setUniformLocationWithMatrix4fv(_uniform->location, (GLfloat*)&_value.matrixValue, 1);
  124. break;
  125. default:
  126. CCASSERT(false, "Invalid UniformValue");
  127. break;
  128. }
  129. }
  130. }
  131. void UniformValue::setCallback(const std::function<void(GLProgram*, Uniform*)> &callback)
  132. {
  133. // delete previously set callback
  134. // TODO: memory will leak if the user does:
  135. // value->setCallback();
  136. // value->setFloat();
  137. if (_type == Type::CALLBACK_FN)
  138. delete _value.callback;
  139. _value.callback = new (std::nothrow) std::function<void(GLProgram*, Uniform*)>();
  140. *_value.callback = callback;
  141. _type = Type::CALLBACK_FN;
  142. }
  143. void UniformValue::setTexture(GLuint textureId, GLuint textureUnit)
  144. {
  145. //CCASSERT(_uniform->type == GL_SAMPLER_2D, "Wrong type. expecting GL_SAMPLER_2D");
  146. _value.tex.textureId = textureId;
  147. _value.tex.textureUnit = textureUnit;
  148. _value.tex.texture = nullptr;
  149. _type = Type::VALUE;
  150. }
  151. void UniformValue::setTexture(Texture2D* texture, GLuint textureUnit)
  152. {
  153. CCASSERT(texture != nullptr, "texture is nullptr");
  154. if (texture != _value.tex.texture)
  155. {
  156. CC_SAFE_RELEASE(_value.tex.texture);
  157. CC_SAFE_RETAIN(texture);
  158. _value.tex.texture = texture;
  159. _value.tex.textureId = texture->getName();
  160. _value.tex.textureUnit = textureUnit;
  161. _type = Type::VALUE;
  162. }
  163. }
  164. void UniformValue::setInt(int value)
  165. {
  166. CCASSERT(_uniform->type == GL_INT, "Wrong type: expecting GL_INT");
  167. _value.intValue = value;
  168. _type = Type::VALUE;
  169. }
  170. void UniformValue::setFloat(float value)
  171. {
  172. CCASSERT(_uniform->type == GL_FLOAT, "Wrong type: expecting GL_FLOAT");
  173. _value.floatValue = value;
  174. _type = Type::VALUE;
  175. }
  176. void UniformValue::setFloatv(ssize_t size, const float* pointer)
  177. {
  178. CCASSERT(_uniform->type == GL_FLOAT, "Wrong type: expecting GL_FLOAT");
  179. _value.floatv.pointer = (const float*)pointer;
  180. _value.floatv.size = (GLsizei)size;
  181. _type = Type::POINTER;
  182. }
  183. void UniformValue::setVec2(const Vec2& value)
  184. {
  185. CCASSERT(_uniform->type == GL_FLOAT_VEC2, "Wrong type: expecting GL_FLOAT_VEC2");
  186. memcpy(_value.v2Value, &value, sizeof(_value.v2Value));
  187. _type = Type::VALUE;
  188. }
  189. void UniformValue::setVec2v(ssize_t size, const Vec2* pointer)
  190. {
  191. CCASSERT(_uniform->type == GL_FLOAT_VEC2, "Wrong type: expecting GL_FLOAT_VEC2");
  192. _value.v2f.pointer = (const float*)pointer;
  193. _value.v2f.size = (GLsizei)size;
  194. _type = Type::POINTER;
  195. }
  196. void UniformValue::setVec3(const Vec3& value)
  197. {
  198. CCASSERT(_uniform->type == GL_FLOAT_VEC3, "Wrong type: expecting GL_FLOAT_VEC3");
  199. memcpy(_value.v3Value, &value, sizeof(_value.v3Value));
  200. _type = Type::VALUE;
  201. }
  202. void UniformValue::setVec3v(ssize_t size, const Vec3* pointer)
  203. {
  204. CCASSERT(_uniform->type == GL_FLOAT_VEC3, "Wrong type: expecting GL_FLOAT_VEC3");
  205. _value.v3f.pointer = (const float*)pointer;
  206. _value.v3f.size = (GLsizei)size;
  207. _type = Type::POINTER;
  208. }
  209. void UniformValue::setVec4(const Vec4& value)
  210. {
  211. CCASSERT (_uniform->type == GL_FLOAT_VEC4, "Wrong type: expecting GL_FLOAT_VEC4");
  212. memcpy(_value.v4Value, &value, sizeof(_value.v4Value));
  213. _type = Type::VALUE;
  214. }
  215. void UniformValue::setVec4v(ssize_t size, const Vec4* pointer)
  216. {
  217. CCASSERT (_uniform->type == GL_FLOAT_VEC4, "Wrong type: expecting GL_FLOAT_VEC4");
  218. _value.v4f.pointer = (const float*)pointer;
  219. _value.v4f.size = (GLsizei)size;
  220. _type = Type::POINTER;
  221. }
  222. void UniformValue::setMat4(const Mat4& value)
  223. {
  224. CCASSERT(_uniform->type == GL_FLOAT_MAT4, "_uniform's type should be equal GL_FLOAT_MAT4.");
  225. memcpy(_value.matrixValue, &value, sizeof(_value.matrixValue));
  226. _type = Type::VALUE;
  227. }
  228. UniformValue& UniformValue::operator=(const UniformValue& o)
  229. {
  230. _uniform = o._uniform;
  231. _glprogram = o._glprogram;
  232. _type = o._type;
  233. _value = o._value;
  234. if (_uniform->type == GL_SAMPLER_2D)
  235. {
  236. CC_SAFE_RETAIN(_value.tex.texture);
  237. }
  238. return *this;
  239. }
  240. //
  241. //
  242. // VertexAttribValue
  243. //
  244. //
  245. VertexAttribValue::VertexAttribValue()
  246. : _vertexAttrib(nullptr)
  247. , _useCallback(false)
  248. , _enabled(false)
  249. {
  250. }
  251. VertexAttribValue::VertexAttribValue(VertexAttrib *vertexAttrib)
  252. : _vertexAttrib(vertexAttrib)
  253. , _useCallback(false)
  254. , _enabled(false)
  255. {
  256. }
  257. VertexAttribValue::~VertexAttribValue()
  258. {
  259. if (_useCallback)
  260. delete _value.callback;
  261. }
  262. void VertexAttribValue::apply()
  263. {
  264. if(_enabled) {
  265. if(_useCallback) {
  266. (*_value.callback)(_vertexAttrib);
  267. }
  268. else
  269. {
  270. glVertexAttribPointer(_vertexAttrib->index,
  271. _value.pointer.size,
  272. _value.pointer.type,
  273. _value.pointer.normalized,
  274. _value.pointer.stride,
  275. _value.pointer.pointer);
  276. }
  277. }
  278. }
  279. void VertexAttribValue::setCallback(const std::function<void(VertexAttrib*)> &callback)
  280. {
  281. _value.callback = new (std::nothrow) std::function<void(VertexAttrib*)>();
  282. *_value.callback = callback;
  283. _useCallback = true;
  284. _enabled = true;
  285. }
  286. void VertexAttribValue::setPointer(GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLvoid *pointer)
  287. {
  288. _value.pointer.size = size;
  289. _value.pointer.type = type;
  290. _value.pointer.normalized = normalized;
  291. _value.pointer.stride = stride;
  292. _value.pointer.pointer = pointer;
  293. _enabled = true;
  294. }
  295. //
  296. //
  297. // GLProgramState
  298. //
  299. //
  300. GLProgramState* GLProgramState::getOrCreateWithGLProgramName(const std::string& glProgramName, Texture2D* texture)
  301. {
  302. if (texture != nullptr && texture->getAlphaTextureName() != 0) {
  303. if (glProgramName == GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR) {
  304. return GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_ETC1AS_POSITION_TEXTURE_COLOR);
  305. }
  306. else if (glProgramName == GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP) {
  307. return GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_ETC1AS_POSITION_TEXTURE_COLOR_NO_MVP);
  308. }
  309. else if (glProgramName == GLProgram::SHADER_NAME_POSITION_GRAYSCALE) {
  310. return GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_ETC1AS_POSITION_TEXTURE_GRAY_NO_MVP);
  311. }
  312. }
  313. return GLProgramState::getOrCreateWithGLProgramName(glProgramName);
  314. }
  315. GLProgramState* GLProgramState::create(GLProgram *glprogram)
  316. {
  317. GLProgramState* ret = new (std::nothrow) GLProgramState();
  318. if(ret && ret->init(glprogram))
  319. {
  320. ret->autorelease();
  321. return ret;
  322. }
  323. CC_SAFE_DELETE(ret);
  324. return nullptr;
  325. }
  326. GLProgramState* GLProgramState::getOrCreateWithGLProgramName(const std::string& glProgramName )
  327. {
  328. GLProgram *glProgram = GLProgramCache::getInstance()->getGLProgram(glProgramName);
  329. if( glProgram )
  330. return getOrCreateWithGLProgram(glProgram);
  331. CCLOG("cocos2d: warning: GLProgram '%s' not found", glProgramName.c_str());
  332. return nullptr;
  333. }
  334. GLProgramState* GLProgramState::getOrCreateWithGLProgram(GLProgram *glprogram)
  335. {
  336. GLProgramState* ret = GLProgramStateCache::getInstance()->getGLProgramState(glprogram);
  337. return ret;
  338. }
  339. GLProgramState* GLProgramState::getOrCreateWithShaders(const std::string& vertexShader, const std::string& fragShader, const std::string& compileTimeDefines)
  340. {
  341. auto glprogramcache = GLProgramCache::getInstance();
  342. const std::string key = vertexShader + "+" + fragShader + "+" + compileTimeDefines;
  343. auto glprogram = glprogramcache->getGLProgram(key);
  344. if (!glprogram) {
  345. glprogram = GLProgram::createWithFilenames(vertexShader, fragShader, compileTimeDefines);
  346. glprogramcache->addGLProgram(glprogram, key);
  347. }
  348. return create(glprogram);
  349. }
  350. GLProgramState::GLProgramState()
  351. : _uniformAttributeValueDirty(true)
  352. , _textureUnitIndex(4) // first 4 textures unites are reserved for CC_Texture0-3
  353. , _vertexAttribsFlags(0)
  354. , _glprogram(nullptr)
  355. , _nodeBinding(nullptr)
  356. {
  357. #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
  358. /** listen the event that renderer was recreated on Android/WP8 */
  359. CCLOG("create rendererRecreatedListener for GLProgramState");
  360. _backToForegroundlistener = EventListenerCustom::create(EVENT_RENDERER_RECREATED,
  361. [this](EventCustom*)
  362. {
  363. CCLOG("Dirty Uniform and Attributes of GLProgramState");
  364. _uniformAttributeValueDirty = true;
  365. });
  366. Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(_backToForegroundlistener, -1);
  367. #endif
  368. }
  369. GLProgramState::~GLProgramState()
  370. {
  371. #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
  372. Director::getInstance()->getEventDispatcher()->removeEventListener(_backToForegroundlistener);
  373. #endif
  374. // _uniforms must be cleared before releasing _glprogram since
  375. // the destructor of UniformValue will call a weak pointer
  376. // which points to the member variable in GLProgram.
  377. _uniforms.clear();
  378. _attributes.clear();
  379. CC_SAFE_RELEASE(_glprogram);
  380. }
  381. GLProgramState* GLProgramState::clone() const
  382. {
  383. auto glprogramstate = new (std::nothrow) GLProgramState();
  384. // copy everything manually, instead of calling init since this is faster
  385. glprogramstate->_glprogram = this->_glprogram;
  386. CC_SAFE_RETAIN(glprogramstate->_glprogram);
  387. glprogramstate->_attributes = this->_attributes;
  388. glprogramstate->_vertexAttribsFlags = this->_vertexAttribsFlags;
  389. // copy uniforms
  390. glprogramstate->_uniformsByName = this->_uniformsByName;
  391. glprogramstate->_uniforms = this->_uniforms;
  392. glprogramstate->_uniformAttributeValueDirty = this->_uniformAttributeValueDirty;
  393. // copy textures
  394. glprogramstate->_textureUnitIndex = this->_textureUnitIndex;
  395. glprogramstate->_boundTextureUnits = this->_boundTextureUnits;
  396. // _nodeBinding is null since a node can only have one state.
  397. // making the null explicit to avoid possible bugs in the future
  398. glprogramstate->_nodeBinding = nullptr;
  399. // copy autobindings... rebound them once a target is set again
  400. glprogramstate->_autoBindings = _autoBindings;
  401. glprogramstate->autorelease();
  402. return glprogramstate;
  403. }
  404. bool GLProgramState::init(GLProgram* glprogram)
  405. {
  406. CCASSERT(glprogram, "invalid shader");
  407. _glprogram = glprogram;
  408. _glprogram->retain();
  409. for(auto &attrib : _glprogram->_vertexAttribs) {
  410. VertexAttribValue value(&attrib.second);
  411. _attributes[attrib.first] = value;
  412. }
  413. for(auto &uniform : _glprogram->_userUniforms) {
  414. UniformValue value(&uniform.second, _glprogram);
  415. _uniforms[uniform.second.location] = std::move(value);
  416. _uniformsByName[uniform.first] = uniform.second.location;
  417. }
  418. return true;
  419. }
  420. void GLProgramState::resetGLProgram()
  421. {
  422. // _uniforms must be cleared before releasing _glprogram since
  423. // the destructor of UniformValue will call a weak pointer
  424. // which points to the member variable in GLProgram.
  425. _uniforms.clear();
  426. _attributes.clear();
  427. CC_SAFE_RELEASE(_glprogram);
  428. _glprogram = nullptr;
  429. // first texture is GL_TEXTURE1
  430. _textureUnitIndex = 1;
  431. _nodeBinding = nullptr;
  432. }
  433. void GLProgramState::apply(const Mat4& modelView)
  434. {
  435. applyGLProgram(modelView);
  436. applyAttributes();
  437. applyUniforms();
  438. }
  439. void GLProgramState::updateUniformsAndAttributes()
  440. {
  441. CCASSERT(_glprogram, "invalid glprogram");
  442. if(_uniformAttributeValueDirty)
  443. {
  444. for(auto& uniformLocation : _uniformsByName)
  445. {
  446. _uniforms[uniformLocation.second]._uniform = _glprogram->getUniform(uniformLocation.first);
  447. }
  448. _vertexAttribsFlags = 0;
  449. for(auto& attributeValue : _attributes)
  450. {
  451. attributeValue.second._vertexAttrib = _glprogram->getVertexAttrib(attributeValue.first);
  452. if(attributeValue.second._enabled)
  453. _vertexAttribsFlags |= 1 << attributeValue.second._vertexAttrib->index;
  454. }
  455. _uniformAttributeValueDirty = false;
  456. }
  457. }
  458. void GLProgramState::applyGLProgram(const Mat4& modelView)
  459. {
  460. CCASSERT(_glprogram, "invalid glprogram");
  461. updateUniformsAndAttributes();
  462. // set shader
  463. _glprogram->use();
  464. _glprogram->setUniformsForBuiltins(modelView);
  465. }
  466. void GLProgramState::applyAttributes(bool applyAttribFlags)
  467. {
  468. // Don't set attributes if they weren't set
  469. // Use Case: Auto-batching
  470. updateUniformsAndAttributes();
  471. if(_vertexAttribsFlags) {
  472. // enable/disable vertex attribs
  473. if (applyAttribFlags)
  474. GL::enableVertexAttribs(_vertexAttribsFlags);
  475. // set attributes
  476. for(auto &attribute : _attributes)
  477. {
  478. attribute.second.apply();
  479. }
  480. }
  481. }
  482. void GLProgramState::applyUniforms()
  483. {
  484. // set uniforms
  485. updateUniformsAndAttributes();
  486. for(auto& uniform : _uniforms) {
  487. uniform.second.apply();
  488. }
  489. }
  490. void GLProgramState::setGLProgram(GLProgram *glprogram)
  491. {
  492. CCASSERT(glprogram, "invalid GLProgram");
  493. if( _glprogram != glprogram) {
  494. resetGLProgram();
  495. init(glprogram);
  496. }
  497. }
  498. uint32_t GLProgramState::getVertexAttribsFlags() const
  499. {
  500. return _vertexAttribsFlags;
  501. }
  502. ssize_t GLProgramState::getVertexAttribCount() const
  503. {
  504. return _attributes.size();
  505. }
  506. UniformValue* GLProgramState::getUniformValue(GLint uniformLocation)
  507. {
  508. updateUniformsAndAttributes();
  509. const auto itr = _uniforms.find(uniformLocation);
  510. if (itr != _uniforms.end())
  511. return &itr->second;
  512. return nullptr;
  513. }
  514. UniformValue* GLProgramState::getUniformValue(const std::string& name)
  515. {
  516. updateUniformsAndAttributes();
  517. const auto itr = _uniformsByName.find(name);
  518. if (itr != _uniformsByName.end())
  519. return &_uniforms[itr->second];
  520. return nullptr;
  521. }
  522. VertexAttribValue* GLProgramState::getVertexAttribValue(const std::string& name)
  523. {
  524. updateUniformsAndAttributes();
  525. const auto itr = _attributes.find(name);
  526. if( itr != _attributes.end())
  527. return &itr->second;
  528. return nullptr;
  529. }
  530. // VertexAttrib Setters
  531. void GLProgramState::setVertexAttribCallback(const std::string& name, const std::function<void(VertexAttrib*)> &callback)
  532. {
  533. VertexAttribValue *v = getVertexAttribValue(name);
  534. if(v) {
  535. v->setCallback(callback);
  536. _vertexAttribsFlags |= 1 << v->_vertexAttrib->index;
  537. }
  538. else
  539. {
  540. CCLOG("cocos2d: warning: Attribute not found: %s", name.c_str());
  541. }
  542. }
  543. void GLProgramState::setVertexAttribPointer(const std::string& name, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLvoid *pointer)
  544. {
  545. auto v = getVertexAttribValue(name);
  546. if(v) {
  547. v->setPointer(size, type, normalized, stride, pointer);
  548. _vertexAttribsFlags |= 1 << v->_vertexAttrib->index;
  549. }
  550. else
  551. {
  552. CCLOG("cocos2d: warning: Attribute not found: %s", name.c_str());
  553. }
  554. }
  555. // Uniform Setters
  556. void GLProgramState::setUniformCallback(const std::string& uniformName, const std::function<void(GLProgram*, Uniform*)> &callback)
  557. {
  558. auto v = getUniformValue(uniformName);
  559. if (v)
  560. v->setCallback(callback);
  561. else
  562. CCLOG("cocos2d: warning: Uniform not found: %s", uniformName.c_str());
  563. }
  564. void GLProgramState::setUniformCallback(GLint uniformLocation, const std::function<void(GLProgram*, Uniform*)> &callback)
  565. {
  566. auto v = getUniformValue(uniformLocation);
  567. if (v)
  568. v->setCallback(callback);
  569. else
  570. CCLOG("cocos2d: warning: Uniform at location not found: %i", uniformLocation);
  571. }
  572. void GLProgramState::setUniformFloat(const std::string& uniformName, float value)
  573. {
  574. auto v = getUniformValue(uniformName);
  575. if (v)
  576. v->setFloat(value);
  577. else
  578. CCLOG("cocos2d: warning: Uniform not found: %s", uniformName.c_str());
  579. }
  580. void GLProgramState::setUniformFloat(GLint uniformLocation, float value)
  581. {
  582. auto v = getUniformValue(uniformLocation);
  583. if (v)
  584. v->setFloat(value);
  585. else
  586. CCLOG("cocos2d: warning: Uniform at location not found: %i", uniformLocation);
  587. }
  588. void GLProgramState::setUniformInt(const std::string& uniformName, int value)
  589. {
  590. auto v = getUniformValue(uniformName);
  591. if(v)
  592. v->setInt(value);
  593. else
  594. CCLOG("cocos2d: warning: Uniform not found: %s", uniformName.c_str());
  595. }
  596. void GLProgramState::setUniformInt(GLint uniformLocation, int value)
  597. {
  598. auto v = getUniformValue(uniformLocation);
  599. if (v)
  600. v->setInt(value);
  601. else
  602. CCLOG("cocos2d: warning: Uniform at location not found: %i", uniformLocation);
  603. }
  604. void GLProgramState::setUniformFloatv(const std::string& uniformName, ssize_t size, const float* pointer)
  605. {
  606. auto v = getUniformValue(uniformName);
  607. if (v)
  608. v->setFloatv(size, pointer);
  609. else
  610. CCLOG("cocos2d: warning: Uniform not found: %s", uniformName.c_str());
  611. }
  612. void GLProgramState::setUniformFloatv(GLint uniformLocation, ssize_t size, const float* pointer)
  613. {
  614. auto v = getUniformValue(uniformLocation);
  615. if (v)
  616. v->setFloatv(size, pointer);
  617. else
  618. CCLOG("cocos2d: warning: Uniform at location not found: %i", uniformLocation);
  619. }
  620. void GLProgramState::setUniformVec2(const std::string& uniformName, const Vec2& value)
  621. {
  622. auto v = getUniformValue(uniformName);
  623. if (v)
  624. v->setVec2(value);
  625. else
  626. CCLOG("cocos2d: warning: Uniform not found: %s", uniformName.c_str());
  627. }
  628. void GLProgramState::setUniformVec2(GLint uniformLocation, const Vec2& value)
  629. {
  630. auto v = getUniformValue(uniformLocation);
  631. if (v)
  632. v->setVec2(value);
  633. else
  634. CCLOG("cocos2d: warning: Uniform at location not found: %i", uniformLocation);
  635. }
  636. void GLProgramState::setUniformVec2v(const std::string& uniformName, ssize_t size, const Vec2* pointer)
  637. {
  638. auto v = getUniformValue(uniformName);
  639. if (v)
  640. v->setVec2v(size, pointer);
  641. else
  642. CCLOG("cocos2d: warning: Uniform not found: %s", uniformName.c_str());
  643. }
  644. void GLProgramState::setUniformVec2v(GLint uniformLocation, ssize_t size, const Vec2* pointer)
  645. {
  646. auto v = getUniformValue(uniformLocation);
  647. if (v)
  648. v->setVec2v(size, pointer);
  649. else
  650. CCLOG("cocos2d: warning: Uniform at location not found: %i", uniformLocation);
  651. }
  652. void GLProgramState::setUniformVec3(const std::string& uniformName, const Vec3& value)
  653. {
  654. auto v = getUniformValue(uniformName);
  655. if (v)
  656. v->setVec3(value);
  657. else
  658. CCLOG("cocos2d: warning: Uniform not found: %s", uniformName.c_str());
  659. }
  660. void GLProgramState::setUniformVec3(GLint uniformLocation, const Vec3& value)
  661. {
  662. auto v = getUniformValue(uniformLocation);
  663. if (v)
  664. v->setVec3(value);
  665. else
  666. CCLOG("cocos2d: warning: Uniform at location not found: %i", uniformLocation);
  667. }
  668. void GLProgramState::setUniformVec3v(const std::string& uniformName, ssize_t size, const Vec3* pointer)
  669. {
  670. auto v = getUniformValue(uniformName);
  671. if (v)
  672. v->setVec3v(size, pointer);
  673. else
  674. CCLOG("cocos2d: warning: Uniform not found: %s", uniformName.c_str());
  675. }
  676. void GLProgramState::setUniformVec3v(GLint uniformLocation, ssize_t size, const Vec3* pointer)
  677. {
  678. auto v = getUniformValue(uniformLocation);
  679. if (v)
  680. v->setVec3v(size, pointer);
  681. else
  682. CCLOG("cocos2d: warning: Uniform at location not found: %i", uniformLocation);
  683. }
  684. void GLProgramState::setUniformVec4(const std::string& uniformName, const Vec4& value)
  685. {
  686. auto v = getUniformValue(uniformName);
  687. if (v)
  688. v->setVec4(value);
  689. else
  690. CCLOG("cocos2d: warning: Uniform not found: %s", uniformName.c_str());
  691. }
  692. void GLProgramState::setUniformVec4(GLint uniformLocation, const Vec4& value)
  693. {
  694. auto v = getUniformValue(uniformLocation);
  695. if (v)
  696. v->setVec4(value);
  697. else
  698. CCLOG("cocos2d: warning: Uniform at location not found: %i", uniformLocation);
  699. }
  700. void GLProgramState::setUniformVec4v(const std::string& uniformName, ssize_t size, const Vec4* value)
  701. {
  702. auto v = getUniformValue(uniformName);
  703. if (v)
  704. v->setVec4v(size, value);
  705. else
  706. CCLOG("cocos2d: warning: Uniform not found: %s", uniformName.c_str());
  707. }
  708. void GLProgramState::setUniformVec4v(GLint uniformLocation, ssize_t size, const Vec4* pointer)
  709. {
  710. auto v = getUniformValue(uniformLocation);
  711. if (v)
  712. v->setVec4v(size, pointer);
  713. else
  714. CCLOG("cocos2d: warning: Uniform at location not found: %i", uniformLocation);
  715. }
  716. void GLProgramState::setUniformMat4(const std::string& uniformName, const Mat4& value)
  717. {
  718. auto v = getUniformValue(uniformName);
  719. if (v)
  720. v->setMat4(value);
  721. else
  722. CCLOG("cocos2d: warning: Uniform not found: %s", uniformName.c_str());
  723. }
  724. void GLProgramState::setUniformMat4(GLint uniformLocation, const Mat4& value)
  725. {
  726. auto v = getUniformValue(uniformLocation);
  727. if (v)
  728. v->setMat4(value);
  729. else
  730. CCLOG("cocos2d: warning: Uniform at location not found: %i", uniformLocation);
  731. }
  732. // Textures
  733. void GLProgramState::setUniformTexture(const std::string& uniformName, Texture2D *texture)
  734. {
  735. CCASSERT(texture, "Invalid texture");
  736. auto v = getUniformValue(uniformName);
  737. if (v)
  738. {
  739. if (_boundTextureUnits.find(uniformName) != _boundTextureUnits.end())
  740. {
  741. v->setTexture(texture, _boundTextureUnits[uniformName]);
  742. }
  743. else
  744. {
  745. v->setTexture(texture, _textureUnitIndex);
  746. _boundTextureUnits[uniformName] = _textureUnitIndex++;
  747. }
  748. }
  749. else
  750. {
  751. CCLOG("cocos2d: warning: Uniform not found: %s", uniformName.c_str());
  752. }
  753. }
  754. void GLProgramState::setUniformTexture(GLint uniformLocation, Texture2D *texture)
  755. {
  756. CCASSERT(texture, "Invalid texture");
  757. auto v = getUniformValue(uniformLocation);
  758. if (v)
  759. {
  760. if (_boundTextureUnits.find(v->_uniform->name) != _boundTextureUnits.end())
  761. {
  762. v->setTexture(texture, _boundTextureUnits[v->_uniform->name]);
  763. }
  764. else
  765. {
  766. v->setTexture(texture, _textureUnitIndex);
  767. _boundTextureUnits[v->_uniform->name] = _textureUnitIndex++;
  768. }
  769. }
  770. else
  771. {
  772. CCLOG("cocos2d: warning: Uniform at location not found: %i", uniformLocation);
  773. }
  774. }
  775. void GLProgramState::setUniformTexture(const std::string& uniformName, GLuint textureId)
  776. {
  777. auto v = getUniformValue(uniformName);
  778. if (v)
  779. {
  780. if (_boundTextureUnits.find(uniformName) != _boundTextureUnits.end())
  781. {
  782. v->setTexture(textureId, _boundTextureUnits[uniformName]);
  783. }
  784. else
  785. {
  786. v->setTexture(textureId, _textureUnitIndex);
  787. _boundTextureUnits[uniformName] = _textureUnitIndex++;
  788. }
  789. }
  790. else
  791. {
  792. CCLOG("cocos2d: warning: Uniform not found: %s", uniformName.c_str());
  793. }
  794. }
  795. void GLProgramState::setUniformTexture(GLint uniformLocation, GLuint textureId)
  796. {
  797. auto v = getUniformValue(uniformLocation);
  798. if (v)
  799. {
  800. if (_boundTextureUnits.find(v->_uniform->name) != _boundTextureUnits.end())
  801. {
  802. v->setTexture(textureId, _boundTextureUnits[v->_uniform->name]);
  803. }
  804. else
  805. {
  806. v->setTexture(textureId, _textureUnitIndex);
  807. _boundTextureUnits[v->_uniform->name] = _textureUnitIndex++;
  808. }
  809. }
  810. else
  811. {
  812. CCLOG("cocos2d: warning: Uniform at location not found: %i", uniformLocation);
  813. }
  814. }
  815. // Auto bindings
  816. void GLProgramState::setParameterAutoBinding(const std::string& uniformName, const std::string& autoBinding)
  817. {
  818. _autoBindings[uniformName] = autoBinding;
  819. if (_nodeBinding)
  820. applyAutoBinding(uniformName, autoBinding);
  821. }
  822. void GLProgramState::applyAutoBinding(const std::string& uniformName, const std::string& autoBinding)
  823. {
  824. // This code tries to replace GLProgram::setUniformsForBuiltins. But it is unfinished ATM.
  825. // The idea is that users will be able to use variables from cocos2d-x without hardcoding the
  826. // information on GLProgram and other objects.
  827. // Instead, the Cocos2d uniform variables will be callbacks.
  828. // As an example of how bad the current design is, the ModelView matrix is being passed from Node, to the Commands, to the GLProgram.
  829. // Instead, the GLProgramState should obtain it from its target.
  830. bool resolved = false;
  831. for (const auto resolver: _customAutoBindingResolvers)
  832. {
  833. resolved = resolver->resolveAutoBinding(this, _nodeBinding, uniformName, autoBinding);
  834. if (resolved)
  835. break;
  836. }
  837. if (!resolved)
  838. {
  839. // add cocos2d-x variables here like:
  840. // PROJECT_MATRIX
  841. // MODEL_MATRIX
  842. // MODEL_VIEW
  843. // MODEL_VIEW_PROJECTION
  844. // etc...
  845. //
  846. // and remove them from GLProgram::setUniformsForBuiltins
  847. }
  848. }
  849. void GLProgramState::setNodeBinding(Node* target)
  850. {
  851. CCASSERT(target, "must be non-null");
  852. // weak ref
  853. _nodeBinding = target;
  854. for (const auto autobinding: _autoBindings)
  855. applyAutoBinding(autobinding.first, autobinding.second);
  856. }
  857. Node* GLProgramState::getNodeBinding() const
  858. {
  859. return _nodeBinding;
  860. }
  861. //
  862. // MARK: AutoBindingResolver
  863. //
  864. GLProgramState::AutoBindingResolver::AutoBindingResolver()
  865. {
  866. _customAutoBindingResolvers.push_back(this);
  867. }
  868. GLProgramState::AutoBindingResolver::~AutoBindingResolver()
  869. {
  870. std::vector<GLProgramState::AutoBindingResolver*>::iterator itr = std::find(_customAutoBindingResolvers.begin(), _customAutoBindingResolvers.end(), this);
  871. if (itr != _customAutoBindingResolvers.end())
  872. _customAutoBindingResolvers.erase(itr);
  873. }
  874. NS_CC_END