2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 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.
24 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.
26 ===========================================================================
29 #include "../idlib/precompiled.h"
36 back end scene + lights rendering functions
43 RB_DrawElementsImmediate
45 Draws with immediate mode commands, which is going to be very slow.
46 This should never happen if the vertex cache is operating properly.
49 void RB_DrawElementsImmediate( const srfTriangles_t *tri ) {
51 backEnd.pc.c_drawElements++;
52 backEnd.pc.c_drawIndexes += tri->numIndexes;
53 backEnd.pc.c_drawVertexes += tri->numVerts;
55 if ( tri->ambientSurface != NULL ) {
56 if ( tri->indexes == tri->ambientSurface->indexes ) {
57 backEnd.pc.c_drawRefIndexes += tri->numIndexes;
59 if ( tri->verts == tri->ambientSurface->verts ) {
60 backEnd.pc.c_drawRefVertexes += tri->numVerts;
64 qglBegin( GL_TRIANGLES );
65 for ( int i = 0 ; i < tri->numIndexes ; i++ ) {
66 qglTexCoord2fv( tri->verts[ tri->indexes[i] ].st.ToFloatPtr() );
67 qglVertex3fv( tri->verts[ tri->indexes[i] ].xyz.ToFloatPtr() );
75 RB_DrawElementsWithCounters
78 void RB_DrawElementsWithCounters( const srfTriangles_t *tri ) {
80 backEnd.pc.c_drawElements++;
81 backEnd.pc.c_drawIndexes += tri->numIndexes;
82 backEnd.pc.c_drawVertexes += tri->numVerts;
84 if ( tri->ambientSurface != NULL ) {
85 if ( tri->indexes == tri->ambientSurface->indexes ) {
86 backEnd.pc.c_drawRefIndexes += tri->numIndexes;
88 if ( tri->verts == tri->ambientSurface->verts ) {
89 backEnd.pc.c_drawRefVertexes += tri->numVerts;
93 if ( tri->indexCache && r_useIndexBuffers.GetBool() ) {
94 qglDrawElements( GL_TRIANGLES,
95 r_singleTriangle.GetBool() ? 3 : tri->numIndexes,
97 (int *)vertexCache.Position( tri->indexCache ) );
98 backEnd.pc.c_vboIndexes += tri->numIndexes;
100 if ( r_useIndexBuffers.GetBool() ) {
101 vertexCache.UnbindIndex();
103 qglDrawElements( GL_TRIANGLES,
104 r_singleTriangle.GetBool() ? 3 : tri->numIndexes,
112 RB_DrawShadowElementsWithCounters
114 May not use all the indexes in the surface if caps are skipped
117 void RB_DrawShadowElementsWithCounters( const srfTriangles_t *tri, int numIndexes ) {
118 backEnd.pc.c_shadowElements++;
119 backEnd.pc.c_shadowIndexes += numIndexes;
120 backEnd.pc.c_shadowVertexes += tri->numVerts;
122 if ( tri->indexCache && r_useIndexBuffers.GetBool() ) {
123 qglDrawElements( GL_TRIANGLES,
124 r_singleTriangle.GetBool() ? 3 : numIndexes,
126 (int *)vertexCache.Position( tri->indexCache ) );
127 backEnd.pc.c_vboIndexes += numIndexes;
129 if ( r_useIndexBuffers.GetBool() ) {
130 vertexCache.UnbindIndex();
132 qglDrawElements( GL_TRIANGLES,
133 r_singleTriangle.GetBool() ? 3 : numIndexes,
142 RB_RenderTriangleSurface
144 Sets texcoord and vertex pointers
147 void RB_RenderTriangleSurface( const srfTriangles_t *tri ) {
148 if ( !tri->ambientCache ) {
149 RB_DrawElementsImmediate( tri );
154 idDrawVert *ac = (idDrawVert *)vertexCache.Position( tri->ambientCache );
155 qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() );
156 qglTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ), ac->st.ToFloatPtr() );
158 RB_DrawElementsWithCounters( tri );
163 RB_T_RenderTriangleSurface
167 void RB_T_RenderTriangleSurface( const drawSurf_t *surf ) {
168 RB_RenderTriangleSurface( surf->geo );
173 RB_EnterWeaponDepthHack
176 void RB_EnterWeaponDepthHack() {
177 qglDepthRange( 0, 0.5 );
181 memcpy( matrix, backEnd.viewDef->projectionMatrix, sizeof( matrix ) );
185 qglMatrixMode(GL_PROJECTION);
186 qglLoadMatrixf( matrix );
187 qglMatrixMode(GL_MODELVIEW);
192 RB_EnterModelDepthHack
195 void RB_EnterModelDepthHack( float depth ) {
196 qglDepthRange( 0.0f, 1.0f );
200 memcpy( matrix, backEnd.viewDef->projectionMatrix, sizeof( matrix ) );
204 qglMatrixMode(GL_PROJECTION);
205 qglLoadMatrixf( matrix );
206 qglMatrixMode(GL_MODELVIEW);
214 void RB_LeaveDepthHack() {
215 qglDepthRange( 0, 1 );
217 qglMatrixMode(GL_PROJECTION);
218 qglLoadMatrixf( backEnd.viewDef->projectionMatrix );
219 qglMatrixMode(GL_MODELVIEW);
224 RB_RenderDrawSurfListWithFunction
226 The triangle functions can check backEnd.currentSpace != surf->space
227 to see if they need to perform any new matrix setup. The modelview
228 matrix will already have been loaded, and backEnd.currentSpace will
229 be updated after the triangle function completes.
232 void RB_RenderDrawSurfListWithFunction( drawSurf_t **drawSurfs, int numDrawSurfs,
233 void (*triFunc_)( const drawSurf_t *) ) {
235 const drawSurf_t *drawSurf;
237 backEnd.currentSpace = NULL;
239 for (i = 0 ; i < numDrawSurfs ; i++ ) {
240 drawSurf = drawSurfs[i];
242 // change the matrix if needed
243 if ( drawSurf->space != backEnd.currentSpace ) {
244 qglLoadMatrixf( drawSurf->space->modelViewMatrix );
247 if ( drawSurf->space->weaponDepthHack ) {
248 RB_EnterWeaponDepthHack();
251 if ( drawSurf->space->modelDepthHack != 0.0f ) {
252 RB_EnterModelDepthHack( drawSurf->space->modelDepthHack );
255 // change the scissor if needed
256 if ( r_useScissor.GetBool() && !backEnd.currentScissor.Equals( drawSurf->scissorRect ) ) {
257 backEnd.currentScissor = drawSurf->scissorRect;
258 qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1,
259 backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1,
260 backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1,
261 backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 );
265 triFunc_( drawSurf );
267 if ( drawSurf->space->weaponDepthHack || drawSurf->space->modelDepthHack != 0.0f ) {
271 backEnd.currentSpace = drawSurf->space;
276 ======================
277 RB_RenderDrawSurfChainWithFunction
278 ======================
280 void RB_RenderDrawSurfChainWithFunction( const drawSurf_t *drawSurfs,
281 void (*triFunc_)( const drawSurf_t *) ) {
282 const drawSurf_t *drawSurf;
284 backEnd.currentSpace = NULL;
286 for ( drawSurf = drawSurfs ; drawSurf ; drawSurf = drawSurf->nextOnLight ) {
287 // change the matrix if needed
288 if ( drawSurf->space != backEnd.currentSpace ) {
289 qglLoadMatrixf( drawSurf->space->modelViewMatrix );
292 if ( drawSurf->space->weaponDepthHack ) {
293 RB_EnterWeaponDepthHack();
296 if ( drawSurf->space->modelDepthHack ) {
297 RB_EnterModelDepthHack( drawSurf->space->modelDepthHack );
300 // change the scissor if needed
301 if ( r_useScissor.GetBool() && !backEnd.currentScissor.Equals( drawSurf->scissorRect ) ) {
302 backEnd.currentScissor = drawSurf->scissorRect;
303 qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1,
304 backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1,
305 backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1,
306 backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 );
310 triFunc_( drawSurf );
312 if ( drawSurf->space->weaponDepthHack || drawSurf->space->modelDepthHack != 0.0f ) {
316 backEnd.currentSpace = drawSurf->space;
321 ======================
322 RB_GetShaderTextureMatrix
323 ======================
325 void RB_GetShaderTextureMatrix( const float *shaderRegisters,
326 const textureStage_t *texture, float matrix[16] ) {
327 matrix[0] = shaderRegisters[ texture->matrix[0][0] ];
328 matrix[4] = shaderRegisters[ texture->matrix[0][1] ];
330 matrix[12] = shaderRegisters[ texture->matrix[0][2] ];
332 // we attempt to keep scrolls from generating incredibly large texture values, but
333 // center rotations and center scales can still generate offsets that need to be > 1
334 if ( matrix[12] < -40 || matrix[12] > 40 ) {
335 matrix[12] -= (int)matrix[12];
338 matrix[1] = shaderRegisters[ texture->matrix[1][0] ];
339 matrix[5] = shaderRegisters[ texture->matrix[1][1] ];
341 matrix[13] = shaderRegisters[ texture->matrix[1][2] ];
342 if ( matrix[13] < -40 || matrix[13] > 40 ) {
343 matrix[13] -= (int)matrix[13];
358 ======================
359 RB_LoadShaderTextureMatrix
360 ======================
362 void RB_LoadShaderTextureMatrix( const float *shaderRegisters, const textureStage_t *texture ) {
365 RB_GetShaderTextureMatrix( shaderRegisters, texture, matrix );
366 qglMatrixMode( GL_TEXTURE );
367 qglLoadMatrixf( matrix );
368 qglMatrixMode( GL_MODELVIEW );
372 ======================
373 RB_BindVariableStageImage
375 Handles generating a cinematic frame if needed
376 ======================
378 void RB_BindVariableStageImage( const textureStage_t *texture, const float *shaderRegisters ) {
379 if ( texture->cinematic ) {
382 if ( r_skipDynamicTextures.GetBool() ) {
383 globalImages->defaultImage->Bind();
387 // offset time by shaderParm[7] (FIXME: make the time offset a parameter of the shader?)
388 // We make no attempt to optimize for multiple identical cinematics being in view, or
389 // for cinematics going at a lower framerate than the renderer.
390 cin = texture->cinematic->ImageForTime( (int)(1000 * ( backEnd.viewDef->floatTime + backEnd.viewDef->renderView.shaderParms[11] ) ) );
393 globalImages->cinematicImage->UploadScratch( cin.image, cin.imageWidth, cin.imageHeight );
395 globalImages->blackImage->Bind();
398 //FIXME: see why image is invalid
399 if (texture->image) {
400 texture->image->Bind();
406 ======================
408 ======================
410 void RB_BindStageTexture( const float *shaderRegisters, const textureStage_t *texture, const drawSurf_t *surf ) {
412 RB_BindVariableStageImage( texture, shaderRegisters );
415 if ( texture->texgen == TG_DIFFUSE_CUBE ) {
416 qglTexCoordPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ((idDrawVert *)vertexCache.Position( surf->geo->ambientCache ))->normal.ToFloatPtr() );
418 if ( texture->texgen == TG_SKYBOX_CUBE || texture->texgen == TG_WOBBLESKY_CUBE ) {
419 qglTexCoordPointer( 3, GL_FLOAT, 0, vertexCache.Position( surf->dynamicTexCoords ) );
421 if ( texture->texgen == TG_REFLECT_CUBE ) {
422 qglEnable( GL_TEXTURE_GEN_S );
423 qglEnable( GL_TEXTURE_GEN_T );
424 qglEnable( GL_TEXTURE_GEN_R );
425 qglTexGenf( GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT );
426 qglTexGenf( GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT );
427 qglTexGenf( GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT );
428 qglEnableClientState( GL_NORMAL_ARRAY );
429 qglNormalPointer( GL_FLOAT, sizeof( idDrawVert ), ((idDrawVert *)vertexCache.Position( surf->geo->ambientCache ))->normal.ToFloatPtr() );
431 qglMatrixMode( GL_TEXTURE );
434 R_TransposeGLMatrix( backEnd.viewDef->worldSpace.modelViewMatrix, mat );
436 qglLoadMatrixf( mat );
437 qglMatrixMode( GL_MODELVIEW );
441 if ( texture->hasMatrix ) {
442 RB_LoadShaderTextureMatrix( shaderRegisters, texture );
447 ======================
448 RB_FinishStageTexture
449 ======================
451 void RB_FinishStageTexture( const textureStage_t *texture, const drawSurf_t *surf ) {
452 if ( texture->texgen == TG_DIFFUSE_CUBE || texture->texgen == TG_SKYBOX_CUBE
453 || texture->texgen == TG_WOBBLESKY_CUBE ) {
454 qglTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ),
455 (void *)&(((idDrawVert *)vertexCache.Position( surf->geo->ambientCache ))->st) );
458 if ( texture->texgen == TG_REFLECT_CUBE ) {
459 qglDisable( GL_TEXTURE_GEN_S );
460 qglDisable( GL_TEXTURE_GEN_T );
461 qglDisable( GL_TEXTURE_GEN_R );
462 qglTexGenf( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
463 qglTexGenf( GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
464 qglTexGenf( GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
465 qglDisableClientState( GL_NORMAL_ARRAY );
467 qglMatrixMode( GL_TEXTURE );
469 qglMatrixMode( GL_MODELVIEW );
472 if ( texture->hasMatrix ) {
473 qglMatrixMode( GL_TEXTURE );
475 qglMatrixMode( GL_MODELVIEW );
481 //=============================================================================================
486 RB_DetermineLightScale
492 Find out how much we are going to need to overscale the lighting, so we
493 can down modulate the pre-lighting passes.
495 We only look at light calculations, but an argument could be made that
496 we should also look at surface evaluations, which would let surfaces
500 void RB_DetermineLightScale( void ) {
502 const idMaterial *shader;
505 const shaderStage_t *stage;
507 // the light scale will be based on the largest color component of any surface
508 // that will be drawn.
509 // should we consider separating rgb scales?
511 // if there are no lights, this will remain at 1.0, so GUI-only
512 // rendering will not lose any bits of precision
515 for ( vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) {
516 // lights with no surfaces or shaderparms may still be present
518 if ( !vLight->localInteractions && !vLight->globalInteractions
519 && !vLight->translucentInteractions ) {
523 shader = vLight->lightShader;
524 numStages = shader->GetNumStages();
525 for ( i = 0 ; i < numStages ; i++ ) {
526 stage = shader->GetStage( i );
527 for ( j = 0 ; j < 3 ; j++ ) {
528 float v = r_lightScale.GetFloat() * vLight->shaderRegisters[ stage->color.registers[j] ];
536 backEnd.pc.maxLightValue = max;
537 if ( max <= tr.backEndRendererMaxLight ) {
538 backEnd.lightScale = r_lightScale.GetFloat();
539 backEnd.overBright = 1.0;
541 backEnd.lightScale = r_lightScale.GetFloat() * tr.backEndRendererMaxLight / max;
542 backEnd.overBright = max / tr.backEndRendererMaxLight;
551 Any mirrored or portaled views have already been drawn, so prepare
552 to actually render the visible surfaces for this view
555 void RB_BeginDrawingView (void) {
556 // set the modelview matrix for the viewer
557 qglMatrixMode(GL_PROJECTION);
558 qglLoadMatrixf( backEnd.viewDef->projectionMatrix );
559 qglMatrixMode(GL_MODELVIEW);
561 // set the window clipping
562 qglViewport( tr.viewportOffset[0] + backEnd.viewDef->viewport.x1,
563 tr.viewportOffset[1] + backEnd.viewDef->viewport.y1,
564 backEnd.viewDef->viewport.x2 + 1 - backEnd.viewDef->viewport.x1,
565 backEnd.viewDef->viewport.y2 + 1 - backEnd.viewDef->viewport.y1 );
567 // the scissor may be smaller than the viewport for subviews
568 qglScissor( tr.viewportOffset[0] + backEnd.viewDef->viewport.x1 + backEnd.viewDef->scissor.x1,
569 tr.viewportOffset[1] + backEnd.viewDef->viewport.y1 + backEnd.viewDef->scissor.y1,
570 backEnd.viewDef->scissor.x2 + 1 - backEnd.viewDef->scissor.x1,
571 backEnd.viewDef->scissor.y2 + 1 - backEnd.viewDef->scissor.y1 );
572 backEnd.currentScissor = backEnd.viewDef->scissor;
574 // ensures that depth writes are enabled for the depth clear
575 GL_State( GLS_DEFAULT );
577 // we don't have to clear the depth / stencil buffer for 2D rendering
578 if ( backEnd.viewDef->viewEntitys ) {
579 qglStencilMask( 0xff );
580 // some cards may have 7 bit stencil buffers, so don't assume this
582 qglClearStencil( 1<<(glConfig.stencilBits-1) );
583 qglClear( GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
584 qglEnable( GL_DEPTH_TEST );
586 qglDisable( GL_DEPTH_TEST );
587 qglDisable( GL_STENCIL_TEST );
590 backEnd.glState.faceCulling = -1; // force face culling to set next time
591 GL_Cull( CT_FRONT_SIDED );
597 R_SetDrawInteractions
600 void R_SetDrawInteraction( const shaderStage_t *surfaceStage, const float *surfaceRegs,
601 idImage **image, idVec4 matrix[2], float color[4] ) {
602 *image = surfaceStage->texture.image;
603 if ( surfaceStage->texture.hasMatrix ) {
604 matrix[0][0] = surfaceRegs[surfaceStage->texture.matrix[0][0]];
605 matrix[0][1] = surfaceRegs[surfaceStage->texture.matrix[0][1]];
607 matrix[0][3] = surfaceRegs[surfaceStage->texture.matrix[0][2]];
609 matrix[1][0] = surfaceRegs[surfaceStage->texture.matrix[1][0]];
610 matrix[1][1] = surfaceRegs[surfaceStage->texture.matrix[1][1]];
612 matrix[1][3] = surfaceRegs[surfaceStage->texture.matrix[1][2]];
614 // we attempt to keep scrolls from generating incredibly large texture values, but
615 // center rotations and center scales can still generate offsets that need to be > 1
616 if ( matrix[0][3] < -40 || matrix[0][3] > 40 ) {
617 matrix[0][3] -= (int)matrix[0][3];
619 if ( matrix[1][3] < -40 || matrix[1][3] > 40 ) {
620 matrix[1][3] -= (int)matrix[1][3];
635 for ( int i = 0 ; i < 4 ; i++ ) {
636 color[i] = surfaceRegs[surfaceStage->color.registers[i]];
637 // clamp here, so card with greater range don't look different.
638 // we could perform overbrighting like we do for lights, but
639 // it doesn't currently look worth it.
640 if ( color[i] < 0 ) {
642 } else if ( color[i] > 1.0 ) {
651 RB_SubmittInteraction
654 static void RB_SubmittInteraction( drawInteraction_t *din, void (*DrawInteraction)(const drawInteraction_t *) ) {
655 if ( !din->bumpImage ) {
659 if ( !din->diffuseImage || r_skipDiffuse.GetBool() ) {
660 din->diffuseImage = globalImages->blackImage;
662 if ( !din->specularImage || r_skipSpecular.GetBool() || din->ambientLight ) {
663 din->specularImage = globalImages->blackImage;
665 if ( !din->bumpImage || r_skipBump.GetBool() ) {
666 din->bumpImage = globalImages->flatNormalMap;
669 // if we wouldn't draw anything, don't call the Draw function
671 ( ( din->diffuseColor[0] > 0 ||
672 din->diffuseColor[1] > 0 ||
673 din->diffuseColor[2] > 0 ) && din->diffuseImage != globalImages->blackImage )
674 || ( ( din->specularColor[0] > 0 ||
675 din->specularColor[1] > 0 ||
676 din->specularColor[2] > 0 ) && din->specularImage != globalImages->blackImage ) ) {
677 DrawInteraction( din );
683 RB_CreateSingleDrawInteractions
685 This can be used by different draw_* backends to decompose a complex light / surface
686 interaction into primitive interactions
689 void RB_CreateSingleDrawInteractions( const drawSurf_t *surf, void (*DrawInteraction)(const drawInteraction_t *) ) {
690 const idMaterial *surfaceShader = surf->material;
691 const float *surfaceRegs = surf->shaderRegisters;
692 const viewLight_t *vLight = backEnd.vLight;
693 const idMaterial *lightShader = vLight->lightShader;
694 const float *lightRegs = vLight->shaderRegisters;
695 drawInteraction_t inter;
697 if ( r_skipInteractions.GetBool() || !surf->geo || !surf->geo->ambientCache ) {
702 RB_LogComment( "---------- RB_CreateSingleDrawInteractions %s on %s ----------\n", lightShader->GetName(), surfaceShader->GetName() );
705 // change the matrix and light projection vectors if needed
706 if ( surf->space != backEnd.currentSpace ) {
707 backEnd.currentSpace = surf->space;
708 qglLoadMatrixf( surf->space->modelViewMatrix );
711 // change the scissor if needed
712 if ( r_useScissor.GetBool() && !backEnd.currentScissor.Equals( surf->scissorRect ) ) {
713 backEnd.currentScissor = surf->scissorRect;
714 qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1,
715 backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1,
716 backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1,
717 backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 );
720 // hack depth range if needed
721 if ( surf->space->weaponDepthHack ) {
722 RB_EnterWeaponDepthHack();
725 if ( surf->space->modelDepthHack ) {
726 RB_EnterModelDepthHack( surf->space->modelDepthHack );
730 inter.lightFalloffImage = vLight->falloffImage;
732 R_GlobalPointToLocal( surf->space->modelMatrix, vLight->globalLightOrigin, inter.localLightOrigin.ToVec3() );
733 R_GlobalPointToLocal( surf->space->modelMatrix, backEnd.viewDef->renderView.vieworg, inter.localViewOrigin.ToVec3() );
734 inter.localLightOrigin[3] = 0;
735 inter.localViewOrigin[3] = 1;
736 inter.ambientLight = lightShader->IsAmbientLight();
738 // the base projections may be modified by texture matrix on light stages
739 idPlane lightProject[4];
740 for ( int i = 0 ; i < 4 ; i++ ) {
741 R_GlobalPlaneToLocal( surf->space->modelMatrix, backEnd.vLight->lightProject[i], lightProject[i] );
744 for ( int lightStageNum = 0 ; lightStageNum < lightShader->GetNumStages() ; lightStageNum++ ) {
745 const shaderStage_t *lightStage = lightShader->GetStage( lightStageNum );
747 // ignore stages that fail the condition
748 if ( !lightRegs[ lightStage->conditionRegister ] ) {
752 inter.lightImage = lightStage->texture.image;
754 memcpy( inter.lightProjection, lightProject, sizeof( inter.lightProjection ) );
755 // now multiply the texgen by the light texture matrix
756 if ( lightStage->texture.hasMatrix ) {
757 RB_GetShaderTextureMatrix( lightRegs, &lightStage->texture, backEnd.lightTextureMatrix );
758 RB_BakeTextureMatrixIntoTexgen( reinterpret_cast<class idPlane *>(inter.lightProjection), backEnd.lightTextureMatrix );
761 inter.bumpImage = NULL;
762 inter.specularImage = NULL;
763 inter.diffuseImage = NULL;
764 inter.diffuseColor[0] = inter.diffuseColor[1] = inter.diffuseColor[2] = inter.diffuseColor[3] = 0;
765 inter.specularColor[0] = inter.specularColor[1] = inter.specularColor[2] = inter.specularColor[3] = 0;
769 // backEnd.lightScale is calculated so that lightColor[] will never exceed
770 // tr.backEndRendererMaxLight
771 lightColor[0] = backEnd.lightScale * lightRegs[ lightStage->color.registers[0] ];
772 lightColor[1] = backEnd.lightScale * lightRegs[ lightStage->color.registers[1] ];
773 lightColor[2] = backEnd.lightScale * lightRegs[ lightStage->color.registers[2] ];
774 lightColor[3] = lightRegs[ lightStage->color.registers[3] ];
776 // go through the individual stages
777 for ( int surfaceStageNum = 0 ; surfaceStageNum < surfaceShader->GetNumStages() ; surfaceStageNum++ ) {
778 const shaderStage_t *surfaceStage = surfaceShader->GetStage( surfaceStageNum );
780 switch( surfaceStage->lighting ) {
782 // ignore ambient stages while drawing interactions
786 // ignore stage that fails the condition
787 if ( !surfaceRegs[ surfaceStage->conditionRegister ] ) {
790 // draw any previous interaction
791 RB_SubmittInteraction( &inter, DrawInteraction );
792 inter.diffuseImage = NULL;
793 inter.specularImage = NULL;
794 R_SetDrawInteraction( surfaceStage, surfaceRegs, &inter.bumpImage, inter.bumpMatrix, NULL );
798 // ignore stage that fails the condition
799 if ( !surfaceRegs[ surfaceStage->conditionRegister ] ) {
802 if ( inter.diffuseImage ) {
803 RB_SubmittInteraction( &inter, DrawInteraction );
805 R_SetDrawInteraction( surfaceStage, surfaceRegs, &inter.diffuseImage,
806 inter.diffuseMatrix, inter.diffuseColor.ToFloatPtr() );
807 inter.diffuseColor[0] *= lightColor[0];
808 inter.diffuseColor[1] *= lightColor[1];
809 inter.diffuseColor[2] *= lightColor[2];
810 inter.diffuseColor[3] *= lightColor[3];
811 inter.vertexColor = surfaceStage->vertexColor;
815 // ignore stage that fails the condition
816 if ( !surfaceRegs[ surfaceStage->conditionRegister ] ) {
819 if ( inter.specularImage ) {
820 RB_SubmittInteraction( &inter, DrawInteraction );
822 R_SetDrawInteraction( surfaceStage, surfaceRegs, &inter.specularImage,
823 inter.specularMatrix, inter.specularColor.ToFloatPtr() );
824 inter.specularColor[0] *= lightColor[0];
825 inter.specularColor[1] *= lightColor[1];
826 inter.specularColor[2] *= lightColor[2];
827 inter.specularColor[3] *= lightColor[3];
828 inter.vertexColor = surfaceStage->vertexColor;
834 // draw the final interaction
835 RB_SubmittInteraction( &inter, DrawInteraction );
838 // unhack depth range if needed
839 if ( surf->space->weaponDepthHack || surf->space->modelDepthHack != 0.0f ) {
849 void RB_DrawView( const void *data ) {
850 const drawSurfsCommand_t *cmd;
852 cmd = (const drawSurfsCommand_t *)data;
854 backEnd.viewDef = cmd->viewDef;
856 // we will need to do a new copyTexSubImage of the screen
857 // when a SS_POST_PROCESS material is used
858 backEnd.currentRenderCopied = false;
860 // if there aren't any drawsurfs, do nothing
861 if ( !backEnd.viewDef->numDrawSurfs ) {
865 // skip render bypasses everything that has models, assuming
866 // them to be 3D views, but leaves 2D rendering visible
867 if ( r_skipRender.GetBool() && backEnd.viewDef->viewEntitys ) {
871 // skip render context sets the wgl context to NULL,
872 // which should factor out the API cost, under the assumption
873 // that all gl calls just return if the context isn't valid
874 if ( r_skipRenderContext.GetBool() && backEnd.viewDef->viewEntitys ) {
875 GLimp_DeactivateContext();
878 backEnd.pc.c_surfaces += backEnd.viewDef->numDrawSurfs;
882 // render the scene, jumping to the hardware specific interaction renderers
885 // restore the context for 2D drawing if we were stubbing it out
886 if ( r_skipRenderContext.GetBool() && backEnd.viewDef->viewEntitys ) {
887 GLimp_ActivateContext();
888 RB_SetDefaultGLState();