/* ============= RB_DrawView ============= */ const void *RB_DrawView( const void *data ) { const drawViewCommand_t *cmd; GLimp_LogComment( "--- RB_DrawView ---\n" ); // finish any 2D drawing if needed if ( tess.numIndexes ) { Tess_End(); } cmd = ( const drawViewCommand_t * ) data; backEnd.refdef = cmd->refdef; backEnd.viewParms = cmd->viewParms; #if defined( USE_D3D10 ) D3D10_RenderView(); #else GL_RenderView(); #endif return ( const void * )( cmd + 1 ); }
/* ============== Tess_SurfaceVBOMD5Mesh ============== */ static void Tess_SurfaceVBOMD5Mesh( srfVBOMD5Mesh_t *srf ) { int i; md5Model_t *model; GLimp_LogComment( "--- Tess_SurfaceVBOMD5Mesh ---\n" ); if ( !srf->vbo || !srf->ibo ) { return; } Tess_EndBegin(); R_BindVBO( srf->vbo ); R_BindIBO( srf->ibo ); tess.numIndexes = srf->numIndexes; tess.numVertexes = srf->numVerts; model = srf->md5Model; tess.vboVertexSkinning = true; tess.numBones = srf->numBoneRemap; for ( i = 0; i < srf->numBoneRemap; i++ ) { refBone_t *bone = &backEnd.currentEntity->e.skeleton.bones[ srf->boneRemapInverse[ i ] ]; if ( backEnd.currentEntity->e.skeleton.type == SK_ABSOLUTE ) { TransInitRotationQuat( model->bones[ srf->boneRemapInverse[ i ] ].rotation, &tess.bones[ i ] ); TransAddTranslation( model->bones[ srf->boneRemapInverse[ i ] ].origin, &tess.bones[ i ] ); TransInverse( &tess.bones[ i ], &tess.bones[ i ] ); TransCombine( &tess.bones[ i ], &bone->t, &tess.bones[ i ] ); } else { TransInit( &tess.bones[ i ] ); } TransAddScale( backEnd.currentEntity->e.skeleton.scale, &tess.bones[ i ] ); TransInsScale( model->internalScale, &tess.bones[ i ] ); } Tess_End(); }
/* ============== Tess_CheckOverflow ============== */ void Tess_CheckOverflow( int verts, int indexes ) { // FIXME: need to check if a vbo is bound, otherwise we fail on startup if ( glState.currentVBO != nullptr && glState.currentIBO != nullptr ) { Tess_CheckVBOAndIBO( tess.vbo, tess.ibo ); } if ( tess.buildingVBO ) { return; } if ( tess.numVertexes + verts < SHADER_MAX_VERTEXES && tess.numIndexes + indexes < SHADER_MAX_INDEXES ) { return; } if ( r_logFile->integer ) { // don't just call LogComment, or we will get // a call to va() every frame! GLimp_LogComment( va ( "--- Tess_CheckOverflow(%i + %i vertices, %i + %i triangles ) ---\n", tess.numVertexes, verts, ( tess.numIndexes / 3 ), indexes ) ); } Tess_End(); if ( verts >= SHADER_MAX_VERTEXES ) { ri.Error( ERR_DROP, "Tess_CheckOverflow: verts > std::max (%d > %d)", verts, SHADER_MAX_VERTEXES ); } if ( indexes >= SHADER_MAX_INDEXES ) { ri.Error( ERR_DROP, "Tess_CheckOverflow: indexes > std::max (%d > %d)", indexes, SHADER_MAX_INDEXES ); } Tess_Begin( tess.stageIteratorFunc, tess.stageIteratorFunc2, tess.surfaceShader, tess.lightShader, tess.skipTangentSpaces, tess.skipVBO, tess.lightmapNum, tess.fogNum ); }
/* ============== Tess_SurfaceVBOMDVMesh ============== */ void Tess_SurfaceVBOMDVMesh( srfVBOMDVMesh_t *surface ) { refEntity_t *refEnt; GLimp_LogComment( "--- Tess_SurfaceVBOMDVMesh ---\n" ); if ( !surface->vbo || !surface->ibo ) { return; } Tess_EndBegin(); R_BindVBO( surface->vbo ); R_BindIBO( surface->ibo ); tess.numIndexes = surface->numIndexes; tess.numVertexes = surface->numVerts; tess.vboVertexAnimation = true; refEnt = &backEnd.currentEntity->e; if ( refEnt->oldframe == refEnt->frame ) { glState.vertexAttribsInterpolation = 0; } else { glState.vertexAttribsInterpolation = ( 1.0 - refEnt->backlerp ); } glState.vertexAttribsOldFrame = refEnt->oldframe; glState.vertexAttribsNewFrame = refEnt->frame; Tess_End(); }
/* ** RB_DrawSun */ void RB_DrawSun( void ) { #if 0 float size; float dist; vec3_t origin, vec1, vec2; vec3_t temp; matrix_t transformMatrix; matrix_t modelViewMatrix; if ( !backEnd.skyRenderedThisView ) { return; } if ( !r_drawSun->integer ) { return; } GL_PushMatrix(); GL_BindProgram( &tr.genericShader ); // set uniforms GLSL_SetUniform_TCGen_Environment( &tr.genericShader, qfalse ); GLSL_SetUniform_InverseVertexColor( &tr.genericShader, qfalse ); if ( glConfig2.vboVertexSkinningAvailable ) { GLSL_SetUniform_VertexSkinning( &tr.genericShader, qfalse ); } GLSL_SetUniform_DeformGen( &tr.genericShader, DGEN_NONE ); GLSL_SetUniform_AlphaTest( &tr.genericShader, -1.0 ); MatrixSetupTranslation( transformMatrix, backEnd.viewParms.orientation.origin[ 0 ], backEnd.viewParms.orientation.origin[ 1 ], backEnd.viewParms.orientation.origin[ 2 ] ); MatrixMultiply( backEnd.viewParms.world.viewMatrix, transformMatrix, modelViewMatrix ); GL_LoadProjectionMatrix( backEnd.viewParms.projectionMatrix ); GL_LoadModelViewMatrix( modelViewMatrix ); GLSL_SetUniform_ModelMatrix( &tr.genericShader, backEnd.orientation.transformMatrix ); GLSL_SetUniform_ModelViewProjectionMatrix( &tr.genericShader, glState.modelViewProjectionMatrix[ glState.stackIndex ] ); GLSL_SetUniform_PortalClipping( &tr.genericShader, backEnd.viewParms.isPortal ); if ( backEnd.viewParms.isPortal ) { float plane[ 4 ]; // clipping plane in world space plane[ 0 ] = backEnd.viewParms.portalPlane.normal[ 0 ]; plane[ 1 ] = backEnd.viewParms.portalPlane.normal[ 1 ]; plane[ 2 ] = backEnd.viewParms.portalPlane.normal[ 2 ]; plane[ 3 ] = backEnd.viewParms.portalPlane.dist; GLSL_SetUniform_PortalPlane( &tr.genericShader, plane ); } dist = backEnd.viewParms.skyFar / 1.75; // div sqrt(3) size = dist * 0.4; VectorScale( tr.sunDirection, dist, origin ); PerpendicularVector( vec1, tr.sunDirection ); CrossProduct( tr.sunDirection, vec1, vec2 ); VectorScale( vec1, size, vec1 ); VectorScale( vec2, size, vec2 ); // farthest depth range glDepthRange( 1.0, 1.0 ); // FIXME: use quad stamp Tess_Begin( Tess_StageIteratorGeneric, tr.sunShader, NULL, tess.skipTangentSpaces, qfalse, -1, tess.fogNum ); VectorCopy( origin, temp ); VectorSubtract( temp, vec1, temp ); VectorSubtract( temp, vec2, temp ); VectorCopy( temp, tess.xyz[ tess.numVertexes ] ); tess.xyz[ tess.numVertexes ][ 3 ] = 1; tess.texCoords[ tess.numVertexes ][ 0 ] = 0; tess.texCoords[ tess.numVertexes ][ 1 ] = 0; tess.texCoords[ tess.numVertexes ][ 2 ] = 0; tess.texCoords[ tess.numVertexes ][ 3 ] = 1; tess.colors[ tess.numVertexes ][ 0 ] = 1; tess.colors[ tess.numVertexes ][ 1 ] = 1; tess.colors[ tess.numVertexes ][ 2 ] = 1; tess.numVertexes++; VectorCopy( origin, temp ); VectorAdd( temp, vec1, temp ); VectorSubtract( temp, vec2, temp ); VectorCopy( temp, tess.xyz[ tess.numVertexes ] ); tess.xyz[ tess.numVertexes ][ 3 ] = 1; tess.texCoords[ tess.numVertexes ][ 0 ] = 0; tess.texCoords[ tess.numVertexes ][ 1 ] = 1; tess.texCoords[ tess.numVertexes ][ 2 ] = 0; tess.texCoords[ tess.numVertexes ][ 3 ] = 1; tess.colors[ tess.numVertexes ][ 0 ] = 1; tess.colors[ tess.numVertexes ][ 1 ] = 1; tess.colors[ tess.numVertexes ][ 2 ] = 1; tess.numVertexes++; VectorCopy( origin, temp ); VectorAdd( temp, vec1, temp ); VectorAdd( temp, vec2, temp ); VectorCopy( temp, tess.xyz[ tess.numVertexes ] ); tess.xyz[ tess.numVertexes ][ 3 ] = 1; tess.texCoords[ tess.numVertexes ][ 0 ] = 1; tess.texCoords[ tess.numVertexes ][ 1 ] = 1; tess.texCoords[ tess.numVertexes ][ 2 ] = 0; tess.texCoords[ tess.numVertexes ][ 3 ] = 1; tess.colors[ tess.numVertexes ][ 0 ] = 1; tess.colors[ tess.numVertexes ][ 1 ] = 1; tess.colors[ tess.numVertexes ][ 2 ] = 1; tess.numVertexes++; VectorCopy( origin, temp ); VectorSubtract( temp, vec1, temp ); VectorAdd( temp, vec2, temp ); VectorCopy( temp, tess.xyz[ tess.numVertexes ] ); tess.xyz[ tess.numVertexes ][ 3 ] = 1; tess.texCoords[ tess.numVertexes ][ 0 ] = 1; tess.texCoords[ tess.numVertexes ][ 1 ] = 0; tess.texCoords[ tess.numVertexes ][ 2 ] = 0; tess.texCoords[ tess.numVertexes ][ 3 ] = 1; tess.colors[ tess.numVertexes ][ 0 ] = 1; tess.colors[ tess.numVertexes ][ 1 ] = 1; tess.colors[ tess.numVertexes ][ 2 ] = 1; tess.numVertexes++; tess.indexes[ tess.numIndexes++ ] = 0; tess.indexes[ tess.numIndexes++ ] = 1; tess.indexes[ tess.numIndexes++ ] = 2; tess.indexes[ tess.numIndexes++ ] = 0; tess.indexes[ tess.numIndexes++ ] = 2; tess.indexes[ tess.numIndexes++ ] = 3; Tess_End(); // back to standard depth range glDepthRange( 0.0, 1.0 ); GL_PopMatrix(); #endif }
/* ============= RB_StretchPic ============= */ const void *RB_StretchPic( const void *data ) { int i; const stretchPicCommand_t *cmd; shader_t *shader; int numVerts, numIndexes; GLimp_LogComment( "--- RB_StretchPic ---\n" ); cmd = ( const stretchPicCommand_t * ) data; if ( !backEnd.projection2D ) { RB_SetGL2D(); } shader = cmd->shader; if ( shader != tess.surfaceShader ) { if ( tess.numIndexes ) { Tess_End(); } backEnd.currentEntity = &backEnd.entity2D; Tess_Begin( Tess_StageIteratorGeneric, NULL, shader, NULL, qfalse, qfalse, -1, tess.fogNum ); } Tess_CheckOverflow( 4, 6 ); numVerts = tess.numVertexes; numIndexes = tess.numIndexes; tess.numVertexes += 4; tess.numIndexes += 6; tess.indexes[ numIndexes ] = numVerts + 3; tess.indexes[ numIndexes + 1 ] = numVerts + 0; tess.indexes[ numIndexes + 2 ] = numVerts + 2; tess.indexes[ numIndexes + 3 ] = numVerts + 2; tess.indexes[ numIndexes + 4 ] = numVerts + 0; tess.indexes[ numIndexes + 5 ] = numVerts + 1; for ( i = 0; i < 4; i++ ) { tess.colors[ numVerts + i ][ 0 ] = backEnd.color2D[ 0 ]; tess.colors[ numVerts + i ][ 1 ] = backEnd.color2D[ 1 ]; tess.colors[ numVerts + i ][ 2 ] = backEnd.color2D[ 2 ]; tess.colors[ numVerts + i ][ 3 ] = backEnd.color2D[ 3 ]; } tess.xyz[ numVerts ][ 0 ] = cmd->x; tess.xyz[ numVerts ][ 1 ] = cmd->y; tess.xyz[ numVerts ][ 2 ] = 0; tess.xyz[ numVerts ][ 3 ] = 1; tess.texCoords[ numVerts ][ 0 ] = cmd->s1; tess.texCoords[ numVerts ][ 1 ] = cmd->t1; tess.texCoords[ numVerts ][ 2 ] = 0; tess.texCoords[ numVerts ][ 3 ] = 1; tess.xyz[ numVerts + 1 ][ 0 ] = cmd->x + cmd->w; tess.xyz[ numVerts + 1 ][ 1 ] = cmd->y; tess.xyz[ numVerts + 1 ][ 2 ] = 0; tess.xyz[ numVerts + 1 ][ 3 ] = 1; tess.texCoords[ numVerts + 1 ][ 0 ] = cmd->s2; tess.texCoords[ numVerts + 1 ][ 1 ] = cmd->t1; tess.texCoords[ numVerts + 1 ][ 2 ] = 0; tess.texCoords[ numVerts + 1 ][ 3 ] = 1; tess.xyz[ numVerts + 2 ][ 0 ] = cmd->x + cmd->w; tess.xyz[ numVerts + 2 ][ 1 ] = cmd->y + cmd->h; tess.xyz[ numVerts + 2 ][ 2 ] = 0; tess.xyz[ numVerts + 2 ][ 3 ] = 1; tess.texCoords[ numVerts + 2 ][ 0 ] = cmd->s2; tess.texCoords[ numVerts + 2 ][ 1 ] = cmd->t2; tess.texCoords[ numVerts + 2 ][ 2 ] = 0; tess.texCoords[ numVerts + 2 ][ 3 ] = 1; tess.xyz[ numVerts + 3 ][ 0 ] = cmd->x; tess.xyz[ numVerts + 3 ][ 1 ] = cmd->y + cmd->h; tess.xyz[ numVerts + 3 ][ 2 ] = 0; tess.xyz[ numVerts + 3 ][ 3 ] = 1; tess.texCoords[ numVerts + 3 ][ 0 ] = cmd->s1; tess.texCoords[ numVerts + 3 ][ 1 ] = cmd->t2; tess.texCoords[ numVerts + 3 ][ 2 ] = 0; tess.texCoords[ numVerts + 3 ][ 3 ] = 1; return ( const void * )( cmd + 1 ); }
static void RB_RenderDrawSurfaces( qboolean opaque, qboolean depthFill ) { trRefEntity_t *entity, *oldEntity; shader_t *shader, *oldShader; int lightmapNum, oldLightmapNum; qboolean depthRange, oldDepthRange; int i; drawSurf_t *drawSurf; GLimp_LogComment( "--- RB_RenderDrawSurfaces ---\n" ); // draw everything oldEntity = NULL; oldShader = NULL; oldLightmapNum = -1; oldDepthRange = qfalse; depthRange = qfalse; backEnd.currentLight = NULL; for ( i = 0, drawSurf = backEnd.viewParms.drawSurfs; i < backEnd.viewParms.numDrawSurfs; i++, drawSurf++ ) { // update locals entity = drawSurf->entity; shader = tr.sortedShaders[ drawSurf->shaderNum ]; lightmapNum = drawSurf->lightmapNum; if ( opaque ) { // skip all translucent surfaces that don't matter for this pass if ( shader->sort > SS_OPAQUE ) { break; } } else { // skip all opaque surfaces that don't matter for this pass if ( shader->sort <= SS_OPAQUE ) { continue; } } if ( entity == oldEntity && shader == oldShader && lightmapNum == oldLightmapNum ) { // fast path, same as previous sort rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); continue; } // change the tess parameters if needed // an "entityMergable" shader is a shader that can have surfaces from separate // entities merged into a single batch, like smoke and blood puff sprites if ( shader != oldShader || lightmapNum != oldLightmapNum || ( entity != oldEntity && !shader->entityMergable ) ) { if ( oldShader != NULL ) { Tess_End(); } if ( depthFill ) { Tess_Begin( Tess_StageIteratorDepthFill, NULL, shader, NULL, qtrue, qfalse, lightmapNum, tess.fogNum ); } else { Tess_Begin( Tess_StageIteratorGeneric, NULL, shader, NULL, qfalse, qfalse, lightmapNum, tess.fogNum ); } oldShader = shader; oldLightmapNum = lightmapNum; } // change the modelview matrix if needed if ( entity != oldEntity ) { depthRange = qfalse; if ( entity != &tr.worldEntity ) { backEnd.currentEntity = entity; // set up the transformation matrix R_RotateEntityForViewParms( backEnd.currentEntity, &backEnd.viewParms, &backEnd.orientation ); if ( backEnd.currentEntity->e.renderfx & RF_DEPTHHACK ) { // hack the depth range to prevent view model from poking into walls depthRange = qtrue; } } else { backEnd.currentEntity = &tr.worldEntity; backEnd.orientation = backEnd.viewParms.world; } #if defined( USE_D3D10 ) // TODO #else GL_LoadModelViewMatrix( backEnd.orientation.modelViewMatrix ); #endif // change depthrange if needed if ( oldDepthRange != depthRange ) { #if defined( USE_D3D10 ) // TODO #else if ( depthRange ) { qglDepthRange( 0, 0.3 ); } else { qglDepthRange( 0, 1 ); } #endif oldDepthRange = depthRange; } oldEntity = entity; } // add the triangles for this surface rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); } // draw the contents of the last shader batch if ( oldShader != NULL ) { Tess_End(); } // go back to the world modelview matrix #if defined( USE_D3D10 ) // TODO #else GL_LoadModelViewMatrix( backEnd.viewParms.world.modelViewMatrix ); #endif if ( depthRange ) { #if defined( USE_D3D10 ) // TODO #else qglDepthRange( 0, 1 ); #endif } #if defined( USE_D3D10 ) // TODO #else GL_CheckErrors(); #endif }
/* ============= RB_SwapBuffers ============= */ const void *RB_SwapBuffers( const void *data ) { const swapBuffersCommand_t *cmd; // finish any 2D drawing if needed if ( tess.numIndexes ) { Tess_End(); } // texture swapping test #if !defined( USE_D3D10 ) if ( r_showImages->integer ) { RB_ShowImages(); } #endif cmd = ( const swapBuffersCommand_t * ) data; #if defined( USE_D3D10 ) // TODO #else // we measure overdraw by reading back the stencil buffer and // counting up the number of increments that have happened if ( r_measureOverdraw->integer ) { int i; long sum = 0; unsigned char *stencilReadback; stencilReadback = ri.Hunk_AllocateTempMemory( glConfig.vidWidth * glConfig.vidHeight ); qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, stencilReadback ); for ( i = 0; i < glConfig.vidWidth * glConfig.vidHeight; i++ ) { sum += stencilReadback[ i ]; } backEnd.pc.c_overDraw += sum; ri.Hunk_FreeTempMemory( stencilReadback ); } #endif #if defined( USE_D3D10 ) // TODO #else if ( !glState.finishCalled ) { qglFinish(); } #endif GLimp_LogComment( "***************** RB_SwapBuffers *****************\n\n\n" ); // present the information rendered to the back buffer to the front buffer (the screen) dx.swapChain->Present( 0, 0 ); if ( r_fullscreen->modified ) { bool fullscreen; bool needToToggle = qtrue; bool sdlToggled = qfalse; SDL_Surface *s = SDL_GetVideoSurface(); if ( s ) { // Find out the current state fullscreen = !!( s->flags & SDL_FULLSCREEN ); if ( r_fullscreen->integer > 0 && ri.Cvar_VariableIntegerValue( "in_nograb" ) > 0 ) { ri.Printf( PRINT_ALL, "Fullscreen not allowed with in_nograb 1\n" ); ri.Cvar_Set( "r_fullscreen", "0" ); r_fullscreen->modified = qfalse; } // Is the state we want different from the current state? needToToggle = !!r_fullscreen->integer != fullscreen; if ( needToToggle ) { sdlToggled = SDL_WM_ToggleFullScreen( s ); } } if ( needToToggle ) { // SDL_WM_ToggleFullScreen didn't work, so do it the slow way if ( !sdlToggled ) { ri.Cmd_ExecuteText( EXEC_APPEND, "vid_restart" ); } ri.IN_Restart(); } r_fullscreen->modified = qfalse; } backEnd.projection2D = qfalse; return ( const void * )( cmd + 1 ); }
/* ============== Tess_EndBegin ============== */ void Tess_EndBegin() { Tess_End(); Tess_Begin( tess.stageIteratorFunc, tess.stageIteratorFunc2, tess.surfaceShader, tess.lightShader, tess.skipTangentSpaces, tess.skipVBO, tess.lightmapNum, tess.fogNum ); }
/* ================= Tess_SurfaceIQM Compute vertices for this model surface ================= */ void Tess_SurfaceIQM( srfIQModel_t *surf ) { IQModel_t *model = surf->data; int i, j; int offset = tess.numVertexes - surf->first_vertex; GLimp_LogComment( "--- RB_SurfaceIQM ---\n" ); Tess_CheckOverflow( surf->num_vertexes, surf->num_triangles * 3 ); // compute bones for ( i = 0; i < model->num_joints; i++ ) { if ( backEnd.currentEntity->e.skeleton.type == SK_ABSOLUTE ) { refBone_t *bone = &backEnd.currentEntity->e.skeleton.bones[ i ]; TransInverse( &model->joints[ i ], &bones[ i ] ); TransCombine( &bones[ i ], &bone->t, &bones[ i ] ); } else { TransInit( &bones[ i ] ); } TransAddScale( backEnd.currentEntity->e.skeleton.scale, &bones[ i ] ); TransInsScale( model->internalScale, &bones[ i ] ); } if( surf->vbo && surf->ibo ) { if( model->num_joints > 0 ) { Com_Memcpy( tess.bones, bones, model->num_joints * sizeof(transform_t) ); tess.numBones = model->num_joints; } else { TransInitScale( model->internalScale * backEnd.currentEntity->e.skeleton.scale, &tess.bones[ 0 ] ); tess.numBones = 1; } R_BindVBO( surf->vbo ); R_BindIBO( surf->ibo ); tess.vboVertexSkinning = true; tess.multiDrawIndexes[ tess.multiDrawPrimitives ] = ((glIndex_t *)nullptr) + surf->first_triangle * 3; tess.multiDrawCounts[ tess.multiDrawPrimitives ] = surf->num_triangles * 3; tess.multiDrawPrimitives++; Tess_End(); return; } for ( i = 0; i < surf->num_triangles; i++ ) { tess.indexes[ tess.numIndexes + i * 3 + 0 ] = offset + model->triangles[ 3 * ( surf->first_triangle + i ) + 0 ]; tess.indexes[ tess.numIndexes + i * 3 + 1 ] = offset + model->triangles[ 3 * ( surf->first_triangle + i ) + 1 ]; tess.indexes[ tess.numIndexes + i * 3 + 2 ] = offset + model->triangles[ 3 * ( surf->first_triangle + i ) + 2 ]; } tess.attribsSet |= ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT; if( model->num_joints > 0 && model->blendWeights && model->blendIndexes ) { // deform the vertices by the lerped bones for ( i = 0; i < surf->num_vertexes; i++ ) { int idxIn = surf->first_vertex + i; int idxOut = tess.numVertexes + i; const float weightFactor = 1.0f / 255.0f; vec3_t tangent, binormal, normal, tmp; if( model->blendWeights[ 4 * idxIn + 0 ] == 0 && model->blendWeights[ 4 * idxIn + 1 ] == 0 && model->blendWeights[ 4 * idxIn + 2 ] == 0 && model->blendWeights[ 4 * idxIn + 3 ] == 0 ) model->blendWeights[ 4 * idxIn + 0 ] = 255; VectorClear( tess.verts[ idxOut ].xyz ); VectorClear( normal ); VectorClear( tangent ); VectorClear( binormal ); for ( j = 0; j < 4; j++ ) { int bone = model->blendIndexes[ 4 * idxIn + j ]; float weight = weightFactor * model->blendWeights[ 4 * idxIn + j ]; TransformPoint( &bones[ bone ], &model->positions[ 3 * idxIn ], tmp ); VectorMA( tess.verts[ idxOut ].xyz, weight, tmp, tess.verts[ idxOut ].xyz ); TransformNormalVector( &bones[ bone ], &model->normals[ 3 * idxIn ], tmp ); VectorMA( normal, weight, tmp, normal ); TransformNormalVector( &bones[ bone ], &model->tangents[ 3 * idxIn ], tmp ); VectorMA( tangent, weight, tmp, tangent ); TransformNormalVector( &bones[ bone ], &model->bitangents[ 3 * idxIn ], tmp ); VectorMA( binormal, weight, tmp, binormal ); } VectorNormalize( normal ); VectorNormalize( tangent ); VectorNormalize( binormal ); R_TBNtoQtangents( tangent, binormal, normal, tess.verts[ idxOut ].qtangents ); tess.verts[ idxOut ].texCoords[ 0 ] = model->texcoords[ 2 * idxIn + 0 ]; tess.verts[ idxOut ].texCoords[ 1 ] = model->texcoords[ 2 * idxIn + 1 ]; } } else { for ( i = 0; i < surf->num_vertexes; i++ ) { int idxIn = surf->first_vertex + i; int idxOut = tess.numVertexes + i; float scale = model->internalScale * backEnd.currentEntity->e.skeleton.scale; VectorScale( &model->positions[ 3 * idxIn ], scale, tess.verts[ idxOut ].xyz ); R_TBNtoQtangents( &model->tangents[ 3 * idxIn ], &model->bitangents[ 3 * idxIn ], &model->normals[ 3 * idxIn ], tess.verts[ idxOut ].qtangents ); tess.verts[ idxOut ].texCoords[ 0 ] = model->texcoords[ 2 * idxIn + 0 ]; tess.verts[ idxOut ].texCoords[ 1 ] = model->texcoords[ 2 * idxIn + 1 ]; } } tess.numIndexes += 3 * surf->num_triangles; tess.numVertexes += surf->num_vertexes; }
/* ================== RB_RenderFlare ================== */ void RB_RenderFlare(flare_t * f) { float size; vec3_t color; backEnd.pc.c_flareRenders++; #if 1 //VectorScale(f->color, f->drawIntensity, color); VectorScale(colorWhite, f->drawIntensity, color); size = backEnd.viewParms.viewportWidth * (r_flareSize->value / 640.0f + 8 / -f->eyeZ); #else /* As flare sizes stay nearly constant with increasing distance we must decrease the intensity to achieve a reasonable visual result. The intensity is ~ (size^2 / distance^2) which can be got by considering the ratio of (flaresurface on screen) : (Surface of sphere defined by flare origin and distance from flare) An important requirement is: intensity <= 1 for all distances. The formula used here to compute the intensity is as follows: intensity = flareCoeff * size^2 / (distance + size*sqrt(flareCoeff))^2. As you can see, the intensity will have a max. of 1 when the distance is 0. The coefficient flareCoeff will determine the falloff speed with increasing distance. */ float distance, intensity, factor; // We don't want too big values anyways when dividing by distance if(f->eyeZ > -1.0f) distance = 1.0f; else distance = -f->eyeZ; // calculate the flare size size = backEnd.viewParms.viewportWidth * (r_flareSize->value / 640.0f + 8 / distance); factor = distance + size * sqrt(flareCoeff); intensity = flareCoeff * size * size / (factor * factor); VectorScale(f->color, f->drawIntensity * intensity, color); iColor[0] = color[0] * 255; iColor[1] = color[1] * 255; iColor[2] = color[2] * 255; #endif Tess_Begin(Tess_StageIteratorGeneric, tr.flareShader, NULL, qfalse, qfalse, -1); // FIXME: use quadstamp? tess.xyz[tess.numVertexes][0] = f->windowX - size; tess.xyz[tess.numVertexes][1] = f->windowY - size; tess.xyz[tess.numVertexes][2] = 0; tess.xyz[tess.numVertexes][3] = 1; tess.texCoords[tess.numVertexes][0] = 0; tess.texCoords[tess.numVertexes][1] = 0; tess.texCoords[tess.numVertexes][2] = 0; tess.texCoords[tess.numVertexes][3] = 1; tess.colors[tess.numVertexes][0] = color[0]; tess.colors[tess.numVertexes][1] = color[1]; tess.colors[tess.numVertexes][2] = color[2]; tess.colors[tess.numVertexes][3] = 1; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = f->windowX - size; tess.xyz[tess.numVertexes][1] = f->windowY + size; tess.xyz[tess.numVertexes][2] = 0; tess.xyz[tess.numVertexes][3] = 1; tess.texCoords[tess.numVertexes][0] = 0; tess.texCoords[tess.numVertexes][1] = 1; tess.texCoords[tess.numVertexes][2] = 0; tess.texCoords[tess.numVertexes][3] = 1; tess.colors[tess.numVertexes][0] = color[0]; tess.colors[tess.numVertexes][1] = color[1]; tess.colors[tess.numVertexes][2] = color[2]; tess.colors[tess.numVertexes][3] = 1; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = f->windowX + size; tess.xyz[tess.numVertexes][1] = f->windowY + size; tess.xyz[tess.numVertexes][2] = 0; tess.xyz[tess.numVertexes][3] = 1; tess.texCoords[tess.numVertexes][0] = 1; tess.texCoords[tess.numVertexes][1] = 1; tess.texCoords[tess.numVertexes][2] = 0; tess.texCoords[tess.numVertexes][3] = 1; tess.colors[tess.numVertexes][0] = color[0]; tess.colors[tess.numVertexes][1] = color[1]; tess.colors[tess.numVertexes][2] = color[2]; tess.colors[tess.numVertexes][3] = 1; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = f->windowX + size; tess.xyz[tess.numVertexes][1] = f->windowY - size; tess.xyz[tess.numVertexes][2] = 0; tess.xyz[tess.numVertexes][3] = 1; tess.texCoords[tess.numVertexes][0] = 1; tess.texCoords[tess.numVertexes][1] = 0; tess.texCoords[tess.numVertexes][2] = 0; tess.texCoords[tess.numVertexes][3] = 1; tess.colors[tess.numVertexes][0] = color[0]; tess.colors[tess.numVertexes][1] = color[1]; tess.colors[tess.numVertexes][2] = color[2]; tess.colors[tess.numVertexes][3] = 1; tess.numVertexes++; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 1; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 3; Tess_End(); }
/* ** RB_DrawSun */ void RB_DrawSun(void) { float size; float dist; vec3_t origin, vec1, vec2; vec3_t temp; matrix_t transformMatrix; matrix_t modelViewMatrix; if (!backEnd.skyRenderedThisView) { return; } if (!r_drawSun->integer) { return; } #if defined(USE_D3D10) //TODO #else GL_PushMatrix(); gl_genericShader->DisableAlphaTesting(); gl_genericShader->DisablePortalClipping(); gl_genericShader->DisableVertexSkinning(); gl_genericShader->DisableVertexAnimation(); gl_genericShader->DisableDeformVertexes(); gl_genericShader->DisableTCGenEnvironment(); gl_genericShader->BindProgram(); // set uniforms gl_genericShader->SetUniform_ColorModulate(CGEN_VERTEX, AGEN_VERTEX); #endif MatrixSetupTranslation(transformMatrix, backEnd.viewParms.orientation.origin[0], backEnd.viewParms.orientation.origin[1], backEnd.viewParms.orientation.origin[2]); MatrixMultiplyMOD(backEnd.viewParms.world.viewMatrix, transformMatrix, modelViewMatrix); #if defined(USE_D3D10) //TODO #else GL_LoadProjectionMatrix(backEnd.viewParms.projectionMatrix); GL_LoadModelViewMatrix(modelViewMatrix); gl_genericShader->SetUniform_ModelMatrix(backEnd.orientation.transformMatrix); gl_genericShader->SetUniform_ModelViewProjectionMatrix(glState.modelViewProjectionMatrix[glState.stackIndex]); gl_genericShader->SetPortalClipping(backEnd.viewParms.isPortal); #endif if (backEnd.viewParms.isPortal) { float plane[4]; // clipping plane in world space plane[0] = backEnd.viewParms.portalPlane.normal[0]; plane[1] = backEnd.viewParms.portalPlane.normal[1]; plane[2] = backEnd.viewParms.portalPlane.normal[2]; plane[3] = backEnd.viewParms.portalPlane.dist; #if defined(USE_D3D10) //TODO #else gl_genericShader->SetUniform_PortalPlane(plane); #endif } dist = backEnd.viewParms.skyFar / 1.75; // div sqrt(3) size = dist * 0.4; VectorScale(tr.sunDirection, dist, origin); PerpendicularVector(vec1, tr.sunDirection); CrossProduct(tr.sunDirection, vec1, vec2); VectorScale(vec1, size, vec1); VectorScale(vec2, size, vec2); // farthest depth range #if defined(USE_D3D10) //TODO #else glDepthRange(1.0, 1.0); #endif // FIXME: use quad stamp Tess_Begin(Tess_StageIteratorGeneric, NULL, tr.sunShader, NULL, tess.skipTangentSpaces, qfalse, -1, tess.fogNum); VectorCopy(origin, temp); VectorSubtract(temp, vec1, temp); VectorSubtract(temp, vec2, temp); VectorCopy(temp, tess.xyz[tess.numVertexes]); tess.xyz[tess.numVertexes][3] = 1; tess.texCoords[tess.numVertexes][0] = 0; tess.texCoords[tess.numVertexes][1] = 0; tess.texCoords[tess.numVertexes][2] = 0; tess.texCoords[tess.numVertexes][3] = 1; tess.colors[tess.numVertexes][0] = 1; tess.colors[tess.numVertexes][1] = 1; tess.colors[tess.numVertexes][2] = 1; tess.numVertexes++; VectorCopy(origin, temp); VectorAdd(temp, vec1, temp); VectorSubtract(temp, vec2, temp); VectorCopy(temp, tess.xyz[tess.numVertexes]); tess.xyz[tess.numVertexes][3] = 1; tess.texCoords[tess.numVertexes][0] = 0; tess.texCoords[tess.numVertexes][1] = 1; tess.texCoords[tess.numVertexes][2] = 0; tess.texCoords[tess.numVertexes][3] = 1; tess.colors[tess.numVertexes][0] = 1; tess.colors[tess.numVertexes][1] = 1; tess.colors[tess.numVertexes][2] = 1; tess.numVertexes++; VectorCopy(origin, temp); VectorAdd(temp, vec1, temp); VectorAdd(temp, vec2, temp); VectorCopy(temp, tess.xyz[tess.numVertexes]); tess.xyz[tess.numVertexes][3] = 1; tess.texCoords[tess.numVertexes][0] = 1; tess.texCoords[tess.numVertexes][1] = 1; tess.texCoords[tess.numVertexes][2] = 0; tess.texCoords[tess.numVertexes][3] = 1; tess.colors[tess.numVertexes][0] = 1; tess.colors[tess.numVertexes][1] = 1; tess.colors[tess.numVertexes][2] = 1; tess.numVertexes++; VectorCopy(origin, temp); VectorSubtract(temp, vec1, temp); VectorAdd(temp, vec2, temp); VectorCopy(temp, tess.xyz[tess.numVertexes]); tess.xyz[tess.numVertexes][3] = 1; tess.texCoords[tess.numVertexes][0] = 1; tess.texCoords[tess.numVertexes][1] = 0; tess.texCoords[tess.numVertexes][2] = 0; tess.texCoords[tess.numVertexes][3] = 1; tess.colors[tess.numVertexes][0] = 1; tess.colors[tess.numVertexes][1] = 1; tess.colors[tess.numVertexes][2] = 1; tess.numVertexes++; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 1; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 3; Tess_End(); // back to normal depth range #if defined(USE_D3D10) //TODO #else glDepthRange(0.0, 1.0); GL_PopMatrix(); #endif }