ShaderProg.cpp 13 KB

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