RenderProgs_GLSL.cpp 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #pragma hdrstop
  21. #include "../idlib/precompiled.h"
  22. #include "tr_local.h"
  23. idCVar r_skipStripDeadCode( "r_skipStripDeadCode", "0", CVAR_BOOL, "Skip stripping dead code" );
  24. idCVar r_useUniformArrays( "r_useUniformArrays", "1", CVAR_BOOL, "" );
  25. #define VERTEX_UNIFORM_ARRAY_NAME "_va_"
  26. #define FRAGMENT_UNIFORM_ARRAY_NAME "_fa_"
  27. static const int AT_VS_IN = BIT( 1 );
  28. static const int AT_VS_OUT = BIT( 2 );
  29. static const int AT_PS_IN = BIT( 3 );
  30. static const int AT_PS_OUT = BIT( 4 );
  31. struct idCGBlock {
  32. idStr prefix; // tokens that comes before the name
  33. idStr name; // the name
  34. idStr postfix; // tokens that comes after the name
  35. bool used; // whether or not this block is referenced anywhere
  36. };
  37. /*
  38. ================================================
  39. attribInfo_t
  40. ================================================
  41. */
  42. struct attribInfo_t {
  43. const char * type;
  44. const char * name;
  45. const char * semantic;
  46. const char * glsl;
  47. int bind;
  48. int flags;
  49. int vertexMask;
  50. };
  51. /*
  52. ================================================
  53. vertexMask_t
  54. NOTE: There is a PS3 dependency between the bit flag specified here and the vertex
  55. attribute index and attribute semantic specified in DeclRenderProg.cpp because the
  56. stored render prog vertexMask is initialized with cellCgbGetVertexConfiguration().
  57. The ATTRIB_INDEX_ defines are used to make sure the vertexMask_t and attrib assignment
  58. in DeclRenderProg.cpp are in sync.
  59. Even though VERTEX_MASK_XYZ_SHORT and VERTEX_MASK_ST_SHORT are not real attributes,
  60. they come before the VERTEX_MASK_MORPH to reduce the range of vertex program
  61. permutations defined by the vertexMask_t bits on the Xbox 360 (see MAX_VERTEX_DECLARATIONS).
  62. ================================================
  63. */
  64. enum vertexMask_t {
  65. VERTEX_MASK_XYZ = BIT( PC_ATTRIB_INDEX_VERTEX ),
  66. VERTEX_MASK_ST = BIT( PC_ATTRIB_INDEX_ST ),
  67. VERTEX_MASK_NORMAL = BIT( PC_ATTRIB_INDEX_NORMAL ),
  68. VERTEX_MASK_COLOR = BIT( PC_ATTRIB_INDEX_COLOR ),
  69. VERTEX_MASK_TANGENT = BIT( PC_ATTRIB_INDEX_TANGENT ),
  70. VERTEX_MASK_COLOR2 = BIT( PC_ATTRIB_INDEX_COLOR2 ),
  71. };
  72. attribInfo_t attribsPC[] = {
  73. // vertex attributes
  74. { "float4", "position", "POSITION", "in_Position", PC_ATTRIB_INDEX_VERTEX, AT_VS_IN, VERTEX_MASK_XYZ },
  75. { "float2", "texcoord", "TEXCOORD0", "in_TexCoord", PC_ATTRIB_INDEX_ST, AT_VS_IN, VERTEX_MASK_ST },
  76. { "float4", "normal", "NORMAL", "in_Normal", PC_ATTRIB_INDEX_NORMAL, AT_VS_IN, VERTEX_MASK_NORMAL },
  77. { "float4", "tangent", "TANGENT", "in_Tangent", PC_ATTRIB_INDEX_TANGENT, AT_VS_IN, VERTEX_MASK_TANGENT },
  78. { "float4", "color", "COLOR0", "in_Color", PC_ATTRIB_INDEX_COLOR, AT_VS_IN, VERTEX_MASK_COLOR },
  79. { "float4", "color2", "COLOR1", "in_Color2", PC_ATTRIB_INDEX_COLOR2, AT_VS_IN, VERTEX_MASK_COLOR2 },
  80. // pre-defined vertex program output
  81. { "float4", "position", "POSITION", "gl_Position", 0, AT_VS_OUT, 0 },
  82. { "float", "clip0", "CLP0", "gl_ClipDistance[0]", 0, AT_VS_OUT, 0 },
  83. { "float", "clip1", "CLP1", "gl_ClipDistance[1]", 0, AT_VS_OUT, 0 },
  84. { "float", "clip2", "CLP2", "gl_ClipDistance[2]", 0, AT_VS_OUT, 0 },
  85. { "float", "clip3", "CLP3", "gl_ClipDistance[3]", 0, AT_VS_OUT, 0 },
  86. { "float", "clip4", "CLP4", "gl_ClipDistance[4]", 0, AT_VS_OUT, 0 },
  87. { "float", "clip5", "CLP5", "gl_ClipDistance[5]", 0, AT_VS_OUT, 0 },
  88. // pre-defined fragment program input
  89. { "float4", "position", "WPOS", "gl_FragCoord", 0, AT_PS_IN, 0 },
  90. { "half4", "hposition", "WPOS", "gl_FragCoord", 0, AT_PS_IN, 0 },
  91. { "float", "facing", "FACE", "gl_FrontFacing", 0, AT_PS_IN, 0 },
  92. // fragment program output
  93. { "float4", "color", "COLOR", "gl_FragColor", 0, AT_PS_OUT, 0 }, // GLSL version 1.2 doesn't allow for custom color name mappings
  94. { "half4", "hcolor", "COLOR", "gl_FragColor", 0, AT_PS_OUT, 0 },
  95. { "float4", "color0", "COLOR0", "gl_FragColor", 0, AT_PS_OUT, 0 },
  96. { "float4", "color1", "COLOR1", "gl_FragColor", 1, AT_PS_OUT, 0 },
  97. { "float4", "color2", "COLOR2", "gl_FragColor", 2, AT_PS_OUT, 0 },
  98. { "float4", "color3", "COLOR3", "gl_FragColor", 3, AT_PS_OUT, 0 },
  99. { "float", "depth", "DEPTH", "gl_FragDepth", 4, AT_PS_OUT, 0 },
  100. // vertex to fragment program pass through
  101. { "float4", "color", "COLOR", "gl_FrontColor", 0, AT_VS_OUT, 0 },
  102. { "float4", "color0", "COLOR0", "gl_FrontColor", 0, AT_VS_OUT, 0 },
  103. { "float4", "color1", "COLOR1", "gl_FrontSecondaryColor", 0, AT_VS_OUT, 0 },
  104. { "float4", "color", "COLOR", "gl_Color", 0, AT_PS_IN, 0 },
  105. { "float4", "color0", "COLOR0", "gl_Color", 0, AT_PS_IN, 0 },
  106. { "float4", "color1", "COLOR1", "gl_SecondaryColor", 0, AT_PS_IN, 0 },
  107. { "half4", "hcolor", "COLOR", "gl_Color", 0, AT_PS_IN, 0 },
  108. { "half4", "hcolor0", "COLOR0", "gl_Color", 0, AT_PS_IN, 0 },
  109. { "half4", "hcolor1", "COLOR1", "gl_SecondaryColor", 0, AT_PS_IN, 0 },
  110. { "float4", "texcoord0", "TEXCOORD0_centroid", "vofi_TexCoord0", 0, AT_PS_IN, 0 },
  111. { "float4", "texcoord1", "TEXCOORD1_centroid", "vofi_TexCoord1", 0, AT_PS_IN, 0 },
  112. { "float4", "texcoord2", "TEXCOORD2_centroid", "vofi_TexCoord2", 0, AT_PS_IN, 0 },
  113. { "float4", "texcoord3", "TEXCOORD3_centroid", "vofi_TexCoord3", 0, AT_PS_IN, 0 },
  114. { "float4", "texcoord4", "TEXCOORD4_centroid", "vofi_TexCoord4", 0, AT_PS_IN, 0 },
  115. { "float4", "texcoord5", "TEXCOORD5_centroid", "vofi_TexCoord5", 0, AT_PS_IN, 0 },
  116. { "float4", "texcoord6", "TEXCOORD6_centroid", "vofi_TexCoord6", 0, AT_PS_IN, 0 },
  117. { "float4", "texcoord7", "TEXCOORD7_centroid", "vofi_TexCoord7", 0, AT_PS_IN, 0 },
  118. { "float4", "texcoord8", "TEXCOORD8_centroid", "vofi_TexCoord8", 0, AT_PS_IN, 0 },
  119. { "float4", "texcoord9", "TEXCOORD9_centroid", "vofi_TexCoord9", 0, AT_PS_IN, 0 },
  120. { "float4", "texcoord0", "TEXCOORD0", "vofi_TexCoord0", 0, AT_VS_OUT | AT_PS_IN, 0 },
  121. { "float4", "texcoord1", "TEXCOORD1", "vofi_TexCoord1", 0, AT_VS_OUT | AT_PS_IN, 0 },
  122. { "float4", "texcoord2", "TEXCOORD2", "vofi_TexCoord2", 0, AT_VS_OUT | AT_PS_IN, 0 },
  123. { "float4", "texcoord3", "TEXCOORD3", "vofi_TexCoord3", 0, AT_VS_OUT | AT_PS_IN, 0 },
  124. { "float4", "texcoord4", "TEXCOORD4", "vofi_TexCoord4", 0, AT_VS_OUT | AT_PS_IN, 0 },
  125. { "float4", "texcoord5", "TEXCOORD5", "vofi_TexCoord5", 0, AT_VS_OUT | AT_PS_IN, 0 },
  126. { "float4", "texcoord6", "TEXCOORD6", "vofi_TexCoord6", 0, AT_VS_OUT | AT_PS_IN, 0 },
  127. { "float4", "texcoord7", "TEXCOORD7", "vofi_TexCoord7", 0, AT_VS_OUT | AT_PS_IN, 0 },
  128. { "float4", "texcoord8", "TEXCOORD8", "vofi_TexCoord8", 0, AT_VS_OUT | AT_PS_IN, 0 },
  129. { "float4", "texcoord9", "TEXCOORD9", "vofi_TexCoord9", 0, AT_VS_OUT | AT_PS_IN, 0 },
  130. { "half4", "htexcoord0", "TEXCOORD0", "vofi_TexCoord0", 0, AT_PS_IN, 0 },
  131. { "half4", "htexcoord1", "TEXCOORD1", "vofi_TexCoord1", 0, AT_PS_IN, 0 },
  132. { "half4", "htexcoord2", "TEXCOORD2", "vofi_TexCoord2", 0, AT_PS_IN, 0 },
  133. { "half4", "htexcoord3", "TEXCOORD3", "vofi_TexCoord3", 0, AT_PS_IN, 0 },
  134. { "half4", "htexcoord4", "TEXCOORD4", "vofi_TexCoord4", 0, AT_PS_IN, 0 },
  135. { "half4", "htexcoord5", "TEXCOORD5", "vofi_TexCoord5", 0, AT_PS_IN, 0 },
  136. { "half4", "htexcoord6", "TEXCOORD6", "vofi_TexCoord6", 0, AT_PS_IN, 0 },
  137. { "half4", "htexcoord7", "TEXCOORD7", "vofi_TexCoord7", 0, AT_PS_IN, 0 },
  138. { "half4", "htexcoord8", "TEXCOORD8", "vofi_TexCoord8", 0, AT_PS_IN, 0 },
  139. { "half4", "htexcoord9", "TEXCOORD9", "vofi_TexCoord9", 0, AT_PS_IN, 0 },
  140. { "float", "fog", "FOG", "gl_FogFragCoord", 0, AT_VS_OUT, 0 },
  141. { "float4", "fog", "FOG", "gl_FogFragCoord", 0, AT_PS_IN, 0 },
  142. { NULL, NULL, NULL, NULL, 0, 0, 0 }
  143. };
  144. const char * types[] = {
  145. "int",
  146. "float",
  147. "half",
  148. "fixed",
  149. "bool",
  150. "cint",
  151. "cfloat",
  152. "void"
  153. };
  154. static const int numTypes = sizeof( types ) / sizeof( types[0] );
  155. const char * typePosts[] = {
  156. "1", "2", "3", "4",
  157. "1x1", "1x2", "1x3", "1x4",
  158. "2x1", "2x2", "2x3", "2x4",
  159. "3x1", "3x2", "3x3", "3x4",
  160. "4x1", "4x2", "4x3", "4x4"
  161. };
  162. static const int numTypePosts = sizeof( typePosts ) / sizeof( typePosts[0] );
  163. const char * prefixes[] = {
  164. "static",
  165. "const",
  166. "uniform",
  167. "struct",
  168. "sampler",
  169. "sampler1D",
  170. "sampler2D",
  171. "sampler3D",
  172. "samplerCUBE",
  173. "sampler1DShadow", // GLSL
  174. "sampler2DShadow", // GLSL
  175. "sampler3DShadow", // GLSL
  176. "samplerCubeShadow", // GLSL
  177. "sampler2DMS", // GLSL
  178. };
  179. static const int numPrefixes = sizeof( prefixes ) / sizeof( prefixes[0] );
  180. // For GLSL we need to have the names for the renderparms so we can look up their run time indices within the renderprograms
  181. static const char * GLSLParmNames[] = {
  182. "rpScreenCorrectionFactor",
  183. "rpWindowCoord",
  184. "rpDiffuseModifier",
  185. "rpSpecularModifier",
  186. "rpLocalLightOrigin",
  187. "rpLocalViewOrigin",
  188. "rpLightProjectionS",
  189. "rpLightProjectionT",
  190. "rpLightProjectionQ",
  191. "rpLightFalloffS",
  192. "rpBumpMatrixS",
  193. "rpBumpMatrixT",
  194. "rpDiffuseMatrixS",
  195. "rpDiffuseMatrixT",
  196. "rpSpecularMatrixS",
  197. "rpSpecularMatrixT",
  198. "rpVertexColorModulate",
  199. "rpVertexColorAdd",
  200. "rpColor",
  201. "rpViewOrigin",
  202. "rpGlobalEyePos",
  203. "rpMVPmatrixX",
  204. "rpMVPmatrixY",
  205. "rpMVPmatrixZ",
  206. "rpMVPmatrixW",
  207. "rpModelMatrixX",
  208. "rpModelMatrixY",
  209. "rpModelMatrixZ",
  210. "rpModelMatrixW",
  211. "rpProjectionMatrixX",
  212. "rpProjectionMatrixY",
  213. "rpProjectionMatrixZ",
  214. "rpProjectionMatrixW",
  215. "rpModelViewMatrixX",
  216. "rpModelViewMatrixY",
  217. "rpModelViewMatrixZ",
  218. "rpModelViewMatrixW",
  219. "rpTextureMatrixS",
  220. "rpTextureMatrixT",
  221. "rpTexGen0S",
  222. "rpTexGen0T",
  223. "rpTexGen0Q",
  224. "rpTexGen0Enabled",
  225. "rpTexGen1S",
  226. "rpTexGen1T",
  227. "rpTexGen1Q",
  228. "rpTexGen1Enabled",
  229. "rpWobbleSkyX",
  230. "rpWobbleSkyY",
  231. "rpWobbleSkyZ",
  232. "rpOverbright",
  233. "rpEnableSkinning",
  234. "rpAlphaTest"
  235. };
  236. /*
  237. ========================
  238. StripDeadCode
  239. ========================
  240. */
  241. idStr StripDeadCode( const idStr & in, const char * name ) {
  242. if ( r_skipStripDeadCode.GetBool() ) {
  243. return in;
  244. }
  245. //idLexer src( LEXFL_NOFATALERRORS );
  246. idParser src( LEXFL_NOFATALERRORS );
  247. src.LoadMemory( in.c_str(), in.Length(), name );
  248. src.AddDefine("PC");
  249. idList< idCGBlock, TAG_RENDERPROG > blocks;
  250. blocks.SetNum( 100 );
  251. idToken token;
  252. while ( !src.EndOfFile() ) {
  253. idCGBlock & block = blocks.Alloc();
  254. // read prefix
  255. while ( src.ReadToken( &token ) ) {
  256. bool found = false;
  257. for ( int i = 0; i < numPrefixes; i++ ) {
  258. if ( token == prefixes[i] ) {
  259. found = true;
  260. break;
  261. }
  262. }
  263. if ( !found ) {
  264. for ( int i = 0; i < numTypes; i++ ) {
  265. if ( token == types[i] ) {
  266. found = true;
  267. break;
  268. }
  269. int typeLen = idStr::Length( types[i] );
  270. if ( token.Cmpn( types[i], typeLen ) == 0 ) {
  271. for ( int j = 0; j < numTypePosts; j++ ) {
  272. if ( idStr::Cmp( token.c_str() + typeLen, typePosts[j] ) == 0 ) {
  273. found = true;
  274. break;
  275. }
  276. }
  277. if ( found ) {
  278. break;
  279. }
  280. }
  281. }
  282. }
  283. if ( found ) {
  284. if ( block.prefix.Length() > 0 && token.WhiteSpaceBeforeToken() ) {
  285. block.prefix += ' ';
  286. }
  287. block.prefix += token;
  288. } else {
  289. src.UnreadToken( &token );
  290. break;
  291. }
  292. }
  293. if ( !src.ReadToken( &token ) ) {
  294. blocks.SetNum( blocks.Num() - 1 );
  295. break;
  296. }
  297. block.name = token;
  298. if ( src.PeekTokenString( "=" ) || src.PeekTokenString( ":" ) || src.PeekTokenString( "[" ) ) {
  299. src.ReadToken( &token );
  300. block.postfix = token;
  301. while ( src.ReadToken( &token ) ) {
  302. if ( token == ";" ) {
  303. block.postfix += ';';
  304. break;
  305. } else {
  306. if ( token.WhiteSpaceBeforeToken() ){
  307. block.postfix += ' ';
  308. }
  309. block.postfix += token;
  310. }
  311. }
  312. } else if ( src.PeekTokenString( "(" ) ) {
  313. idStr parms, body;
  314. src.ParseBracedSection( parms, -1, true, '(', ')' );
  315. if ( src.CheckTokenString( ";" ) ) {
  316. block.postfix = parms + ";";
  317. } else {
  318. src.ParseBracedSection( body, -1, true, '{', '}' );
  319. block.postfix = parms + " " + body;
  320. }
  321. } else if ( src.PeekTokenString( "{" ) ) {
  322. src.ParseBracedSection( block.postfix, -1, true, '{', '}' );
  323. if ( src.CheckTokenString( ";" ) ) {
  324. block.postfix += ';';
  325. }
  326. } else if ( src.CheckTokenString( ";" ) ) {
  327. block.postfix = idStr( ';' );
  328. } else {
  329. src.Warning( "Could not strip dead code -- unknown token %s\n", token.c_str() );
  330. return in;
  331. }
  332. }
  333. idList<int, TAG_RENDERPROG> stack;
  334. for ( int i = 0; i < blocks.Num(); i++ ) {
  335. blocks[i].used = ( ( blocks[i].name == "main" )
  336. || blocks[i].name.Right( 4 ) == "_ubo"
  337. );
  338. if ( blocks[i].name == "include" ) {
  339. blocks[i].used = true;
  340. blocks[i].name = ""; // clear out the include tag
  341. }
  342. if ( blocks[i].used ) {
  343. stack.Append( i );
  344. }
  345. }
  346. while ( stack.Num() > 0 ) {
  347. int i = stack[stack.Num() - 1];
  348. stack.SetNum( stack.Num() - 1 );
  349. idLexer src( LEXFL_NOFATALERRORS );
  350. src.LoadMemory( blocks[i].postfix.c_str(), blocks[i].postfix.Length(), name );
  351. while ( src.ReadToken( &token ) ) {
  352. for ( int j = 0; j < blocks.Num(); j++ ) {
  353. if ( !blocks[j].used ) {
  354. if ( token == blocks[j].name ) {
  355. blocks[j].used = true;
  356. stack.Append( j );
  357. }
  358. }
  359. }
  360. }
  361. }
  362. idStr out;
  363. for ( int i = 0; i < blocks.Num(); i++ ) {
  364. if ( blocks[i].used ) {
  365. out += blocks[i].prefix;
  366. out += ' ';
  367. out += blocks[i].name;
  368. out += ' ';
  369. out += blocks[i].postfix;
  370. out += '\n';
  371. }
  372. }
  373. return out;
  374. }
  375. struct typeConversion_t {
  376. const char * typeCG;
  377. const char * typeGLSL;
  378. } typeConversion[] = {
  379. { "void", "void" },
  380. { "fixed", "float" },
  381. { "float", "float" },
  382. { "float2", "vec2" },
  383. { "float3", "vec3" },
  384. { "float4", "vec4" },
  385. { "half", "float" },
  386. { "half2", "vec2" },
  387. { "half3", "vec3" },
  388. { "half4", "vec4" },
  389. { "int", "int" },
  390. { "int2", "ivec2" },
  391. { "int3", "ivec3" },
  392. { "int4", "ivec4" },
  393. { "bool", "bool" },
  394. { "bool2", "bvec2" },
  395. { "bool3", "bvec3" },
  396. { "bool4", "bvec4" },
  397. { "float2x2", "mat2x2" },
  398. { "float2x3", "mat2x3" },
  399. { "float2x4", "mat2x4" },
  400. { "float3x2", "mat3x2" },
  401. { "float3x3", "mat3x3" },
  402. { "float3x4", "mat3x4" },
  403. { "float4x2", "mat4x2" },
  404. { "float4x3", "mat4x3" },
  405. { "float4x4", "mat4x4" },
  406. { "sampler1D", "sampler1D" },
  407. { "sampler2D", "sampler2D" },
  408. { "sampler3D", "sampler3D" },
  409. { "samplerCUBE", "samplerCube" },
  410. { "sampler1DShadow", "sampler1DShadow" },
  411. { "sampler2DShadow", "sampler2DShadow" },
  412. { "sampler3DShadow", "sampler3DShadow" },
  413. { "samplerCubeShadow", "samplerCubeShadow" },
  414. { "sampler2DMS", "sampler2DMS" },
  415. { NULL, NULL }
  416. };
  417. const char * vertexInsert = {
  418. "#version 150\n"
  419. "#define PC\n"
  420. "\n"
  421. "float saturate( float v ) { return clamp( v, 0.0, 1.0 ); }\n"
  422. "vec2 saturate( vec2 v ) { return clamp( v, 0.0, 1.0 ); }\n"
  423. "vec3 saturate( vec3 v ) { return clamp( v, 0.0, 1.0 ); }\n"
  424. "vec4 saturate( vec4 v ) { return clamp( v, 0.0, 1.0 ); }\n"
  425. "vec4 tex2Dlod( sampler2D sampler, vec4 texcoord ) { return textureLod( sampler, texcoord.xy, texcoord.w ); }\n"
  426. "\n"
  427. };
  428. const char * fragmentInsert = {
  429. "#version 150\n"
  430. "#define PC\n"
  431. "\n"
  432. "void clip( float v ) { if ( v < 0.0 ) { discard; } }\n"
  433. "void clip( vec2 v ) { if ( any( lessThan( v, vec2( 0.0 ) ) ) ) { discard; } }\n"
  434. "void clip( vec3 v ) { if ( any( lessThan( v, vec3( 0.0 ) ) ) ) { discard; } }\n"
  435. "void clip( vec4 v ) { if ( any( lessThan( v, vec4( 0.0 ) ) ) ) { discard; } }\n"
  436. "\n"
  437. "float saturate( float v ) { return clamp( v, 0.0, 1.0 ); }\n"
  438. "vec2 saturate( vec2 v ) { return clamp( v, 0.0, 1.0 ); }\n"
  439. "vec3 saturate( vec3 v ) { return clamp( v, 0.0, 1.0 ); }\n"
  440. "vec4 saturate( vec4 v ) { return clamp( v, 0.0, 1.0 ); }\n"
  441. "\n"
  442. "vec4 tex2D( sampler2D sampler, vec2 texcoord ) { return texture( sampler, texcoord.xy ); }\n"
  443. "vec4 tex2D( sampler2DShadow sampler, vec3 texcoord ) { return vec4( texture( sampler, texcoord.xyz ) ); }\n"
  444. "\n"
  445. "vec4 tex2D( sampler2D sampler, vec2 texcoord, vec2 dx, vec2 dy ) { return textureGrad( sampler, texcoord.xy, dx, dy ); }\n"
  446. "vec4 tex2D( sampler2DShadow sampler, vec3 texcoord, vec2 dx, vec2 dy ) { return vec4( textureGrad( sampler, texcoord.xyz, dx, dy ) ); }\n"
  447. "\n"
  448. "vec4 texCUBE( samplerCube sampler, vec3 texcoord ) { return texture( sampler, texcoord.xyz ); }\n"
  449. "vec4 texCUBE( samplerCubeShadow sampler, vec4 texcoord ) { return vec4( texture( sampler, texcoord.xyzw ) ); }\n"
  450. "\n"
  451. "vec4 tex1Dproj( sampler1D sampler, vec2 texcoord ) { return textureProj( sampler, texcoord ); }\n"
  452. "vec4 tex2Dproj( sampler2D sampler, vec3 texcoord ) { return textureProj( sampler, texcoord ); }\n"
  453. "vec4 tex3Dproj( sampler3D sampler, vec4 texcoord ) { return textureProj( sampler, texcoord ); }\n"
  454. "\n"
  455. "vec4 tex1Dbias( sampler1D sampler, vec4 texcoord ) { return texture( sampler, texcoord.x, texcoord.w ); }\n"
  456. "vec4 tex2Dbias( sampler2D sampler, vec4 texcoord ) { return texture( sampler, texcoord.xy, texcoord.w ); }\n"
  457. "vec4 tex3Dbias( sampler3D sampler, vec4 texcoord ) { return texture( sampler, texcoord.xyz, texcoord.w ); }\n"
  458. "vec4 texCUBEbias( samplerCube sampler, vec4 texcoord ) { return texture( sampler, texcoord.xyz, texcoord.w ); }\n"
  459. "\n"
  460. "vec4 tex1Dlod( sampler1D sampler, vec4 texcoord ) { return textureLod( sampler, texcoord.x, texcoord.w ); }\n"
  461. "vec4 tex2Dlod( sampler2D sampler, vec4 texcoord ) { return textureLod( sampler, texcoord.xy, texcoord.w ); }\n"
  462. "vec4 tex3Dlod( sampler3D sampler, vec4 texcoord ) { return textureLod( sampler, texcoord.xyz, texcoord.w ); }\n"
  463. "vec4 texCUBElod( samplerCube sampler, vec4 texcoord ) { return textureLod( sampler, texcoord.xyz, texcoord.w ); }\n"
  464. "\n"
  465. };
  466. struct builtinConversion_t {
  467. const char * nameCG;
  468. const char * nameGLSL;
  469. } builtinConversion[] = {
  470. { "frac", "fract" },
  471. { "lerp", "mix" },
  472. { "rsqrt", "inversesqrt" },
  473. { "ddx", "dFdx" },
  474. { "ddy", "dFdy" },
  475. { NULL, NULL }
  476. };
  477. struct inOutVariable_t {
  478. idStr type;
  479. idStr nameCg;
  480. idStr nameGLSL;
  481. bool declareInOut;
  482. };
  483. /*
  484. ========================
  485. ParseInOutStruct
  486. ========================
  487. */
  488. void ParseInOutStruct( idLexer & src, int attribType, idList< inOutVariable_t > & inOutVars ) {
  489. src.ExpectTokenString( "{" );
  490. while( !src.CheckTokenString( "}" ) ) {
  491. inOutVariable_t var;
  492. idToken token;
  493. src.ReadToken( &token );
  494. var.type = token;
  495. src.ReadToken( &token );
  496. var.nameCg = token;
  497. if ( !src.CheckTokenString( ":" ) ) {
  498. src.SkipUntilString( ";" );
  499. continue;
  500. }
  501. src.ReadToken( &token );
  502. var.nameGLSL = token;
  503. src.ExpectTokenString( ";" );
  504. // convert the type
  505. for ( int i = 0; typeConversion[i].typeCG != NULL; i++ ) {
  506. if ( var.type.Cmp( typeConversion[i].typeCG ) == 0 ) {
  507. var.type = typeConversion[i].typeGLSL;
  508. break;
  509. }
  510. }
  511. // convert the semantic to a GLSL name
  512. for ( int i = 0; attribsPC[i].semantic != NULL; i++ ) {
  513. if ( ( attribsPC[i].flags & attribType ) != 0 ) {
  514. if ( var.nameGLSL.Cmp( attribsPC[i].semantic ) == 0 ) {
  515. var.nameGLSL = attribsPC[i].glsl;
  516. break;
  517. }
  518. }
  519. }
  520. // check if it was defined previously
  521. var.declareInOut = true;
  522. for ( int i = 0; i < inOutVars.Num(); i++ ) {
  523. if ( var.nameGLSL == inOutVars[i].nameGLSL ) {
  524. var.declareInOut = false;
  525. break;
  526. }
  527. }
  528. inOutVars.Append( var );
  529. }
  530. src.ExpectTokenString( ";" );
  531. }
  532. /*
  533. ========================
  534. ConvertCG2GLSL
  535. ========================
  536. */
  537. idStr ConvertCG2GLSL( const idStr & in, const char * name, bool isVertexProgram, idStr & uniforms ) {
  538. idStr program;
  539. program.ReAllocate( in.Length() * 2, false );
  540. idList< inOutVariable_t, TAG_RENDERPROG > varsIn;
  541. idList< inOutVariable_t, TAG_RENDERPROG > varsOut;
  542. idList< idStr > uniformList;
  543. idLexer src( LEXFL_NOFATALERRORS );
  544. src.LoadMemory( in.c_str(), in.Length(), name );
  545. bool inMain = false;
  546. const char * uniformArrayName = isVertexProgram ? VERTEX_UNIFORM_ARRAY_NAME : FRAGMENT_UNIFORM_ARRAY_NAME;
  547. char newline[128] = { "\n" };
  548. idToken token;
  549. while ( src.ReadToken( &token ) ) {
  550. // check for uniforms
  551. while ( token == "uniform" && src.CheckTokenString( "float4" ) ) {
  552. src.ReadToken( &token );
  553. uniformList.Append( token );
  554. // strip ': register()' from uniforms
  555. if ( src.CheckTokenString( ":" ) ) {
  556. if ( src.CheckTokenString( "register" ) ) {
  557. src.SkipUntilString( ";" );
  558. }
  559. }
  560. src.ReadToken( & token );
  561. }
  562. // convert the in/out structs
  563. if ( token == "struct" ) {
  564. if ( src.CheckTokenString( "VS_IN" ) ) {
  565. ParseInOutStruct( src, AT_VS_IN, varsIn );
  566. program += "\n\n";
  567. for ( int i = 0; i < varsIn.Num(); i++ ) {
  568. if ( varsIn[i].declareInOut ) {
  569. program += "in " + varsIn[i].type + " " + varsIn[i].nameGLSL + ";\n";
  570. }
  571. }
  572. continue;
  573. } else if ( src.CheckTokenString( "VS_OUT" ) ) {
  574. ParseInOutStruct( src, AT_VS_OUT, varsOut );
  575. program += "\n";
  576. for ( int i = 0; i < varsOut.Num(); i++ ) {
  577. if ( varsOut[i].declareInOut ) {
  578. program += "out " + varsOut[i].type + " " + varsOut[i].nameGLSL + ";\n";
  579. }
  580. }
  581. continue;
  582. } else if ( src.CheckTokenString( "PS_IN" ) ) {
  583. ParseInOutStruct( src, AT_PS_IN, varsIn );
  584. program += "\n\n";
  585. for ( int i = 0; i < varsIn.Num(); i++ ) {
  586. if ( varsIn[i].declareInOut ) {
  587. program += "in " + varsIn[i].type + " " + varsIn[i].nameGLSL + ";\n";
  588. }
  589. }
  590. inOutVariable_t var;
  591. var.type = "vec4";
  592. var.nameCg = "position";
  593. var.nameGLSL = "gl_FragCoord";
  594. varsIn.Append( var );
  595. continue;
  596. } else if ( src.CheckTokenString( "PS_OUT" ) ) {
  597. ParseInOutStruct( src, AT_PS_OUT, varsOut );
  598. program += "\n";
  599. for ( int i = 0; i < varsOut.Num(); i++ ) {
  600. if ( varsOut[i].declareInOut ) {
  601. program += "out " + varsOut[i].type + " " + varsOut[i].nameGLSL + ";\n";
  602. }
  603. }
  604. continue;
  605. }
  606. }
  607. // strip 'static'
  608. if ( token == "static" ) {
  609. program += ( token.linesCrossed > 0 ) ? newline : ( token.WhiteSpaceBeforeToken() > 0 ? " " : "" );
  610. src.SkipWhiteSpace( true ); // remove white space between 'static' and the next token
  611. continue;
  612. }
  613. // strip ': register()' from uniforms
  614. if ( token == ":" ) {
  615. if ( src.CheckTokenString( "register" ) ) {
  616. src.SkipUntilString( ";" );
  617. program += ";";
  618. continue;
  619. }
  620. }
  621. // strip in/program parameters from main
  622. if ( token == "void" && src.CheckTokenString( "main" ) ) {
  623. src.ExpectTokenString( "(" );
  624. while( src.ReadToken( &token ) ) {
  625. if ( token == ")" ) {
  626. break;
  627. }
  628. }
  629. program += "\nvoid main()";
  630. inMain = true;
  631. continue;
  632. }
  633. // strip 'const' from local variables in main()
  634. if ( token == "const" && inMain ) {
  635. program += ( token.linesCrossed > 0 ) ? newline : ( token.WhiteSpaceBeforeToken() > 0 ? " " : "" );
  636. src.SkipWhiteSpace( true ); // remove white space between 'const' and the next token
  637. continue;
  638. }
  639. // maintain indentation
  640. if ( token == "{" ) {
  641. program += ( token.linesCrossed > 0 ) ? newline : ( token.WhiteSpaceBeforeToken() > 0 ? " " : "" );
  642. program += "{";
  643. int len = Min( idStr::Length( newline ) + 1, (int)sizeof( newline ) - 1 );
  644. newline[len - 1] = '\t';
  645. newline[len - 0] = '\0';
  646. continue;
  647. }
  648. if ( token == "}" ) {
  649. int len = Max( idStr::Length( newline ) - 1, 0 );
  650. newline[len] = '\0';
  651. program += ( token.linesCrossed > 0 ) ? newline : ( token.WhiteSpaceBeforeToken() > 0 ? " " : "" );
  652. program += "}";
  653. continue;
  654. }
  655. // check for a type conversion
  656. bool foundType = false;
  657. for ( int i = 0; typeConversion[i].typeCG != NULL; i++ ) {
  658. if ( token.Cmp( typeConversion[i].typeCG ) == 0 ) {
  659. program += ( token.linesCrossed > 0 ) ? newline : ( token.WhiteSpaceBeforeToken() > 0 ? " " : "" );
  660. program += typeConversion[i].typeGLSL;
  661. foundType = true;
  662. break;
  663. }
  664. }
  665. if ( foundType ) {
  666. continue;
  667. }
  668. if ( r_useUniformArrays.GetBool() ) {
  669. // check for uniforms that need to be converted to the array
  670. bool isUniform = false;
  671. for ( int i = 0; i < uniformList.Num(); i++ ) {
  672. if ( token == uniformList[i] ) {
  673. program += ( token.linesCrossed > 0 ) ? newline : ( token.WhiteSpaceBeforeToken() > 0 ? " " : "" );
  674. program += va( "%s[%d /* %s */]", uniformArrayName, i, uniformList[i].c_str() );
  675. isUniform = true;
  676. break;
  677. }
  678. }
  679. if ( isUniform ) {
  680. continue;
  681. }
  682. }
  683. // check for input/output parameters
  684. if ( src.CheckTokenString( "." ) ) {
  685. if ( token == "vertex" || token == "fragment" ) {
  686. idToken member;
  687. src.ReadToken( &member );
  688. bool foundInOut = false;
  689. for ( int i = 0; i < varsIn.Num(); i++ ) {
  690. if ( member.Cmp( varsIn[i].nameCg ) == 0 ) {
  691. program += ( token.linesCrossed > 0 ) ? newline : ( token.WhiteSpaceBeforeToken() > 0 ? " " : "" );
  692. program += varsIn[i].nameGLSL;
  693. foundInOut = true;
  694. break;
  695. }
  696. }
  697. if ( !foundInOut ) {
  698. src.Error( "invalid input parameter %s.%s", token.c_str(), member.c_str() );
  699. program += ( token.linesCrossed > 0 ) ? newline : ( token.WhiteSpaceBeforeToken() > 0 ? " " : "" );
  700. program += token;
  701. program += ".";
  702. program += member;
  703. }
  704. continue;
  705. }
  706. if ( token == "result" ) {
  707. idToken member;
  708. src.ReadToken( &member );
  709. bool foundInOut = false;
  710. for ( int i = 0; i < varsOut.Num(); i++ ) {
  711. if ( member.Cmp( varsOut[i].nameCg ) == 0 ) {
  712. program += ( token.linesCrossed > 0 ) ? newline : ( token.WhiteSpaceBeforeToken() > 0 ? " " : "" );
  713. program += varsOut[i].nameGLSL;
  714. foundInOut = true;
  715. break;
  716. }
  717. }
  718. if ( !foundInOut ) {
  719. src.Error( "invalid output parameter %s.%s", token.c_str(), member.c_str() );
  720. program += ( token.linesCrossed > 0 ) ? newline : ( token.WhiteSpaceBeforeToken() > 0 ? " " : "" );
  721. program += token;
  722. program += ".";
  723. program += member;
  724. }
  725. continue;
  726. }
  727. program += ( token.linesCrossed > 0 ) ? newline : ( token.WhiteSpaceBeforeToken() > 0 ? " " : "" );
  728. program += token;
  729. program += ".";
  730. continue;
  731. }
  732. // check for a function conversion
  733. bool foundFunction = false;
  734. for ( int i = 0; builtinConversion[i].nameCG != NULL; i++ ) {
  735. if ( token.Cmp( builtinConversion[i].nameCG ) == 0 ) {
  736. program += ( token.linesCrossed > 0 ) ? newline : ( token.WhiteSpaceBeforeToken() > 0 ? " " : "" );
  737. program += builtinConversion[i].nameGLSL;
  738. foundFunction = true;
  739. break;
  740. }
  741. }
  742. if ( foundFunction ) {
  743. continue;
  744. }
  745. program += ( token.linesCrossed > 0 ) ? newline : ( token.WhiteSpaceBeforeToken() > 0 ? " " : "" );
  746. program += token;
  747. }
  748. idStr out;
  749. if ( isVertexProgram ) {
  750. out.ReAllocate( idStr::Length( vertexInsert ) + in.Length() * 2, false );
  751. out += vertexInsert;
  752. } else {
  753. out.ReAllocate( idStr::Length( fragmentInsert ) + in.Length() * 2, false );
  754. out += fragmentInsert;
  755. }
  756. if ( uniformList.Num() > 0 ) {
  757. if ( r_useUniformArrays.GetBool() ) {
  758. out += va( "\nuniform vec4 %s[%d];\n", uniformArrayName, uniformList.Num() );
  759. } else {
  760. out += "\n";
  761. for ( int i = 0; i < uniformList.Num(); i++ ) {
  762. out += "uniform vec4 ";
  763. out += uniformList[i];
  764. out += ";\n";
  765. }
  766. }
  767. }
  768. out += program;
  769. for ( int i = 0; i < uniformList.Num(); i++ ) {
  770. uniforms += uniformList[i];
  771. uniforms += "\n";
  772. }
  773. uniforms += "\n";
  774. return out;
  775. }
  776. /*
  777. ================================================================================================
  778. idRenderProgManager::LoadGLSLShader
  779. ================================================================================================
  780. */
  781. GLuint idRenderProgManager::LoadGLSLShader( GLenum target, const char * name, idList<int> & uniforms ) {
  782. idStr inFile;
  783. idStr outFileHLSL;
  784. idStr outFileGLSL;
  785. idStr outFileUniforms;
  786. inFile.Format( "renderprogs\\%s", name );
  787. inFile.StripFileExtension();
  788. outFileHLSL.Format( "renderprogs\\glsl\\%s", name );
  789. outFileHLSL.StripFileExtension();
  790. outFileGLSL.Format( "renderprogs\\glsl\\%s", name );
  791. outFileGLSL.StripFileExtension();
  792. outFileUniforms.Format( "renderprogs\\glsl\\%s", name );
  793. outFileUniforms.StripFileExtension();
  794. if ( target == GL_FRAGMENT_SHADER ) {
  795. inFile += ".pixel";
  796. outFileHLSL += "_fragment.hlsl";
  797. outFileGLSL += "_fragment.glsl";
  798. outFileUniforms += "_fragment.uniforms";
  799. } else {
  800. inFile += ".vertex";
  801. outFileHLSL += "_vertex.hlsl";
  802. outFileGLSL += "_vertex.glsl";
  803. outFileUniforms += "_vertex.uniforms";
  804. }
  805. // first check whether we already have a valid GLSL file and compare it to the hlsl timestamp;
  806. ID_TIME_T hlslTimeStamp;
  807. int hlslFileLength = fileSystem->ReadFile( inFile.c_str(), NULL, &hlslTimeStamp );
  808. ID_TIME_T glslTimeStamp;
  809. int glslFileLength = fileSystem->ReadFile( outFileGLSL.c_str(), NULL, &glslTimeStamp );
  810. // if the glsl file doesn't exist or we have a newer HLSL file we need to recreate the glsl file.
  811. idStr programGLSL;
  812. idStr programUniforms;
  813. if ( ( glslFileLength <= 0 ) || ( hlslTimeStamp > glslTimeStamp ) ) {
  814. if ( hlslFileLength <= 0 ) {
  815. // hlsl file doesn't even exist bail out
  816. return false;
  817. }
  818. void * hlslFileBuffer = NULL;
  819. int len = fileSystem->ReadFile( inFile.c_str(), &hlslFileBuffer );
  820. if ( len <= 0 ) {
  821. return false;
  822. }
  823. idStr hlslCode( ( const char* ) hlslFileBuffer );
  824. idStr programHLSL = StripDeadCode( hlslCode, inFile );
  825. programGLSL = ConvertCG2GLSL( programHLSL, inFile, target == GL_VERTEX_SHADER, programUniforms );
  826. fileSystem->WriteFile( outFileHLSL, programHLSL.c_str(), programHLSL.Length(), "fs_basepath" );
  827. fileSystem->WriteFile( outFileGLSL, programGLSL.c_str(), programGLSL.Length(), "fs_basepath" );
  828. if ( r_useUniformArrays.GetBool() ) {
  829. fileSystem->WriteFile( outFileUniforms, programUniforms.c_str(), programUniforms.Length(), "fs_basepath" );
  830. }
  831. } else {
  832. // read in the glsl file
  833. void * fileBufferGLSL = NULL;
  834. int lengthGLSL = fileSystem->ReadFile( outFileGLSL.c_str(), &fileBufferGLSL );
  835. if ( lengthGLSL <= 0 ) {
  836. idLib::Error( "GLSL file %s could not be loaded and may be corrupt", outFileGLSL.c_str() );
  837. }
  838. programGLSL = ( const char * ) fileBufferGLSL;
  839. Mem_Free( fileBufferGLSL );
  840. if ( r_useUniformArrays.GetBool() ) {
  841. // read in the uniform file
  842. void * fileBufferUniforms = NULL;
  843. int lengthUniforms = fileSystem->ReadFile( outFileUniforms.c_str(), &fileBufferUniforms );
  844. if ( lengthUniforms <= 0 ) {
  845. idLib::Error( "uniform file %s could not be loaded and may be corrupt", outFileUniforms.c_str() );
  846. }
  847. programUniforms = ( const char* ) fileBufferUniforms;
  848. Mem_Free( fileBufferUniforms );
  849. }
  850. }
  851. // find the uniforms locations in either the vertex or fragment uniform array
  852. if ( r_useUniformArrays.GetBool() ) {
  853. uniforms.Clear();
  854. idLexer src( programUniforms, programUniforms.Length(), "uniforms" );
  855. idToken token;
  856. while ( src.ReadToken( &token ) ) {
  857. int index = -1;
  858. for ( int i = 0; i < RENDERPARM_TOTAL && index == -1; i++ ) {
  859. const char * parmName = GetGLSLParmName( i );
  860. if ( token == parmName ) {
  861. index = i;
  862. }
  863. }
  864. for ( int i = 0; i < MAX_GLSL_USER_PARMS && index == -1; i++ ) {
  865. const char * parmName = GetGLSLParmName( RENDERPARM_USER + i );
  866. if ( token == parmName ) {
  867. index = RENDERPARM_USER + i;
  868. }
  869. }
  870. if ( index == -1 ) {
  871. idLib::Error( "couldn't find uniform %s for %s", token.c_str(), outFileGLSL.c_str() );
  872. }
  873. uniforms.Append( index );
  874. }
  875. }
  876. // create and compile the shader
  877. const GLuint shader = qglCreateShader( target );
  878. if ( shader ) {
  879. const char * source[1] = { programGLSL.c_str() };
  880. qglShaderSource( shader, 1, source, NULL );
  881. qglCompileShader( shader );
  882. int infologLength = 0;
  883. qglGetShaderiv( shader, GL_INFO_LOG_LENGTH, &infologLength );
  884. if ( infologLength > 1 ) {
  885. idTempArray<char> infoLog( infologLength );
  886. int charsWritten = 0;
  887. qglGetShaderInfoLog( shader, infologLength, &charsWritten, infoLog.Ptr() );
  888. // catch the strings the ATI and Intel drivers output on success
  889. if ( strstr( infoLog.Ptr(), "successfully compiled to run on hardware" ) != NULL ||
  890. strstr( infoLog.Ptr(), "No errors." ) != NULL ) {
  891. //idLib::Printf( "%s program %s from %s compiled to run on hardware\n", typeName, GetName(), GetFileName() );
  892. } else {
  893. idLib::Printf( "While compiling %s program %s\n", ( target == GL_FRAGMENT_SHADER ) ? "fragment" : "vertex" , inFile.c_str() );
  894. const char separator = '\n';
  895. idList<idStr> lines;
  896. lines.Clear();
  897. idStr source( programGLSL );
  898. lines.Append( source );
  899. for ( int index = 0, ofs = lines[index].Find( separator ); ofs != -1; index++, ofs = lines[index].Find( separator ) ) {
  900. lines.Append( lines[index].c_str() + ofs + 1 );
  901. lines[index].CapLength( ofs );
  902. }
  903. idLib::Printf( "-----------------\n" );
  904. for ( int i = 0; i < lines.Num(); i++ ) {
  905. idLib::Printf( "%3d: %s\n", i+1, lines[i].c_str() );
  906. }
  907. idLib::Printf( "-----------------\n" );
  908. idLib::Printf( "%s\n", infoLog.Ptr() );
  909. }
  910. }
  911. GLint compiled = GL_FALSE;
  912. qglGetShaderiv( shader, GL_COMPILE_STATUS, &compiled );
  913. if ( compiled == GL_FALSE ) {
  914. qglDeleteShader( shader );
  915. return INVALID_PROGID;
  916. }
  917. }
  918. return shader;
  919. }
  920. /*
  921. ================================================================================================
  922. idRenderProgManager::FindGLSLProgram
  923. ================================================================================================
  924. */
  925. int idRenderProgManager::FindGLSLProgram( const char * name, int vIndex, int fIndex ) {
  926. for ( int i = 0; i < glslPrograms.Num(); ++i ) {
  927. if ( ( glslPrograms[i].vertexShaderIndex == vIndex ) && ( glslPrograms[i].fragmentShaderIndex == fIndex ) ) {
  928. LoadGLSLProgram( i, vIndex, fIndex );
  929. return i;
  930. }
  931. }
  932. glslProgram_t program;
  933. program.name = name;
  934. int index = glslPrograms.Append( program );
  935. LoadGLSLProgram( index, vIndex, fIndex );
  936. return index;
  937. }
  938. /*
  939. ================================================================================================
  940. idRenderProgManager::GetGLSLParmName
  941. ================================================================================================
  942. */
  943. const char* idRenderProgManager::GetGLSLParmName( int rp ) const {
  944. if ( rp >= RENDERPARM_USER ) {
  945. int userParmIndex = rp - RENDERPARM_USER;
  946. return va("rpUser%d", userParmIndex );
  947. }
  948. assert( rp < RENDERPARM_TOTAL );
  949. return GLSLParmNames[ rp ];
  950. }
  951. /*
  952. ================================================================================================
  953. idRenderProgManager::SetUniformValue
  954. ================================================================================================
  955. */
  956. void idRenderProgManager::SetUniformValue( const renderParm_t rp, const float * value ) {
  957. for ( int i = 0; i < 4; i++ ) {
  958. glslUniforms[rp][i] = value[i];
  959. }
  960. }
  961. /*
  962. ================================================================================================
  963. idRenderProgManager::CommitUnforms
  964. ================================================================================================
  965. */
  966. void idRenderProgManager::CommitUniforms() {
  967. const int progID = GetGLSLCurrentProgram();
  968. const glslProgram_t & prog = glslPrograms[progID];
  969. if ( r_useUniformArrays.GetBool() ) {
  970. ALIGNTYPE16 idVec4 localVectors[RENDERPARM_USER + MAX_GLSL_USER_PARMS];
  971. if ( prog.vertexShaderIndex >= 0 ) {
  972. const idList<int> & vertexUniforms = vertexShaders[prog.vertexShaderIndex].uniforms;
  973. if ( prog.vertexUniformArray != -1 && vertexUniforms.Num() > 0 ) {
  974. for ( int i = 0; i < vertexUniforms.Num(); i++ ) {
  975. localVectors[i] = glslUniforms[vertexUniforms[i]];
  976. }
  977. qglUniform4fv( prog.vertexUniformArray, vertexUniforms.Num(), localVectors->ToFloatPtr() );
  978. }
  979. }
  980. if ( prog.fragmentShaderIndex >= 0 ) {
  981. const idList<int> & fragmentUniforms = fragmentShaders[prog.fragmentShaderIndex].uniforms;
  982. if ( prog.fragmentUniformArray != -1 && fragmentUniforms.Num() > 0 ) {
  983. for ( int i = 0; i < fragmentUniforms.Num(); i++ ) {
  984. localVectors[i] = glslUniforms[fragmentUniforms[i]];
  985. }
  986. qglUniform4fv( prog.fragmentUniformArray, fragmentUniforms.Num(), localVectors->ToFloatPtr() );
  987. }
  988. }
  989. } else {
  990. for ( int i = 0; i < prog.uniformLocations.Num(); i++ ) {
  991. const glslUniformLocation_t & uniformLocation = prog.uniformLocations[i];
  992. qglUniform4fv( uniformLocation.uniformIndex, 1, glslUniforms[uniformLocation.parmIndex].ToFloatPtr() );
  993. }
  994. }
  995. }
  996. class idSort_QuickUniforms : public idSort_Quick< glslUniformLocation_t, idSort_QuickUniforms > {
  997. public:
  998. int Compare( const glslUniformLocation_t & a, const glslUniformLocation_t & b ) const { return a.uniformIndex - b.uniformIndex; }
  999. };
  1000. /*
  1001. ================================================================================================
  1002. idRenderProgManager::LoadGLSLProgram
  1003. ================================================================================================
  1004. */
  1005. void idRenderProgManager::LoadGLSLProgram( const int programIndex, const int vertexShaderIndex, const int fragmentShaderIndex ) {
  1006. glslProgram_t & prog = glslPrograms[programIndex];
  1007. if ( prog.progId != INVALID_PROGID ) {
  1008. return; // Already loaded
  1009. }
  1010. GLuint vertexProgID = ( vertexShaderIndex != -1 ) ? vertexShaders[ vertexShaderIndex ].progId : INVALID_PROGID;
  1011. GLuint fragmentProgID = ( fragmentShaderIndex != -1 ) ? fragmentShaders[ fragmentShaderIndex ].progId : INVALID_PROGID;
  1012. const GLuint program = qglCreateProgram();
  1013. if ( program ) {
  1014. if ( vertexProgID != INVALID_PROGID ) {
  1015. qglAttachShader( program, vertexProgID );
  1016. }
  1017. if ( fragmentProgID != INVALID_PROGID ) {
  1018. qglAttachShader( program, fragmentProgID );
  1019. }
  1020. // bind vertex attribute locations
  1021. for ( int i = 0; attribsPC[i].glsl != NULL; i++ ) {
  1022. if ( ( attribsPC[i].flags & AT_VS_IN ) != 0 ) {
  1023. qglBindAttribLocation( program, attribsPC[i].bind, attribsPC[i].glsl );
  1024. }
  1025. }
  1026. qglLinkProgram( program );
  1027. int infologLength = 0;
  1028. qglGetProgramiv( program, GL_INFO_LOG_LENGTH, &infologLength );
  1029. if ( infologLength > 1 ) {
  1030. char * infoLog = (char *)malloc( infologLength );
  1031. int charsWritten = 0;
  1032. qglGetProgramInfoLog( program, infologLength, &charsWritten, infoLog );
  1033. // catch the strings the ATI and Intel drivers output on success
  1034. if ( strstr( infoLog, "Vertex shader(s) linked, fragment shader(s) linked." ) != NULL || strstr( infoLog, "No errors." ) != NULL ) {
  1035. //idLib::Printf( "render prog %s from %s linked\n", GetName(), GetFileName() );
  1036. } else {
  1037. idLib::Printf( "While linking GLSL program %d with vertexShader %s and fragmentShader %s\n",
  1038. programIndex,
  1039. ( vertexShaderIndex >= 0 ) ? vertexShaders[vertexShaderIndex].name.c_str() : "<Invalid>",
  1040. ( fragmentShaderIndex >= 0 ) ? fragmentShaders[ fragmentShaderIndex ].name.c_str() : "<Invalid>" );
  1041. idLib::Printf( "%s\n", infoLog );
  1042. }
  1043. free( infoLog );
  1044. }
  1045. }
  1046. int linked = GL_FALSE;
  1047. qglGetProgramiv( program, GL_LINK_STATUS, &linked );
  1048. if ( linked == GL_FALSE ) {
  1049. qglDeleteProgram( program );
  1050. idLib::Error( "While linking GLSL program %d with vertexShader %s and fragmentShader %s\n",
  1051. programIndex,
  1052. ( vertexShaderIndex >= 0 ) ? vertexShaders[vertexShaderIndex].name.c_str() : "<Invalid>",
  1053. ( fragmentShaderIndex >= 0 ) ? fragmentShaders[ fragmentShaderIndex ].name.c_str() : "<Invalid>" );
  1054. return;
  1055. }
  1056. if ( r_useUniformArrays.GetBool() ) {
  1057. prog.vertexUniformArray = qglGetUniformLocation( program, VERTEX_UNIFORM_ARRAY_NAME );
  1058. prog.fragmentUniformArray = qglGetUniformLocation( program, FRAGMENT_UNIFORM_ARRAY_NAME );
  1059. assert( prog.vertexUniformArray != -1 || vertexShaderIndex < 0 || vertexShaders[vertexShaderIndex].uniforms.Num() == 0 );
  1060. assert( prog.fragmentUniformArray != -1 || fragmentShaderIndex < 0 || fragmentShaders[fragmentShaderIndex].uniforms.Num() == 0 );
  1061. } else {
  1062. // store the uniform locations after we have linked the GLSL program
  1063. prog.uniformLocations.Clear();
  1064. for ( int i = 0; i < RENDERPARM_TOTAL; i++ ) {
  1065. const char * parmName = GetGLSLParmName( i );
  1066. GLint loc = qglGetUniformLocation( program, parmName );
  1067. if ( loc != -1 ) {
  1068. glslUniformLocation_t uniformLocation;
  1069. uniformLocation.parmIndex = i;
  1070. uniformLocation.uniformIndex = loc;
  1071. prog.uniformLocations.Append( uniformLocation );
  1072. }
  1073. }
  1074. // store the USER uniform locations
  1075. for ( int i = 0; i < MAX_GLSL_USER_PARMS; i++ ) {
  1076. const char * parmName = GetGLSLParmName( RENDERPARM_USER + i );
  1077. GLint loc = qglGetUniformLocation( program, parmName );
  1078. if ( loc != -1 ) {
  1079. glslUniformLocation_t uniformLocation;
  1080. uniformLocation.parmIndex = RENDERPARM_USER + i;
  1081. uniformLocation.uniformIndex = loc;
  1082. prog.uniformLocations.Append( uniformLocation );
  1083. }
  1084. }
  1085. // sort the uniforms based on index
  1086. prog.uniformLocations.SortWithTemplate( idSort_QuickUniforms() );
  1087. }
  1088. // get the uniform buffer binding for skinning joint matrices
  1089. GLint blockIndex = qglGetUniformBlockIndex( program, "matrices_ubo" );
  1090. if ( blockIndex != -1 ) {
  1091. qglUniformBlockBinding( program, blockIndex, 0 );
  1092. }
  1093. // set the texture unit locations once for the render program. We only need to do this once since we only link the program once
  1094. qglUseProgram( program );
  1095. for ( int i = 0; i < MAX_PROG_TEXTURE_PARMS; ++i ) {
  1096. GLint loc = qglGetUniformLocation( program, va( "samp%d", i ) );
  1097. if ( loc != -1 ) {
  1098. qglUniform1i( loc, i );
  1099. }
  1100. }
  1101. idStr programName = vertexShaders[ vertexShaderIndex ].name;
  1102. programName.StripFileExtension();
  1103. prog.name = programName;
  1104. prog.progId = program;
  1105. prog.fragmentShaderIndex = fragmentShaderIndex;
  1106. prog.vertexShaderIndex = vertexShaderIndex;
  1107. }
  1108. /*
  1109. ================================================================================================
  1110. idRenderProgManager::ZeroUniforms
  1111. ================================================================================================
  1112. */
  1113. void idRenderProgManager::ZeroUniforms() {
  1114. memset( glslUniforms.Ptr(), 0, glslUniforms.Allocated() );
  1115. }