Example #1
0
/*
==============
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 );
}
Example #2
0
/*
** 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
	}
Example #5
0
/*
==============
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 );
}
Example #6
0
/*
==================
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();
}
Example #7
0
/*
** 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
}