draw_nv20.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 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 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 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 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 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. #include "../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "tr_local.h"
  23. typedef enum {
  24. FPROG_BUMP_AND_LIGHT,
  25. FPROG_DIFFUSE_COLOR,
  26. FPROG_SPECULAR_COLOR,
  27. FPROG_DIFFUSE_AND_SPECULAR_COLOR,
  28. FPROG_NUM_FRAGMENT_PROGRAMS
  29. } fragmentProgram_t;
  30. GLuint fragmentDisplayListBase; // FPROG_NUM_FRAGMENT_PROGRAMS lists
  31. void RB_NV20_DependentSpecularPass( const drawInteraction_t *din );
  32. void RB_NV20_DependentAmbientPass( void );
  33. /*
  34. =========================================================================================
  35. GENERAL INTERACTION RENDERING
  36. =========================================================================================
  37. */
  38. /*
  39. ====================
  40. GL_SelectTextureNoClient
  41. ====================
  42. */
  43. void GL_SelectTextureNoClient( int unit ) {
  44. backEnd.glState.currenttmu = unit;
  45. qglActiveTextureARB( GL_TEXTURE0_ARB + unit );
  46. RB_LogComment( "glActiveTextureARB( %i )\n", unit );
  47. }
  48. /*
  49. ==================
  50. RB_NV20_BumpAndLightFragment
  51. ==================
  52. */
  53. static void RB_NV20_BumpAndLightFragment( void ) {
  54. if ( r_useCombinerDisplayLists.GetBool() ) {
  55. qglCallList( fragmentDisplayListBase + FPROG_BUMP_AND_LIGHT );
  56. return;
  57. }
  58. // program the nvidia register combiners
  59. qglCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 3 );
  60. // stage 0 rgb performs the dot product
  61. // SPARE0 = TEXTURE0 dot TEXTURE1
  62. qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV,
  63. GL_TEXTURE1_ARB, GL_EXPAND_NORMAL_NV, GL_RGB );
  64. qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV,
  65. GL_TEXTURE0_ARB, GL_EXPAND_NORMAL_NV, GL_RGB );
  66. qglCombinerOutputNV( GL_COMBINER0_NV, GL_RGB,
  67. GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV,
  68. GL_NONE, GL_NONE, GL_TRUE, GL_FALSE, GL_FALSE );
  69. // stage 1 rgb multiplies texture 2 and 3 together
  70. // SPARE1 = TEXTURE2 * TEXTURE3
  71. qglCombinerInputNV( GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_A_NV,
  72. GL_TEXTURE2_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  73. qglCombinerInputNV( GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_B_NV,
  74. GL_TEXTURE3_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  75. qglCombinerOutputNV( GL_COMBINER1_NV, GL_RGB,
  76. GL_SPARE1_NV, GL_DISCARD_NV, GL_DISCARD_NV,
  77. GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
  78. // stage 1 alpha does nohing
  79. // stage 2 color multiplies spare0 * spare 1 just for debugging
  80. // SPARE0 = SPARE0 * SPARE1
  81. qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_A_NV,
  82. GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  83. qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_B_NV,
  84. GL_SPARE1_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  85. qglCombinerOutputNV( GL_COMBINER2_NV, GL_RGB,
  86. GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV,
  87. GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
  88. // stage 2 alpha multiples spare0 * spare 1
  89. // SPARE0 = SPARE0 * SPARE1
  90. qglCombinerInputNV( GL_COMBINER2_NV, GL_ALPHA, GL_VARIABLE_A_NV,
  91. GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_BLUE );
  92. qglCombinerInputNV( GL_COMBINER2_NV, GL_ALPHA, GL_VARIABLE_B_NV,
  93. GL_SPARE1_NV, GL_UNSIGNED_IDENTITY_NV, GL_BLUE );
  94. qglCombinerOutputNV( GL_COMBINER2_NV, GL_ALPHA,
  95. GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV,
  96. GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
  97. // final combiner
  98. qglFinalCombinerInputNV( GL_VARIABLE_D_NV, GL_SPARE0_NV,
  99. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  100. qglFinalCombinerInputNV( GL_VARIABLE_A_NV, GL_ZERO,
  101. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  102. qglFinalCombinerInputNV( GL_VARIABLE_B_NV, GL_ZERO,
  103. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  104. qglFinalCombinerInputNV( GL_VARIABLE_C_NV, GL_ZERO,
  105. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  106. qglFinalCombinerInputNV( GL_VARIABLE_G_NV, GL_SPARE0_NV,
  107. GL_UNSIGNED_IDENTITY_NV, GL_ALPHA );
  108. }
  109. /*
  110. ==================
  111. RB_NV20_DI_BumpAndLightPass
  112. We are going to write alpha as light falloff * ( bump dot light ) * lightProjection
  113. If the light isn't a monoLightShader, the lightProjection will be skipped, because
  114. it will have to be done on an itterated basis
  115. ==================
  116. */
  117. static void RB_NV20_DI_BumpAndLightPass( const drawInteraction_t *din, bool monoLightShader ) {
  118. RB_LogComment( "---------- RB_NV_BumpAndLightPass ----------\n" );
  119. GL_State( GLS_COLORMASK | GLS_DEPTHMASK | backEnd.depthFunc );
  120. // texture 0 is the normalization cube map
  121. // GL_TEXTURE0_ARB will be the normalized vector
  122. // towards the light source
  123. #ifdef MACOS_X
  124. GL_SelectTexture( 0 );
  125. qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
  126. #else
  127. GL_SelectTextureNoClient( 0 );
  128. #endif
  129. if ( din->ambientLight ) {
  130. globalImages->ambientNormalMap->Bind();
  131. } else {
  132. globalImages->normalCubeMapImage->Bind();
  133. }
  134. // texture 1 will be the per-surface bump map
  135. #ifdef MACOS_X
  136. GL_SelectTexture( 1 );
  137. qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
  138. #else
  139. GL_SelectTextureNoClient( 1 );
  140. #endif
  141. din->bumpImage->Bind();
  142. // texture 2 will be the light falloff texture
  143. #ifdef MACOS_X
  144. GL_SelectTexture( 2 );
  145. qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
  146. #else
  147. GL_SelectTextureNoClient( 2 );
  148. #endif
  149. din->lightFalloffImage->Bind();
  150. // texture 3 will be the light projection texture
  151. #ifdef MACOS_X
  152. GL_SelectTexture( 3 );
  153. qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
  154. #else
  155. GL_SelectTextureNoClient( 3 );
  156. #endif
  157. if ( monoLightShader ) {
  158. din->lightImage->Bind();
  159. } else {
  160. // if the projected texture is multi-colored, we
  161. // will need to do it in subsequent passes
  162. globalImages->whiteImage->Bind();
  163. }
  164. // bind our "fragment program"
  165. RB_NV20_BumpAndLightFragment();
  166. // draw it
  167. qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_NV20_BUMP_AND_LIGHT );
  168. RB_DrawElementsWithCounters( din->surf->geo );
  169. }
  170. /*
  171. ==================
  172. RB_NV20_DiffuseColorFragment
  173. ==================
  174. */
  175. static void RB_NV20_DiffuseColorFragment( void ) {
  176. if ( r_useCombinerDisplayLists.GetBool() ) {
  177. qglCallList( fragmentDisplayListBase + FPROG_DIFFUSE_COLOR );
  178. return;
  179. }
  180. // program the nvidia register combiners
  181. qglCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 1 );
  182. // stage 0 is free, so we always do the multiply of the vertex color
  183. // when the vertex color is inverted, qglCombinerInputNV(GL_VARIABLE_B_NV) will be changed
  184. qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV,
  185. GL_TEXTURE0_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  186. qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV,
  187. GL_PRIMARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  188. qglCombinerOutputNV( GL_COMBINER0_NV, GL_RGB,
  189. GL_TEXTURE0_ARB, GL_DISCARD_NV, GL_DISCARD_NV,
  190. GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
  191. qglCombinerOutputNV( GL_COMBINER0_NV, GL_ALPHA,
  192. GL_DISCARD_NV, GL_DISCARD_NV, GL_DISCARD_NV,
  193. GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
  194. // for GL_CONSTANT_COLOR0_NV * TEXTURE0 * TEXTURE1
  195. qglFinalCombinerInputNV( GL_VARIABLE_A_NV, GL_CONSTANT_COLOR0_NV,
  196. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  197. qglFinalCombinerInputNV( GL_VARIABLE_B_NV, GL_E_TIMES_F_NV,
  198. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  199. qglFinalCombinerInputNV( GL_VARIABLE_C_NV, GL_ZERO,
  200. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  201. qglFinalCombinerInputNV( GL_VARIABLE_D_NV, GL_ZERO,
  202. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  203. qglFinalCombinerInputNV( GL_VARIABLE_E_NV, GL_TEXTURE0_ARB,
  204. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  205. qglFinalCombinerInputNV( GL_VARIABLE_F_NV, GL_TEXTURE1_ARB,
  206. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  207. qglFinalCombinerInputNV( GL_VARIABLE_G_NV, GL_ZERO,
  208. GL_UNSIGNED_IDENTITY_NV, GL_ALPHA );
  209. }
  210. /*
  211. ==================
  212. RB_NV20_DI_DiffuseColorPass
  213. ==================
  214. */
  215. static void RB_NV20_DI_DiffuseColorPass( const drawInteraction_t *din ) {
  216. RB_LogComment( "---------- RB_NV20_DiffuseColorPass ----------\n" );
  217. GL_State( GLS_SRCBLEND_DST_ALPHA | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | GLS_ALPHAMASK
  218. | backEnd.depthFunc );
  219. // texture 0 will be the per-surface diffuse map
  220. #ifdef MACOS_X
  221. GL_SelectTexture( 0 );
  222. qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
  223. #else
  224. GL_SelectTextureNoClient( 0 );
  225. #endif
  226. din->diffuseImage->Bind();
  227. // texture 1 will be the light projected texture
  228. #ifdef MACOS_X
  229. GL_SelectTexture( 1 );
  230. qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
  231. #else
  232. GL_SelectTextureNoClient( 1 );
  233. #endif
  234. din->lightImage->Bind();
  235. // texture 2 is disabled
  236. #ifdef MACOS_X
  237. GL_SelectTexture( 2 );
  238. qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
  239. #else
  240. GL_SelectTextureNoClient( 2 );
  241. #endif
  242. globalImages->BindNull();
  243. // texture 3 is disabled
  244. #ifdef MACOS_X
  245. GL_SelectTexture( 3 );
  246. qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
  247. #else
  248. GL_SelectTextureNoClient( 3 );
  249. #endif
  250. globalImages->BindNull();
  251. // bind our "fragment program"
  252. RB_NV20_DiffuseColorFragment();
  253. // override one parameter for inverted vertex color
  254. if ( din->vertexColor == SVC_INVERSE_MODULATE ) {
  255. qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV,
  256. GL_PRIMARY_COLOR_NV, GL_UNSIGNED_INVERT_NV, GL_RGB );
  257. }
  258. // draw it
  259. qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_NV20_DIFFUSE_COLOR );
  260. RB_DrawElementsWithCounters( din->surf->geo );
  261. }
  262. /*
  263. ==================
  264. RB_NV20_SpecularColorFragment
  265. ==================
  266. */
  267. static void RB_NV20_SpecularColorFragment( void ) {
  268. if ( r_useCombinerDisplayLists.GetBool() ) {
  269. qglCallList( fragmentDisplayListBase + FPROG_SPECULAR_COLOR );
  270. return;
  271. }
  272. // program the nvidia register combiners
  273. qglCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 4 );
  274. // we want GL_CONSTANT_COLOR1_NV * PRIMARY_COLOR * TEXTURE2 * TEXTURE3 * specular( TEXTURE0 * TEXTURE1 )
  275. // stage 0 rgb performs the dot product
  276. // GL_SPARE0_NV = ( TEXTURE0 dot TEXTURE1 - 0.5 ) * 2
  277. // TEXTURE2 = TEXTURE2 * PRIMARY_COLOR
  278. // the scale and bias steepen the specular curve
  279. qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV,
  280. GL_TEXTURE1_ARB, GL_EXPAND_NORMAL_NV, GL_RGB );
  281. qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV,
  282. GL_TEXTURE0_ARB, GL_EXPAND_NORMAL_NV, GL_RGB );
  283. qglCombinerOutputNV( GL_COMBINER0_NV, GL_RGB,
  284. GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV,
  285. GL_SCALE_BY_TWO_NV, GL_BIAS_BY_NEGATIVE_ONE_HALF_NV, GL_TRUE, GL_FALSE, GL_FALSE );
  286. // stage 0 alpha does nothing
  287. // stage 1 color takes bump * bump
  288. // GL_SPARE0_NV = ( GL_SPARE0_NV * GL_SPARE0_NV - 0.5 ) * 2
  289. // the scale and bias steepen the specular curve
  290. qglCombinerInputNV( GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_A_NV,
  291. GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  292. qglCombinerInputNV( GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_B_NV,
  293. GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  294. qglCombinerOutputNV( GL_COMBINER1_NV, GL_RGB,
  295. GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV,
  296. GL_SCALE_BY_TWO_NV, GL_BIAS_BY_NEGATIVE_ONE_HALF_NV, GL_FALSE, GL_FALSE, GL_FALSE );
  297. // stage 1 alpha does nothing
  298. // stage 2 color
  299. // GL_SPARE0_NV = GL_SPARE0_NV * TEXTURE3
  300. // SECONDARY_COLOR = CONSTANT_COLOR * TEXTURE2
  301. qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_A_NV,
  302. GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  303. qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_B_NV,
  304. GL_TEXTURE3_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  305. qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_C_NV,
  306. GL_CONSTANT_COLOR1_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  307. qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_D_NV,
  308. GL_TEXTURE2_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  309. qglCombinerOutputNV( GL_COMBINER2_NV, GL_RGB,
  310. GL_SPARE0_NV, GL_SECONDARY_COLOR_NV, GL_DISCARD_NV,
  311. GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
  312. // stage 2 alpha does nothing
  313. // stage 3 scales the texture by the vertex color
  314. qglCombinerInputNV( GL_COMBINER3_NV, GL_RGB, GL_VARIABLE_A_NV,
  315. GL_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  316. qglCombinerInputNV( GL_COMBINER3_NV, GL_RGB, GL_VARIABLE_B_NV,
  317. GL_PRIMARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  318. qglCombinerOutputNV( GL_COMBINER3_NV, GL_RGB,
  319. GL_SECONDARY_COLOR_NV, GL_DISCARD_NV, GL_DISCARD_NV,
  320. GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
  321. // stage 3 alpha does nothing
  322. // final combiner = GL_SPARE0_NV * SECONDARY_COLOR + PRIMARY_COLOR * SECONDARY_COLOR
  323. qglFinalCombinerInputNV( GL_VARIABLE_A_NV, GL_SPARE0_NV,
  324. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  325. qglFinalCombinerInputNV( GL_VARIABLE_B_NV, GL_SECONDARY_COLOR_NV,
  326. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  327. qglFinalCombinerInputNV( GL_VARIABLE_C_NV, GL_ZERO,
  328. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  329. qglFinalCombinerInputNV( GL_VARIABLE_D_NV, GL_E_TIMES_F_NV,
  330. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  331. qglFinalCombinerInputNV( GL_VARIABLE_E_NV, GL_SPARE0_NV,
  332. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  333. qglFinalCombinerInputNV( GL_VARIABLE_F_NV, GL_SECONDARY_COLOR_NV,
  334. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  335. qglFinalCombinerInputNV( GL_VARIABLE_G_NV, GL_ZERO,
  336. GL_UNSIGNED_IDENTITY_NV, GL_ALPHA );
  337. }
  338. /*
  339. ==================
  340. RB_NV20_DI_SpecularColorPass
  341. ==================
  342. */
  343. static void RB_NV20_DI_SpecularColorPass( const drawInteraction_t *din ) {
  344. RB_LogComment( "---------- RB_NV20_SpecularColorPass ----------\n" );
  345. GL_State( GLS_SRCBLEND_DST_ALPHA | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | GLS_ALPHAMASK
  346. | backEnd.depthFunc );
  347. // texture 0 is the normalization cube map for the half angle
  348. #ifdef MACOS_X
  349. GL_SelectTexture( 0 );
  350. qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
  351. #else
  352. GL_SelectTextureNoClient( 0 );
  353. #endif
  354. globalImages->normalCubeMapImage->Bind();
  355. // texture 1 will be the per-surface bump map
  356. #ifdef MACOS_X
  357. GL_SelectTexture( 1 );
  358. qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
  359. #else
  360. GL_SelectTextureNoClient( 1 );
  361. #endif
  362. din->bumpImage->Bind();
  363. // texture 2 will be the per-surface specular map
  364. #ifdef MACOS_X
  365. GL_SelectTexture( 2 );
  366. qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
  367. #else
  368. GL_SelectTextureNoClient( 2 );
  369. #endif
  370. din->specularImage->Bind();
  371. // texture 3 will be the light projected texture
  372. #ifdef MACOS_X
  373. GL_SelectTexture( 3 );
  374. qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
  375. #else
  376. GL_SelectTextureNoClient( 3 );
  377. #endif
  378. din->lightImage->Bind();
  379. // bind our "fragment program"
  380. RB_NV20_SpecularColorFragment();
  381. // override one parameter for inverted vertex color
  382. if ( din->vertexColor == SVC_INVERSE_MODULATE ) {
  383. qglCombinerInputNV( GL_COMBINER3_NV, GL_RGB, GL_VARIABLE_B_NV,
  384. GL_PRIMARY_COLOR_NV, GL_UNSIGNED_INVERT_NV, GL_RGB );
  385. }
  386. // draw it
  387. qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_NV20_SPECULAR_COLOR );
  388. RB_DrawElementsWithCounters( din->surf->geo );
  389. }
  390. /*
  391. ==================
  392. RB_NV20_DiffuseAndSpecularColorFragment
  393. ==================
  394. */
  395. static void RB_NV20_DiffuseAndSpecularColorFragment( void ) {
  396. if ( r_useCombinerDisplayLists.GetBool() ) {
  397. qglCallList( fragmentDisplayListBase + FPROG_DIFFUSE_AND_SPECULAR_COLOR );
  398. return;
  399. }
  400. // program the nvidia register combiners
  401. qglCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 3 );
  402. // GL_CONSTANT_COLOR0_NV will be the diffuse color
  403. // GL_CONSTANT_COLOR1_NV will be the specular color
  404. // stage 0 rgb performs the dot product
  405. // GL_SECONDARY_COLOR_NV = ( TEXTURE0 dot TEXTURE1 - 0.5 ) * 2
  406. // the scale and bias steepen the specular curve
  407. qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV,
  408. GL_TEXTURE1_ARB, GL_EXPAND_NORMAL_NV, GL_RGB );
  409. qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV,
  410. GL_TEXTURE0_ARB, GL_EXPAND_NORMAL_NV, GL_RGB );
  411. qglCombinerOutputNV( GL_COMBINER0_NV, GL_RGB,
  412. GL_SECONDARY_COLOR_NV, GL_DISCARD_NV, GL_DISCARD_NV,
  413. GL_SCALE_BY_TWO_NV, GL_BIAS_BY_NEGATIVE_ONE_HALF_NV, GL_TRUE, GL_FALSE, GL_FALSE );
  414. // stage 0 alpha does nothing
  415. // stage 1 color takes bump * bump
  416. // PRIMARY_COLOR = ( GL_SECONDARY_COLOR_NV * GL_SECONDARY_COLOR_NV - 0.5 ) * 2
  417. // the scale and bias steepen the specular curve
  418. qglCombinerInputNV( GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_A_NV,
  419. GL_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  420. qglCombinerInputNV( GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_B_NV,
  421. GL_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  422. qglCombinerOutputNV( GL_COMBINER1_NV, GL_RGB,
  423. GL_SECONDARY_COLOR_NV, GL_DISCARD_NV, GL_DISCARD_NV,
  424. GL_SCALE_BY_TWO_NV, GL_BIAS_BY_NEGATIVE_ONE_HALF_NV, GL_FALSE, GL_FALSE, GL_FALSE );
  425. // stage 1 alpha does nothing
  426. // stage 2 color
  427. // PRIMARY_COLOR = ( PRIMARY_COLOR * TEXTURE3 ) * 2
  428. // SPARE0 = 1.0 * 1.0 (needed for final combiner)
  429. qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_A_NV,
  430. GL_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  431. qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_B_NV,
  432. GL_TEXTURE3_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  433. qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_C_NV,
  434. GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_RGB );
  435. qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_D_NV,
  436. GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_RGB );
  437. qglCombinerOutputNV( GL_COMBINER2_NV, GL_RGB,
  438. GL_SECONDARY_COLOR_NV, GL_SPARE0_NV, GL_DISCARD_NV,
  439. GL_SCALE_BY_TWO_NV, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
  440. // stage 2 alpha does nothing
  441. // final combiner = TEXTURE2_ARB * CONSTANT_COLOR0_NV + PRIMARY_COLOR_NV * CONSTANT_COLOR1_NV
  442. // alpha = GL_ZERO
  443. qglFinalCombinerInputNV( GL_VARIABLE_A_NV, GL_CONSTANT_COLOR1_NV,
  444. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  445. qglFinalCombinerInputNV( GL_VARIABLE_B_NV, GL_SECONDARY_COLOR_NV,
  446. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  447. qglFinalCombinerInputNV( GL_VARIABLE_C_NV, GL_ZERO,
  448. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  449. qglFinalCombinerInputNV( GL_VARIABLE_D_NV, GL_E_TIMES_F_NV,
  450. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  451. qglFinalCombinerInputNV( GL_VARIABLE_E_NV, GL_TEXTURE2_ARB,
  452. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  453. qglFinalCombinerInputNV( GL_VARIABLE_F_NV, GL_CONSTANT_COLOR0_NV,
  454. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  455. qglFinalCombinerInputNV( GL_VARIABLE_G_NV, GL_ZERO,
  456. GL_UNSIGNED_IDENTITY_NV, GL_ALPHA );
  457. }
  458. /*
  459. ==================
  460. RB_NV20_DI_DiffuseAndSpecularColorPass
  461. ==================
  462. */
  463. static void RB_NV20_DI_DiffuseAndSpecularColorPass( const drawInteraction_t *din ) {
  464. RB_LogComment( "---------- RB_NV20_DI_DiffuseAndSpecularColorPass ----------\n" );
  465. GL_State( GLS_SRCBLEND_DST_ALPHA | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | backEnd.depthFunc );
  466. // texture 0 is the normalization cube map for the half angle
  467. // still bound from RB_NV_BumpAndLightPass
  468. // GL_SelectTextureNoClient( 0 );
  469. // GL_Bind( tr.normalCubeMapImage );
  470. // texture 1 is the per-surface bump map
  471. // still bound from RB_NV_BumpAndLightPass
  472. // GL_SelectTextureNoClient( 1 );
  473. // GL_Bind( din->bumpImage );
  474. // texture 2 is the per-surface diffuse map
  475. #ifdef MACOS_X
  476. GL_SelectTexture( 2 );
  477. qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
  478. #else
  479. GL_SelectTextureNoClient( 2 );
  480. #endif
  481. din->diffuseImage->Bind();
  482. // texture 3 is the per-surface specular map
  483. #ifdef MACOS_X
  484. GL_SelectTexture( 3 );
  485. qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
  486. #else
  487. GL_SelectTextureNoClient( 3 );
  488. #endif
  489. din->specularImage->Bind();
  490. // bind our "fragment program"
  491. RB_NV20_DiffuseAndSpecularColorFragment();
  492. // draw it
  493. qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_NV20_DIFFUSE_AND_SPECULAR_COLOR );
  494. RB_DrawElementsWithCounters( din->surf->geo );
  495. }
  496. /*
  497. ==================
  498. RB_NV20_DrawInteraction
  499. ==================
  500. */
  501. static void RB_NV20_DrawInteraction( const drawInteraction_t *din ) {
  502. const drawSurf_t *surf = din->surf;
  503. // load all the vertex program parameters
  504. qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_ORIGIN, din->localLightOrigin.ToFloatPtr() );
  505. qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_VIEW_ORIGIN, din->localViewOrigin.ToFloatPtr() );
  506. qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_PROJECT_S, din->lightProjection[0].ToFloatPtr() );
  507. qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_PROJECT_T, din->lightProjection[1].ToFloatPtr() );
  508. qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_PROJECT_Q, din->lightProjection[2].ToFloatPtr() );
  509. qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_FALLOFF_S, din->lightProjection[3].ToFloatPtr() );
  510. qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_BUMP_MATRIX_S, din->bumpMatrix[0].ToFloatPtr() );
  511. qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_BUMP_MATRIX_T, din->bumpMatrix[1].ToFloatPtr() );
  512. qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_DIFFUSE_MATRIX_S, din->diffuseMatrix[0].ToFloatPtr() );
  513. qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_DIFFUSE_MATRIX_T, din->diffuseMatrix[1].ToFloatPtr() );
  514. qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_SPECULAR_MATRIX_S, din->specularMatrix[0].ToFloatPtr() );
  515. qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_SPECULAR_MATRIX_T, din->specularMatrix[1].ToFloatPtr() );
  516. // set the constant colors
  517. qglCombinerParameterfvNV( GL_CONSTANT_COLOR0_NV, din->diffuseColor.ToFloatPtr() );
  518. qglCombinerParameterfvNV( GL_CONSTANT_COLOR1_NV, din->specularColor.ToFloatPtr() );
  519. // vertex color passes should be pretty rare (cross-faded bump map surfaces), so always
  520. // run them down as three-passes
  521. if ( din->vertexColor != SVC_IGNORE ) {
  522. qglEnableClientState( GL_COLOR_ARRAY );
  523. RB_NV20_DI_BumpAndLightPass( din, false );
  524. RB_NV20_DI_DiffuseColorPass( din );
  525. RB_NV20_DI_SpecularColorPass( din );
  526. qglDisableClientState( GL_COLOR_ARRAY );
  527. return;
  528. }
  529. qglColor3f( 1, 1, 1 );
  530. // on an ideal card, we would now just bind the textures and call a
  531. // single pass vertex / fragment program, but
  532. // on NV20, we need to decide which single / dual / tripple pass set of programs to use
  533. // ambient light could be done as a single pass if we want to optimize for it
  534. // monochrome light is two passes
  535. int internalFormat = din->lightImage->internalFormat;
  536. if ( ( r_useNV20MonoLights.GetInteger() == 2 ) ||
  537. ( din->lightImage->isMonochrome && r_useNV20MonoLights.GetInteger() ) ) {
  538. // do a two-pass rendering
  539. RB_NV20_DI_BumpAndLightPass( din, true );
  540. RB_NV20_DI_DiffuseAndSpecularColorPass( din );
  541. } else {
  542. // general case is three passes
  543. // ( bump dot lightDir ) * lightFalloff
  544. // diffuse * lightProject
  545. // specular * ( bump dot halfAngle extended ) * lightProject
  546. RB_NV20_DI_BumpAndLightPass( din, false );
  547. RB_NV20_DI_DiffuseColorPass( din );
  548. RB_NV20_DI_SpecularColorPass( din );
  549. }
  550. }
  551. /*
  552. =============
  553. RB_NV20_CreateDrawInteractions
  554. =============
  555. */
  556. static void RB_NV20_CreateDrawInteractions( const drawSurf_t *surf ) {
  557. if ( !surf ) {
  558. return;
  559. }
  560. qglEnable( GL_VERTEX_PROGRAM_ARB );
  561. qglEnable( GL_REGISTER_COMBINERS_NV );
  562. #ifdef MACOS_X
  563. GL_SelectTexture(0);
  564. qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
  565. #else
  566. qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
  567. qglEnableVertexAttribArrayARB( 8 );
  568. qglEnableVertexAttribArrayARB( 9 );
  569. qglEnableVertexAttribArrayARB( 10 );
  570. qglEnableVertexAttribArrayARB( 11 );
  571. #endif
  572. for ( ; surf ; surf=surf->nextOnLight ) {
  573. // set the vertex pointers
  574. idDrawVert *ac = (idDrawVert *)vertexCache.Position( surf->geo->ambientCache );
  575. qglColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( idDrawVert ), ac->color );
  576. #ifdef MACOS_X
  577. GL_SelectTexture( 0 );
  578. qglTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ), ac->st.ToFloatPtr() );
  579. GL_SelectTexture( 1 );
  580. qglTexCoordPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->tangents[0].ToFloatPtr() );
  581. GL_SelectTexture( 2 );
  582. qglTexCoordPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->tangents[1].ToFloatPtr() );
  583. GL_SelectTexture( 3 );
  584. qglTexCoordPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->normal.ToFloatPtr() );
  585. GL_SelectTexture( 0 );
  586. #else
  587. qglVertexAttribPointerARB( 11, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->normal.ToFloatPtr() );
  588. qglVertexAttribPointerARB( 10, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->tangents[1].ToFloatPtr() );
  589. qglVertexAttribPointerARB( 9, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->tangents[0].ToFloatPtr() );
  590. qglVertexAttribPointerARB( 8, 2, GL_FLOAT, false, sizeof( idDrawVert ), ac->st.ToFloatPtr() );
  591. #endif
  592. qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() );
  593. RB_CreateSingleDrawInteractions( surf, RB_NV20_DrawInteraction );
  594. }
  595. #ifndef MACOS_X
  596. qglDisableVertexAttribArrayARB( 8 );
  597. qglDisableVertexAttribArrayARB( 9 );
  598. qglDisableVertexAttribArrayARB( 10 );
  599. qglDisableVertexAttribArrayARB( 11 );
  600. #endif
  601. // disable features
  602. #ifdef MACOS_X
  603. GL_SelectTexture( 3 );
  604. globalImages->BindNull();
  605. qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
  606. GL_SelectTexture( 2 );
  607. globalImages->BindNull();
  608. qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
  609. GL_SelectTexture( 1 );
  610. globalImages->BindNull();
  611. qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
  612. #else
  613. GL_SelectTextureNoClient( 3 );
  614. globalImages->BindNull();
  615. GL_SelectTextureNoClient( 2 );
  616. globalImages->BindNull();
  617. GL_SelectTextureNoClient( 1 );
  618. globalImages->BindNull();
  619. #endif
  620. backEnd.glState.currenttmu = -1;
  621. GL_SelectTexture( 0 );
  622. qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
  623. qglDisable( GL_VERTEX_PROGRAM_ARB );
  624. qglDisable( GL_REGISTER_COMBINERS_NV );
  625. }
  626. //======================================================================================
  627. /*
  628. ==================
  629. RB_NV20_DrawInteractions
  630. ==================
  631. */
  632. void RB_NV20_DrawInteractions( void ) {
  633. viewLight_t *vLight;
  634. //
  635. // for each light, perform adding and shadowing
  636. //
  637. for ( vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) {
  638. // do fogging later
  639. if ( vLight->lightShader->IsFogLight() ) {
  640. continue;
  641. }
  642. if ( vLight->lightShader->IsBlendLight() ) {
  643. continue;
  644. }
  645. if ( !vLight->localInteractions && !vLight->globalInteractions
  646. && !vLight->translucentInteractions ) {
  647. continue;
  648. }
  649. backEnd.vLight = vLight;
  650. RB_LogComment( "---------- RB_RenderViewLight 0x%p ----------\n", vLight );
  651. // clear the stencil buffer if needed
  652. if ( vLight->globalShadows || vLight->localShadows ) {
  653. backEnd.currentScissor = vLight->scissorRect;
  654. if ( r_useScissor.GetBool() ) {
  655. qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1,
  656. backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1,
  657. backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1,
  658. backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 );
  659. }
  660. qglClear( GL_STENCIL_BUFFER_BIT );
  661. } else {
  662. // no shadows, so no need to read or write the stencil buffer
  663. // we might in theory want to use GL_ALWAYS instead of disabling
  664. // completely, to satisfy the invarience rules
  665. qglStencilFunc( GL_ALWAYS, 128, 255 );
  666. }
  667. backEnd.depthFunc = GLS_DEPTHFUNC_EQUAL;
  668. if ( r_useShadowVertexProgram.GetBool() ) {
  669. qglEnable( GL_VERTEX_PROGRAM_ARB );
  670. qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_STENCIL_SHADOW );
  671. RB_StencilShadowPass( vLight->globalShadows );
  672. RB_NV20_CreateDrawInteractions( vLight->localInteractions );
  673. qglEnable( GL_VERTEX_PROGRAM_ARB );
  674. qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_STENCIL_SHADOW );
  675. RB_StencilShadowPass( vLight->localShadows );
  676. RB_NV20_CreateDrawInteractions( vLight->globalInteractions );
  677. qglDisable( GL_VERTEX_PROGRAM_ARB ); // if there weren't any globalInteractions, it would have stayed on
  678. } else {
  679. RB_StencilShadowPass( vLight->globalShadows );
  680. RB_NV20_CreateDrawInteractions( vLight->localInteractions );
  681. RB_StencilShadowPass( vLight->localShadows );
  682. RB_NV20_CreateDrawInteractions( vLight->globalInteractions );
  683. }
  684. // translucent surfaces never get stencil shadowed
  685. if ( r_skipTranslucent.GetBool() ) {
  686. continue;
  687. }
  688. qglStencilFunc( GL_ALWAYS, 128, 255 );
  689. backEnd.depthFunc = GLS_DEPTHFUNC_LESS;
  690. RB_NV20_CreateDrawInteractions( vLight->translucentInteractions );
  691. backEnd.depthFunc = GLS_DEPTHFUNC_EQUAL;
  692. }
  693. }
  694. //=======================================================================
  695. /*
  696. ==================
  697. R_NV20_Init
  698. ==================
  699. */
  700. void R_NV20_Init( void ) {
  701. glConfig.allowNV20Path = false;
  702. common->Printf( "---------- R_NV20_Init ----------\n" );
  703. if ( !glConfig.registerCombinersAvailable || !glConfig.ARBVertexProgramAvailable || glConfig.maxTextureUnits < 4 ) {
  704. common->Printf( "Not available.\n" );
  705. return;
  706. }
  707. GL_CheckErrors();
  708. // create our "fragment program" display lists
  709. fragmentDisplayListBase = qglGenLists( FPROG_NUM_FRAGMENT_PROGRAMS );
  710. // force them to issue commands to build the list
  711. bool temp = r_useCombinerDisplayLists.GetBool();
  712. r_useCombinerDisplayLists.SetBool( false );
  713. qglNewList( fragmentDisplayListBase + FPROG_BUMP_AND_LIGHT, GL_COMPILE );
  714. RB_NV20_BumpAndLightFragment();
  715. qglEndList();
  716. qglNewList( fragmentDisplayListBase + FPROG_DIFFUSE_COLOR, GL_COMPILE );
  717. RB_NV20_DiffuseColorFragment();
  718. qglEndList();
  719. qglNewList( fragmentDisplayListBase + FPROG_SPECULAR_COLOR, GL_COMPILE );
  720. RB_NV20_SpecularColorFragment();
  721. qglEndList();
  722. qglNewList( fragmentDisplayListBase + FPROG_DIFFUSE_AND_SPECULAR_COLOR, GL_COMPILE );
  723. RB_NV20_DiffuseAndSpecularColorFragment();
  724. qglEndList();
  725. r_useCombinerDisplayLists.SetBool( temp );
  726. common->Printf( "---------------------------------\n" );
  727. glConfig.allowNV20Path = true;
  728. }