draw_nv10.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  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. /*
  24. ==================
  25. RB_RenderInteraction
  26. backEnd.vLight
  27. backEnd.lightScale
  28. backEnd.depthFunc must be equal for alpha tested surfaces to work right,
  29. it is set to lessThan for blended transparent surfaces
  30. This expects a bumpmap stage before a diffuse stage before a specular stage
  31. The material code is responsible for guaranteeing that, but conditional stages
  32. can still make it invalid.
  33. you can't blend two bumpmaps, but you can change bump maps between
  34. blended diffuse / specular maps to get the same effect
  35. ==================
  36. */
  37. static void RB_RenderInteraction( const drawSurf_t *surf ) {
  38. const idMaterial *surfaceShader = surf->material;
  39. const float *surfaceRegs = surf->shaderRegisters;
  40. const viewLight_t *vLight = backEnd.vLight;
  41. const idMaterial *lightShader = vLight->lightShader;
  42. const float *lightRegs = vLight->shaderRegisters;
  43. static idPlane lightProject[4]; // reused across function calls
  44. const srfTriangles_t *tri = surf->geo;
  45. const shaderStage_t *lastBumpStage = NULL;
  46. RB_LogComment( "---------- RB_RenderInteraction %s on %s ----------\n",
  47. lightShader->GetName(), surfaceShader->GetName() );
  48. // change the matrix and light projection vectors if needed
  49. if ( surf->space != backEnd.currentSpace ) {
  50. backEnd.currentSpace = surf->space;
  51. qglLoadMatrixf( surf->space->modelViewMatrix );
  52. for ( int i = 0 ; i < 4 ; i++ ) {
  53. R_GlobalPlaneToLocal( surf->space->modelMatrix, backEnd.vLight->lightProject[i], lightProject[i] );
  54. }
  55. }
  56. // change the scissor if needed
  57. if ( r_useScissor.GetBool() && !backEnd.currentScissor.Equals( surf->scissorRect ) ) {
  58. backEnd.currentScissor = surf->scissorRect;
  59. qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1,
  60. backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1,
  61. backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1,
  62. backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 );
  63. }
  64. // hack depth range if needed
  65. if ( surf->space->weaponDepthHack ) {
  66. RB_EnterWeaponDepthHack();
  67. }
  68. if ( surf->space->modelDepthHack != 0.0f ) {
  69. RB_EnterModelDepthHack( surf->space->modelDepthHack );
  70. }
  71. // set the vertex arrays, which may not all be enabled on a given pass
  72. idDrawVert *ac = (idDrawVert *)vertexCache.Position(tri->ambientCache);
  73. qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() );
  74. GL_SelectTexture( 0 );
  75. qglTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ), ac->st.ToFloatPtr() );
  76. qglColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( idDrawVert ), ac->color );
  77. // go through the individual stages
  78. for ( int i = 0 ; i < surfaceShader->GetNumStages() ; i++ ) {
  79. const shaderStage_t *surfaceStage = surfaceShader->GetStage( i );
  80. // ignore ambient stages while drawing interactions
  81. if ( surfaceStage->lighting == SL_AMBIENT ) {
  82. continue;
  83. }
  84. // ignore stages that fail the condition
  85. if ( !surfaceRegs[ surfaceStage->conditionRegister ] ) {
  86. continue;
  87. }
  88. //-----------------------------------------------------
  89. //
  90. // bump / falloff
  91. //
  92. //-----------------------------------------------------
  93. if ( surfaceStage->lighting == SL_BUMP ) {
  94. // render light falloff * bumpmap lighting
  95. if ( surfaceStage->vertexColor != SVC_IGNORE ) {
  96. common->Printf( "shader %s: vertexColor on a bump stage\n",
  97. surfaceShader->GetName() );
  98. }
  99. // check for RGBA modulations in the stage, which are also illegal?
  100. // save the bump map stage for the specular calculation and diffuse
  101. // error checking
  102. lastBumpStage = surfaceStage;
  103. //
  104. // ambient lights combine non-directional bump and falloff
  105. // and write to the alpha channel
  106. //
  107. if ( lightShader->IsAmbientLight() ) {
  108. GL_State( GLS_COLORMASK | GLS_DEPTHMASK | backEnd.depthFunc );
  109. // texture 0 will be the per-surface bump map
  110. GL_SelectTexture( 0 );
  111. qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
  112. RB_BindStageTexture( surfaceRegs, &surfaceStage->texture, surf );
  113. // development aid
  114. if ( r_skipBump.GetBool() ) {
  115. globalImages->flatNormalMap->Bind();
  116. }
  117. // texture 1 will be the light falloff
  118. GL_SelectTexture( 1 );
  119. qglEnable( GL_TEXTURE_GEN_S );
  120. qglTexGenfv( GL_S, GL_OBJECT_PLANE, lightProject[3].ToFloatPtr() );
  121. qglTexCoord2f( 0, 0.5 );
  122. vLight->falloffImage->Bind();
  123. qglCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 2 );
  124. // set the constant color to a bit of an angle
  125. qglCombinerParameterfvNV( GL_CONSTANT_COLOR0_NV, tr.ambientLightVector.ToFloatPtr() );
  126. // stage 0 sets primary_color = bump dot constant color
  127. qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV,
  128. GL_CONSTANT_COLOR0_NV, GL_EXPAND_NORMAL_NV, GL_RGB );
  129. qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV,
  130. GL_TEXTURE0_ARB, GL_EXPAND_NORMAL_NV, GL_RGB );
  131. qglCombinerOutputNV( GL_COMBINER0_NV, GL_RGB,
  132. GL_PRIMARY_COLOR_NV, GL_DISCARD_NV, GL_DISCARD_NV,
  133. GL_NONE, GL_NONE, GL_TRUE, GL_FALSE, GL_FALSE );
  134. // stage 1 alpha sets primary_color = primary_color * falloff
  135. qglCombinerInputNV( GL_COMBINER1_NV, GL_ALPHA, GL_VARIABLE_A_NV,
  136. GL_PRIMARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_BLUE );
  137. qglCombinerInputNV( GL_COMBINER1_NV, GL_ALPHA, GL_VARIABLE_B_NV,
  138. GL_TEXTURE1_ARB, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA );
  139. qglCombinerOutputNV( GL_COMBINER1_NV, GL_ALPHA,
  140. GL_PRIMARY_COLOR_NV, GL_DISCARD_NV, GL_DISCARD_NV,
  141. GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
  142. // final combiner takes the result for the alpha channel
  143. qglFinalCombinerInputNV( GL_VARIABLE_A_NV, GL_ZERO,
  144. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  145. qglFinalCombinerInputNV( GL_VARIABLE_B_NV, GL_ZERO,
  146. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  147. qglFinalCombinerInputNV( GL_VARIABLE_C_NV, GL_ZERO,
  148. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  149. qglFinalCombinerInputNV( GL_VARIABLE_D_NV, GL_ZERO,
  150. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  151. qglFinalCombinerInputNV( GL_VARIABLE_G_NV, GL_PRIMARY_COLOR_NV,
  152. GL_UNSIGNED_IDENTITY_NV, GL_ALPHA );
  153. // draw it
  154. RB_DrawElementsWithCounters( tri );
  155. globalImages->BindNull();
  156. qglDisable( GL_TEXTURE_GEN_S );
  157. GL_SelectTexture( 0 );
  158. RB_FinishStageTexture( &surfaceStage->texture, surf );
  159. continue;
  160. }
  161. //
  162. // draw light falloff to the alpha channel
  163. //
  164. GL_State( GLS_COLORMASK | GLS_DEPTHMASK | backEnd.depthFunc );
  165. qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
  166. qglDisableClientState( GL_COLOR_ARRAY );
  167. qglEnable( GL_TEXTURE_GEN_S );
  168. qglTexGenfv( GL_S, GL_OBJECT_PLANE, lightProject[3].ToFloatPtr() );
  169. qglTexCoord2f( 0, 0.5 );
  170. vLight->falloffImage->Bind();
  171. // make sure a combiner output doesn't step on the texture
  172. qglCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 1 );
  173. qglCombinerOutputNV( GL_COMBINER0_NV, GL_ALPHA,
  174. GL_DISCARD_NV, GL_DISCARD_NV, GL_DISCARD_NV,
  175. GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
  176. // final combiner
  177. qglFinalCombinerInputNV( GL_VARIABLE_A_NV, GL_ZERO,
  178. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  179. qglFinalCombinerInputNV( GL_VARIABLE_B_NV, GL_ZERO,
  180. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  181. qglFinalCombinerInputNV( GL_VARIABLE_C_NV, GL_ZERO,
  182. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  183. qglFinalCombinerInputNV( GL_VARIABLE_D_NV, GL_ZERO,
  184. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  185. qglFinalCombinerInputNV( GL_VARIABLE_G_NV, GL_TEXTURE0_ARB,
  186. GL_UNSIGNED_IDENTITY_NV, GL_ALPHA );
  187. // draw it
  188. RB_DrawElementsWithCounters( tri );
  189. qglDisable( GL_TEXTURE_GEN_S );
  190. //
  191. // draw the bump map result onto the alpha channel
  192. //
  193. GL_State( GLS_SRCBLEND_DST_ALPHA | GLS_DSTBLEND_ZERO | GLS_COLORMASK | GLS_DEPTHMASK
  194. | backEnd.depthFunc );
  195. // texture 0 will be the per-surface bump map
  196. GL_SelectTexture( 0 );
  197. qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
  198. RB_BindStageTexture( surfaceRegs, &surfaceStage->texture, surf );
  199. // texture 1 is the normalization cube map
  200. // the texccords are the non-normalized vector towards the light origin
  201. GL_SelectTexture( 1 );
  202. globalImages->normalCubeMapImage->Bind();
  203. qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
  204. qglTexCoordPointer( 3, GL_FLOAT, sizeof( lightingCache_t ), ((lightingCache_t *)vertexCache.Position(tri->lightingCache))->localLightVector.ToFloatPtr() );
  205. qglDisableClientState( GL_COLOR_ARRAY );
  206. // program the nvidia register combiners
  207. // I just want alpha = Dot( texture0, texture1 )
  208. qglCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 1 );
  209. // stage 0 rgb performs the dot product
  210. // SPARE0 = TEXTURE0 dot TEXTURE1
  211. qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV,
  212. GL_TEXTURE1_ARB, GL_EXPAND_NORMAL_NV, GL_RGB );
  213. qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV,
  214. GL_TEXTURE0_ARB, GL_EXPAND_NORMAL_NV, GL_RGB );
  215. qglCombinerOutputNV( GL_COMBINER0_NV, GL_RGB,
  216. GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV,
  217. GL_NONE, GL_NONE, GL_TRUE, GL_FALSE, GL_FALSE );
  218. // final combiner just takes the dot result and puts it in alpha
  219. qglFinalCombinerInputNV( GL_VARIABLE_G_NV, GL_SPARE0_NV,
  220. GL_UNSIGNED_IDENTITY_NV, GL_BLUE );
  221. // draw it
  222. RB_DrawElementsWithCounters( tri );
  223. globalImages->BindNull();
  224. qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
  225. GL_SelectTexture( 0 );
  226. RB_FinishStageTexture( &surfaceStage->texture, surf );
  227. continue;
  228. }
  229. if ( surfaceStage->lighting == SL_DIFFUSE ) {
  230. if ( !lastBumpStage ) {
  231. common->Printf( "shader %s: diffuse stage without a preceeding bumpmap stage\n",
  232. surfaceShader->GetName() );
  233. continue;
  234. }
  235. }
  236. //-----------------------------------------------------
  237. //
  238. // specular exponent modification of the bump / falloff
  239. //
  240. //-----------------------------------------------------
  241. if ( surfaceStage->lighting == SL_SPECULAR ) {
  242. // put specular bump map into alpha channel, then treat as a diffuse
  243. // allow the specular to be skipped as a user speed optimization
  244. if ( r_skipSpecular.GetBool() ) {
  245. continue;
  246. }
  247. // ambient lights don't have specular
  248. if ( lightShader->IsAmbientLight() ) {
  249. continue;
  250. }
  251. if ( !lastBumpStage ) {
  252. common->Printf( "shader %s: specular stage without a preceeding bumpmap stage\n",
  253. surfaceShader->GetName() );
  254. continue;
  255. }
  256. GL_State( GLS_SRCBLEND_DST_ALPHA | GLS_DSTBLEND_SRC_ALPHA | GLS_COLORMASK | GLS_DEPTHMASK
  257. | backEnd.depthFunc );
  258. // texture 0 will be the per-surface bump map
  259. GL_SelectTexture( 0 );
  260. qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
  261. RB_BindStageTexture( surfaceRegs, &lastBumpStage->texture, surf );
  262. // development aid
  263. if ( r_skipBump.GetBool() ) {
  264. globalImages->flatNormalMap->Bind();
  265. }
  266. // texture 1 is the normalization cube map
  267. // indexed by the dynamic halfangle texcoords
  268. GL_SelectTexture( 1 );
  269. globalImages->normalCubeMapImage->Bind();
  270. qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
  271. qglTexCoordPointer( 4, GL_FLOAT, 0, vertexCache.Position( surf->dynamicTexCoords ) );
  272. // program the nvidia register combiners
  273. qglCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 2 );
  274. // stage 0 rgb performs the dot product
  275. // GL_PRIMARY_COLOR_NV = ( TEXTURE0 dot TEXTURE1 - 0.5 ) * 2
  276. // the scale and bias steepen the specular curve
  277. qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV,
  278. GL_TEXTURE1_ARB, GL_EXPAND_NORMAL_NV, GL_RGB );
  279. qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV,
  280. GL_TEXTURE0_ARB, GL_EXPAND_NORMAL_NV, GL_RGB );
  281. qglCombinerOutputNV( GL_COMBINER0_NV, GL_RGB,
  282. GL_PRIMARY_COLOR_NV, GL_DISCARD_NV, GL_DISCARD_NV,
  283. GL_SCALE_BY_TWO_NV, GL_BIAS_BY_NEGATIVE_ONE_HALF_NV, GL_TRUE, GL_FALSE, GL_FALSE );
  284. // stage 0 alpha does nothing
  285. qglCombinerOutputNV( GL_COMBINER0_NV, GL_ALPHA,
  286. GL_DISCARD_NV, GL_DISCARD_NV, GL_DISCARD_NV,
  287. GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
  288. // stage 1 rgb does nothing
  289. qglCombinerOutputNV( GL_COMBINER1_NV, GL_RGB,
  290. GL_PRIMARY_COLOR_NV, GL_DISCARD_NV, GL_DISCARD_NV,
  291. GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
  292. // stage 1 alpha takes bump * bump
  293. // PRIMARY_COLOR = ( GL_PRIMARY_COLOR_NV * GL_PRIMARY_COLOR_NV - 0.5 ) * 2
  294. // the scale and bias steepen the specular curve
  295. qglCombinerInputNV( GL_COMBINER1_NV, GL_ALPHA, GL_VARIABLE_A_NV,
  296. GL_PRIMARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_BLUE );
  297. qglCombinerInputNV( GL_COMBINER1_NV, GL_ALPHA, GL_VARIABLE_B_NV,
  298. GL_PRIMARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_BLUE );
  299. qglCombinerOutputNV( GL_COMBINER1_NV, GL_ALPHA,
  300. GL_PRIMARY_COLOR_NV, GL_DISCARD_NV, GL_DISCARD_NV,
  301. GL_SCALE_BY_TWO_NV, GL_BIAS_BY_NEGATIVE_ONE_HALF_NV, GL_FALSE, GL_FALSE, GL_FALSE );
  302. // final combiner
  303. qglFinalCombinerInputNV( GL_VARIABLE_D_NV, GL_PRIMARY_COLOR_NV,
  304. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  305. qglFinalCombinerInputNV( GL_VARIABLE_A_NV, GL_ZERO,
  306. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  307. qglFinalCombinerInputNV( GL_VARIABLE_B_NV, GL_ZERO,
  308. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  309. qglFinalCombinerInputNV( GL_VARIABLE_C_NV, GL_ZERO,
  310. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  311. qglFinalCombinerInputNV( GL_VARIABLE_G_NV, GL_PRIMARY_COLOR_NV,
  312. GL_UNSIGNED_IDENTITY_NV, GL_ALPHA );
  313. // draw it
  314. RB_DrawElementsWithCounters( tri );
  315. globalImages->BindNull();
  316. qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
  317. GL_SelectTexture( 0 );
  318. RB_FinishStageTexture( &lastBumpStage->texture, surf );
  319. // the bump map in the alpha channel is now corrupted, so a normal diffuse
  320. // map can't be drawn unless a new bumpmap is put down
  321. lastBumpStage = NULL;
  322. // fall through to the common handling of diffuse and specular projected lighting
  323. }
  324. //-----------------------------------------------------
  325. //
  326. // projected light / surface color for diffuse and specular maps
  327. //
  328. //-----------------------------------------------------
  329. if ( surfaceStage->lighting == SL_DIFFUSE || surfaceStage->lighting == SL_SPECULAR ) {
  330. // don't trash alpha
  331. GL_State( GLS_SRCBLEND_DST_ALPHA | GLS_DSTBLEND_ONE | GLS_ALPHAMASK | GLS_DEPTHMASK
  332. | backEnd.depthFunc );
  333. // texture 0 will get the surface color texture
  334. GL_SelectTexture( 0 );
  335. qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
  336. RB_BindStageTexture( surfaceRegs, &surfaceStage->texture, surf );
  337. // development aid
  338. if ( ( surfaceStage->lighting == SL_DIFFUSE && r_skipDiffuse.GetBool() )
  339. || ( surfaceStage->lighting == SL_SPECULAR && r_skipSpecular.GetBool() ) ) {
  340. globalImages->blackImage->Bind();
  341. }
  342. // texture 1 will get the light projected texture
  343. GL_SelectTexture( 1 );
  344. qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
  345. qglEnable( GL_TEXTURE_GEN_S );
  346. qglEnable( GL_TEXTURE_GEN_T );
  347. qglEnable( GL_TEXTURE_GEN_Q );
  348. qglTexGenfv( GL_S, GL_OBJECT_PLANE, lightProject[0].ToFloatPtr() );
  349. qglTexGenfv( GL_T, GL_OBJECT_PLANE, lightProject[1].ToFloatPtr() );
  350. qglTexGenfv( GL_Q, GL_OBJECT_PLANE, lightProject[2].ToFloatPtr() );
  351. // texture0 * texture1 * primaryColor * constantColor
  352. qglCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 1 );
  353. // SPARE0 = TEXTURE0 * PRIMARY_COLOR
  354. // SPARE1 = TEXTURE1 * CONSTANT_COLOR
  355. qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV,
  356. GL_TEXTURE0_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  357. // variable B will be overriden based on the stage vertexColor option
  358. if ( surfaceStage->vertexColor == SVC_MODULATE ) {
  359. qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV,
  360. GL_PRIMARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  361. qglEnableClientState( GL_COLOR_ARRAY );
  362. } else if ( surfaceStage->vertexColor == SVC_INVERSE_MODULATE ) {
  363. qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV,
  364. GL_PRIMARY_COLOR_NV, GL_UNSIGNED_INVERT_NV, GL_RGB );
  365. qglEnableClientState( GL_COLOR_ARRAY );
  366. } else { // SVC_IGNORE
  367. qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV,
  368. GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_RGB );
  369. qglDisableClientState( GL_COLOR_ARRAY );
  370. }
  371. qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_C_NV,
  372. GL_TEXTURE1_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  373. qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_D_NV,
  374. GL_CONSTANT_COLOR1_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  375. qglCombinerOutputNV( GL_COMBINER0_NV, GL_RGB,
  376. GL_SPARE0_NV, GL_SPARE1_NV, GL_DISCARD_NV,
  377. GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
  378. // final combiner
  379. qglFinalCombinerInputNV( GL_VARIABLE_A_NV, GL_SPARE1_NV,
  380. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  381. qglFinalCombinerInputNV( GL_VARIABLE_B_NV, GL_SPARE0_NV,
  382. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  383. qglFinalCombinerInputNV( GL_VARIABLE_C_NV, GL_ZERO,
  384. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  385. qglFinalCombinerInputNV( GL_VARIABLE_D_NV, GL_ZERO,
  386. GL_UNSIGNED_IDENTITY_NV, GL_RGB );
  387. qglFinalCombinerInputNV( GL_VARIABLE_G_NV, GL_ZERO,
  388. GL_UNSIGNED_IDENTITY_NV, GL_ALPHA );
  389. // for all light stages, multiply the projected color by the surface
  390. // color, and blend with the framebuffer
  391. for ( int j = 0 ; j < lightShader->GetNumStages() ; j++ ) {
  392. const shaderStage_t *lightStage = lightShader->GetStage( j );
  393. float color[4];
  394. // ignore stages that fail the condition
  395. if ( !lightRegs[ lightStage->conditionRegister ] ) {
  396. continue;
  397. }
  398. // set the color to the light color times the surface color
  399. color[0] = backEnd.lightScale
  400. * lightRegs[ lightStage->color.registers[0] ]
  401. * surfaceRegs[ surfaceStage->color.registers[0] ];
  402. color[1] = backEnd.lightScale
  403. * lightRegs[ lightStage->color.registers[1] ]
  404. * surfaceRegs[ surfaceStage->color.registers[1] ];
  405. color[2] = backEnd.lightScale
  406. * lightRegs[ lightStage->color.registers[2] ]
  407. * surfaceRegs[ surfaceStage->color.registers[2] ];
  408. color[3] = 1;
  409. // don't draw if it would be all black
  410. if ( color[0] == 0 && color[1] == 0 && color[2] == 0 ) {
  411. continue;
  412. }
  413. qglCombinerParameterfvNV( GL_CONSTANT_COLOR1_NV, color );
  414. RB_BindStageTexture( lightRegs, &lightStage->texture, surf );
  415. RB_DrawElementsWithCounters( tri );
  416. RB_FinishStageTexture( &lightStage->texture, surf );
  417. }
  418. if ( surfaceStage->vertexColor != SVC_IGNORE ) {
  419. qglDisableClientState( GL_COLOR_ARRAY );
  420. }
  421. qglDisable( GL_TEXTURE_GEN_S );
  422. qglDisable( GL_TEXTURE_GEN_T );
  423. qglDisable( GL_TEXTURE_GEN_Q );
  424. globalImages->BindNull();
  425. GL_SelectTexture( 0 );
  426. RB_FinishStageTexture( &surfaceStage->texture, surf );
  427. continue;
  428. }
  429. }
  430. // unhack depth range if needed
  431. if ( surf->space->weaponDepthHack || surf->space->modelDepthHack != 0.0f ) {
  432. RB_LeaveDepthHack();
  433. }
  434. }
  435. /*
  436. ==================
  437. RB_RenderInteractionList
  438. ==================
  439. */
  440. static void RB_RenderInteractionList( const drawSurf_t *surf ) {
  441. if ( !surf ) {
  442. return;
  443. }
  444. qglEnable( GL_REGISTER_COMBINERS_NV );
  445. // force a space calculation for light vectors
  446. backEnd.currentSpace = NULL;
  447. for ( const drawSurf_t *s = surf ; s ; s = s->nextOnLight ) {
  448. RB_RenderInteraction( s );
  449. }
  450. qglDisable( GL_REGISTER_COMBINERS_NV );
  451. }
  452. /*
  453. ==================
  454. RB_RenderViewLight
  455. ==================
  456. */
  457. static void RB_RenderViewLight( viewLight_t *vLight ) {
  458. backEnd.vLight = vLight;
  459. // do fogging later
  460. if ( vLight->lightShader->IsFogLight() ) {
  461. return;
  462. }
  463. if ( vLight->lightShader->IsBlendLight() ) {
  464. return;
  465. }
  466. RB_LogComment( "---------- RB_RenderViewLight 0x%p ----------\n", vLight );
  467. // clear the stencil buffer if needed
  468. if ( vLight->globalShadows || vLight->localShadows ) {
  469. backEnd.currentScissor = vLight->scissorRect;
  470. if ( r_useScissor.GetBool() ) {
  471. qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1,
  472. backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1,
  473. backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1,
  474. backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 );
  475. }
  476. qglClear( GL_STENCIL_BUFFER_BIT );
  477. } else {
  478. // no shadows, so no need to read or write the stencil buffer
  479. // we might in theory want to use GL_ALWAYS instead of disabling
  480. // completely, to satisfy the invarience rules
  481. qglStencilFunc( GL_ALWAYS, 128, 255 );
  482. }
  483. backEnd.depthFunc = GLS_DEPTHFUNC_EQUAL;
  484. RB_StencilShadowPass( vLight->globalShadows );
  485. RB_RenderInteractionList( vLight->localInteractions );
  486. RB_StencilShadowPass( vLight->localShadows );
  487. RB_RenderInteractionList( vLight->globalInteractions );
  488. if ( r_skipTranslucent.GetBool() ) {
  489. return;
  490. }
  491. // disable stencil testing for translucent interactions, because
  492. // the shadow isn't calculated at their point, and the shadow
  493. // behind them may be depth fighting with a back side, so there
  494. // isn't any reasonable thing to do
  495. qglStencilFunc( GL_ALWAYS, 128, 255 );
  496. backEnd.depthFunc = GLS_DEPTHFUNC_LESS;
  497. RB_RenderInteractionList( vLight->translucentInteractions );
  498. }
  499. /*
  500. ==================
  501. RB_NV10_DrawInteractions
  502. ==================
  503. */
  504. void RB_NV10_DrawInteractions( void ) {
  505. qglEnable( GL_STENCIL_TEST );
  506. for ( viewLight_t *vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) {
  507. RB_RenderViewLight( vLight );
  508. }
  509. }
  510. /*
  511. ==================
  512. R_NV10_Init
  513. ==================
  514. */
  515. void R_NV10_Init( void ) {
  516. glConfig.allowNV10Path = false;
  517. if ( !glConfig.registerCombinersAvailable ) {
  518. return;
  519. }
  520. glConfig.allowNV10Path = true;
  521. }