PageRenderTime 27ms CodeModel.GetById 36ms RepoModel.GetById 1ms app.codeStats 0ms

/OpenGLAPI/src/gfx/GLProgram.cpp

https://github.com/victorkendy/PandoraBox
C++ | 257 lines | 228 code | 28 blank | 1 comment | 38 complexity | a91cc9740f538d0630bfc7c2e8cf0b92 MD5 | raw file
  1. #include <string>
  2. #include <vector>
  3. #include <functional>
  4. #include <algorithm>
  5. #include <set>
  6. #include "pbge/gfx/GraphicAPI.h"
  7. #include "pbge/gfx/Texture.h"
  8. #include "pbge/gfx/states/TextureUnits.h"
  9. #include "OpenGLAPI/gfx/GLShader.h"
  10. #include "OpenGLAPI/gfx/GLProgram.h"
  11. #include "OpenGLAPI/gfx/AttrBinders.h"
  12. #include "OpenGLAPI/gfx/BuiltInUniformBinders.h"
  13. namespace {
  14. pbge::UniformType translateGLType(GLenum type) {
  15. switch(type) {
  16. case GL_FLOAT: return pbge::FLOAT; break;
  17. case GL_FLOAT_VEC2: return pbge::FLOAT_VEC2; break;
  18. case GL_FLOAT_VEC3: return pbge::FLOAT_VEC3; break;
  19. case GL_FLOAT_VEC4: return pbge::FLOAT_VEC4; break;
  20. case GL_INT: return pbge::INT; break;
  21. case GL_INT_VEC2: return pbge::INT_VEC2; break;
  22. case GL_INT_VEC3: return pbge::INT_VEC3; break;
  23. case GL_INT_VEC4: return pbge::INT_VEC4; break;
  24. case GL_BOOL: return pbge::BOOL; break;
  25. case GL_BOOL_VEC2: return pbge::BOOL_VEC2; break;
  26. case GL_BOOL_VEC3: return pbge::BOOL_VEC3; break;
  27. case GL_BOOL_VEC4: return pbge::BOOL_VEC4; break;
  28. case GL_FLOAT_MAT2: return pbge::FLOAT_MAT2; break;
  29. case GL_FLOAT_MAT3: return pbge::FLOAT_MAT3; break;
  30. case GL_FLOAT_MAT4: return pbge::FLOAT_MAT4; break;
  31. case GL_FLOAT_MAT2x3: return pbge::FLOAT_MAT23; break;
  32. case GL_FLOAT_MAT2x4: return pbge::FLOAT_MAT24; break;
  33. case GL_SAMPLER_BUFFER: return pbge::BUFFER_SAMPLER; break;
  34. case GL_SAMPLER_1D: return pbge::SAMPLER_1D; break;
  35. case GL_SAMPLER_2D: return pbge::SAMPLER_2D; break;
  36. case GL_SAMPLER_3D: return pbge::SAMPLER_3D; break;
  37. case GL_SAMPLER_CUBE: return pbge::SAMPLER_CUBE; break;
  38. case GL_SAMPLER_1D_SHADOW: return pbge::SAMPLER_1D_SHADOW; break;
  39. case GL_SAMPLER_2D_SHADOW: return pbge::SAMPLER_2D_SHADOW; break;
  40. default: return pbge::INVALID; break;
  41. }
  42. }
  43. }
  44. using namespace pbge;
  45. void GLProgram::bind(GraphicAPI * gfx){
  46. if(!linked) {
  47. link(gfx);
  48. if(!linked)
  49. throw 1;
  50. }
  51. glUseProgram(programID);
  52. updateUniforms(gfx);
  53. }
  54. void GLProgram::unbind(GraphicAPI * ogl){
  55. std::for_each(attrBinders.begin(),
  56. attrBinders.end(),
  57. std::mem_fun(&AttrBinder::unbind));
  58. currentVertexBuffer = NULL;
  59. std::for_each(uniforms.begin(), uniforms.end(), std::mem_fun_ref(&UniformBindAndInfo::reset));
  60. glUseProgram(0);
  61. }
  62. void GLProgram::updateUniforms(GraphicAPI * gfx) {
  63. std::vector<UniformBindAndInfo>::iterator it;
  64. for(it = uniforms.begin(); it != uniforms.end(); it++) {
  65. UniformValue * value = gfx->searchUniform(it->getInfo());
  66. if(it->shouldUpdate(value)) {
  67. it->update(value);
  68. value->bindValueOn(this, it->getInfo(), gfx);
  69. }
  70. }
  71. std::for_each(builtInUniforms.begin(),
  72. builtInUniforms.end(),
  73. std::bind2nd(std::mem_fun(&BuiltInUniformBinder::bind), gfx));
  74. }
  75. void GLProgram::setAttributes(VertexBuffer * attr) {
  76. if(attr != currentVertexBuffer) {
  77. currentVertexBuffer = attr;
  78. std::for_each(attrBinders.begin(),
  79. attrBinders.end(),
  80. std::bind2nd(std::mem_fun(&AttrBinder::bind), attr));
  81. }
  82. }
  83. bool GLProgram::link(GraphicAPI * gfx){
  84. GLint status;
  85. std::vector<GLShader*>::iterator it;
  86. if(programID == 0) programID = glCreateProgram();
  87. for(it = attachedShaders.begin(); it != attachedShaders.end(); it++) {
  88. if(!(*it)->compile(gfx)) {
  89. std::cout << this->getInfoLog();
  90. return false;
  91. }
  92. glAttachShader(programID, (*it)->getID());
  93. }
  94. glLinkProgram(programID);
  95. extractInfoLog();
  96. glGetProgramiv(programID, GL_LINK_STATUS, &status);
  97. linked = (status == GL_TRUE);
  98. if(linked) {
  99. glUseProgram(programID);
  100. extractUniformInformation(gfx);
  101. extractAttribs();
  102. }
  103. return linked;
  104. }
  105. int GLProgram::getOutputLocation(const std::string & name) {
  106. if(name == "color") return 0;
  107. std::map<std::string, int>::iterator it = outputLocations.find(name);
  108. if(it == outputLocations.end()) {
  109. // TODO: verify gl version before using the getfragdatalocation
  110. int location = glGetFragDataLocation(programID, name.c_str());
  111. outputLocations[name] = location;
  112. return location;
  113. } else {
  114. return it->second;
  115. }
  116. }
  117. void GLProgram::extractInfoLog() {
  118. GLint infoLogLength;
  119. GLsizei lixo;
  120. GLchar * _infoLog;
  121. glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &infoLogLength);
  122. _infoLog = new GLchar[infoLogLength];
  123. glGetProgramInfoLog(programID, infoLogLength, &lixo, _infoLog);
  124. this->infoLog = std::string(_infoLog, infoLogLength);
  125. delete [] _infoLog;
  126. }
  127. void GLProgram::extractUniformInformation(GraphicAPI * ogl) {
  128. GLint numberOfActiveUniforms;
  129. GLint maxUniformNameSize;
  130. GLint uniformSize;
  131. GLenum uniformType;
  132. GLchar * name;
  133. glGetProgramiv(programID, GL_ACTIVE_UNIFORMS, &numberOfActiveUniforms);
  134. glGetProgramiv(programID, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniformNameSize);
  135. name = new GLchar [maxUniformNameSize];
  136. for(int uniformIndex = 0; uniformIndex < numberOfActiveUniforms; ++uniformIndex) {
  137. glGetActiveUniform(programID, uniformIndex, maxUniformNameSize, NULL, &uniformSize, &uniformType, name);
  138. std::string uniformName = name;
  139. GLint location = glGetUniformLocation(programID, name);
  140. if(location == -1 || uniformName.find("pbge_") == 0) {
  141. BuiltInUniformBinder * binder = BuiltInUniformBinders::binderFor(uniformName, location);
  142. if(binder != NULL) {
  143. builtInUniforms.push_back(binder);
  144. }
  145. } else {
  146. UniformInfo info = UniformInfo(uniformName, translateGLType(uniformType), location, uniformSize);
  147. uniforms.push_back(info);
  148. std::cout << "found uniform: " << info.toString() << std::endl;
  149. }
  150. }
  151. delete [] name;
  152. }
  153. void GLProgram::extractAttribs() {
  154. GLint numberOfAttrs;
  155. GLint maxAttrNameSize;
  156. GLint attrSize;
  157. GLenum attrType;
  158. GLchar * name;
  159. glGetProgramiv(programID, GL_ACTIVE_ATTRIBUTES, &numberOfAttrs);
  160. glGetProgramiv(programID, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxAttrNameSize);
  161. name = new GLchar[maxAttrNameSize];
  162. for(int index = 0; index < numberOfAttrs; index++) {
  163. glGetActiveAttrib(programID, index, maxAttrNameSize, NULL, &attrSize, &attrType, name);
  164. AttrBinder * binder = AttrBinders::binderFor(name, glGetAttribLocation(programID, name));
  165. if(binder != NULL) { // some attributes are implementation dependent and aren't meant to be used by the api
  166. attrBinders.push_back(binder);
  167. }
  168. }
  169. delete [] name;
  170. }
  171. void GLProgram::attachShader(GLShader *shader){
  172. attachedShaders.push_back(shader);
  173. }
  174. GLProgram * GLProgram::fromString(const std::string &vertexShader, const std::string &fragmentShader){
  175. GLShader * vs, * fs;
  176. GLProgram * program = new GLProgram;
  177. if(vertexShader != ""){
  178. vs = GLShader::loadSource(vertexShader, Shader::VERTEX_SHADER);
  179. program->attachShader(vs);
  180. }
  181. if(fragmentShader != ""){
  182. fs = GLShader::loadSource(fragmentShader, Shader::FRAGMENT_SHADER);
  183. program->attachShader(fs);
  184. }
  185. return program;
  186. }
  187. GLProgram * GLProgram::fromFile(FileReader * filevs, FileReader * filefs){
  188. GLProgram * program = new GLProgram;
  189. GLShader *vs, *fs;
  190. if(filevs != NULL){
  191. vs = GLShader::loadSourceFromFile(filevs, Shader::VERTEX_SHADER);
  192. program->attachShader(vs);
  193. }
  194. if(filefs != NULL){
  195. fs = GLShader::loadSourceFromFile(filefs, Shader::FRAGMENT_SHADER);
  196. program->attachShader(fs);
  197. }
  198. return program;
  199. }
  200. void GLProgram::bindFloat(const UniformInfo & info, GraphicAPI * ogl, const float * values, const unsigned size) {
  201. glUniform1fv(info.getLocation(), size, values);
  202. }
  203. void GLProgram::bindFloatVec2(const UniformInfo & info, GraphicAPI * ogl, const float * values, const unsigned size) {
  204. glUniform2fv(info.getLocation(), size, values);
  205. }
  206. void GLProgram::bindFloatVec3(const UniformInfo & info, GraphicAPI * ogl, const float * values, const unsigned size) {
  207. glUniform3fv(info.getLocation(), size, values);
  208. }
  209. void GLProgram::bindFloatVec4(const UniformInfo & info, GraphicAPI * ogl, const float * values, const unsigned size) {
  210. glUniform4fv(info.getLocation(), size, values);
  211. }
  212. void GLProgram::bindSampler(const UniformInfo & info, GraphicAPI * ogl, Texture * tex) {
  213. TextureUnit * unit = ogl->chooseTextureUnit(tex);
  214. unit->setTexture(tex);
  215. unit->makeChange(ogl);
  216. glUniform1i(info.getLocation(), unit->getIndex());
  217. }
  218. void GLProgram::bindBufferSampler(const UniformInfo & info, GraphicAPI * ogl, TextureBuffer * tex) {
  219. bindSampler(info, ogl, tex);
  220. }
  221. void GLProgram::bindSampler1D(const UniformInfo & info, GraphicAPI * ogl, Texture1D * tex) {
  222. bindSampler(info, ogl, tex);
  223. }
  224. void GLProgram::bindSampler2D(const UniformInfo & info, GraphicAPI * ogl, Texture2D * tex) {
  225. bindSampler(info, ogl, tex);
  226. }
  227. void GLProgram::bindMat4(const UniformInfo & info, GraphicAPI * ogl, const float * v) {
  228. glUniformMatrix4fv(info.getLocation(), 1, GL_FALSE, v);
  229. }