Esempio n. 1
0
/*
* R_DrawBlackBottom
* 
* Draw dummy skybox side to prevent the HOM effect
*/
static void R_DrawBlackBottom( const skydome_t *skydome, const visSkySide_t *visSides )
{
	int side = 5;
	const visSkySide_t *visSide = visSides + side;

	if( rn.skyMins[0][side] >= rn.skyMaxs[0][side] ||
		rn.skyMins[1][side] >= rn.skyMaxs[1][side] )
		return;

	RB_BindShader( rsc.worldent, rf.envShader, rn.skyFog );

	RB_BindVBO( skydome->linearVbos[side]->index, GL_TRIANGLES );

	RB_DrawElements( visSide->firstVert, visSide->numVerts, visSide->firstElem, visSide->numElems );
}
Esempio n. 2
0
/*
* R_DrawBlackBottom
*
* Draw dummy skybox side to prevent the HOM effect
*/
static void R_DrawBlackBottom( const skydome_t *skydome, const visSkySide_t *visSides, const mfog_t *fog, drawSurfaceSky_t *drawSurf ) {
	int side = 5;
	const visSkySide_t *visSide = visSides + side;

	if( drawSurf->skyMins[0][side] >= drawSurf->skyMaxs[0][side] ||
		drawSurf->skyMins[1][side] >= drawSurf->skyMaxs[1][side] ) {
		return;
	}

	RB_BindShader( rsc.skyent, rsh.envShader, fog );

	RB_BindVBO( skydome->linearVbos[side]->index, GL_TRIANGLES );

	RB_DrawElements( visSide->firstVert, visSide->numVerts, visSide->firstElem, visSide->numElems, 0, 0, 0, 0 );
}
Esempio n. 3
0
/*
* R_DrawSkyBoxSide
*/
static void R_DrawSkyBoxSide( const skydome_t *skydome, const visSkySide_t *visSide, const shader_t *skyShader,
							  const shader_t *skyboxShader, const mfog_t *fog, int imageIndex, drawSurfaceSky_t *drawSurf ) {
	int side = visSide->index;

	if( drawSurf->skyMins[0][side] >= drawSurf->skyMaxs[0][side] ||
		drawSurf->skyMins[1][side] >= drawSurf->skyMaxs[1][side] ) {
		return;
	}

	RB_BindShader( rsc.skyent, skyShader, fog );

	RB_BindVBO( skydome->linearVbos[side]->index, GL_TRIANGLES );

	RB_SetSkyboxShader( skyboxShader );

	RB_SetSkyboxSide( imageIndex );

	RB_DrawElements( visSide->firstVert, visSide->numVerts, visSide->firstElem, visSide->numElems, 0, 0, 0, 0 );
}
Esempio n. 4
0
/*
* R_DrawSkyBoxSide
*/
static void R_DrawSkyBoxSide( const skydome_t *skydome, const visSkySide_t *visSide, const shader_t *shader, 
	int imageIndex )
{
	int side = visSide->index;

	if( rn.skyMins[0][side] >= rn.skyMaxs[0][side] ||
		rn.skyMins[1][side] >= rn.skyMaxs[1][side] )
		return;

	RB_BindShader( rsc.worldent, rf.skyShader, rn.skyFog );

	RB_BindVBO( skydome->linearVbos[side]->index, GL_TRIANGLES );

	RB_SetSkyboxShader( shader );

	RB_SetSkyboxSide( imageIndex );

	RB_DrawElements( visSide->firstVert, visSide->numVerts, visSide->firstElem, visSide->numElems );
}
Esempio n. 5
0
/*
* R_RenderDebugBounds
*/
static void R_RenderDebugBounds( void )
{
	int i, j;
	vec3_t corner;
	const vec_t *mins, *maxs;
	mesh_t *rb_mesh;
	elem_t elems[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };

	if( !r_num_debug_bounds )
		return;

	RB_EnableTriangleOutlines( qtrue );

	RB_BindShader( rsc.worldent, rsh.whiteShader, NULL );

	RB_BindVBO( RB_VBO_STREAM, GL_TRIANGLE_STRIP );

	for( i = 0; i < r_num_debug_bounds; i++ )
	{
		mins = r_debug_bounds[i].mins;
		maxs = r_debug_bounds[i].maxs;

		rb_mesh = RB_MapBatchMesh( 8, 8 );
		for( j = 0; j < 8; j++ )
		{
			corner[0] = ( ( j & 1 ) ? mins[0] : maxs[0] );
			corner[1] = ( ( j & 2 ) ? mins[1] : maxs[1] );
			corner[2] = ( ( j & 4 ) ? mins[2] : maxs[2] );
			VectorCopy( corner, rb_mesh->xyzArray[j] );
		}

		rb_mesh->numVerts = 8;
		rb_mesh->numElems = 8;
		rb_mesh->elems = elems;
		RB_UploadMesh( rb_mesh );

		RB_EndBatch();
	}

	RB_EnableTriangleOutlines( qfalse );
}
Esempio n. 6
0
/*
* RB_FlushDynamicMeshes
*/
void RB_FlushDynamicMeshes( void )
{
    int i, numDraws = rb.numDynamicDraws;
    rbDynamicStream_t *stream;
    rbDynamicDraw_t *draw;
    int sx, sy, sw, sh;
    float offsetx = 0.0f, offsety = 0.0f, transx, transy;
    mat4_t m;

    if( !numDraws ) {
        return;
    }

    for( i = 0; i < RB_VBO_NUM_STREAMS; i++ ) {
        stream = &rb.dynamicStreams[i];

        // R_UploadVBO* are going to rebind buffer arrays for upload
        // so update our local VBO state cache by calling RB_BindVBO
        RB_BindVBO( -i - 1, GL_TRIANGLES ); // dummy value for primitive here

        // because of firstVert, upload elems first
        if( stream->drawElements.numElems ) {
            mesh_t elemMesh;
            memset( &elemMesh, 0, sizeof( elemMesh ) );
            elemMesh.elems = dynamicStreamElems[i] + stream->drawElements.firstElem;
            elemMesh.numElems = stream->drawElements.numElems;
            R_UploadVBOElemData( stream->vbo, 0, stream->drawElements.firstElem, &elemMesh );
            stream->drawElements.firstElem += stream->drawElements.numElems;
            stream->drawElements.numElems = 0;
        }

        if( stream->drawElements.numVerts ) {
            R_UploadVBOVertexRawData( stream->vbo, stream->drawElements.firstVert, stream->drawElements.numVerts,
                                      stream->vertexData + stream->drawElements.firstVert * stream->vbo->vertexSize );
            stream->drawElements.firstVert += stream->drawElements.numVerts;
            stream->drawElements.numVerts = 0;
        }
    }

    RB_GetScissor( &sx, &sy, &sw, &sh );

    Matrix4_Copy( rb.objectMatrix, m );
    transx = m[12];
    transy = m[13];

    for( i = 0, draw = rb.dynamicDraws; i < numDraws; i++, draw++ ) {
        RB_BindShader( draw->entity, draw->shader, draw->fog );
        RB_BindVBO( draw->streamId, draw->primitive );
        RB_SetPortalSurface( draw->portalSurface );
        RB_SetShadowBits( draw->shadowBits );
        RB_Scissor( draw->scissor[0], draw->scissor[1], draw->scissor[2], draw->scissor[3] );

        // translate the mesh in 2D
        if( ( offsetx != draw->offset[0] ) || ( offsety != draw->offset[1] ) ) {
            offsetx = draw->offset[0];
            offsety = draw->offset[1];
            m[12] = transx + offsetx;
            m[13] = transy + offsety;
            RB_LoadObjectMatrix( m );
        }

        RB_DrawElements(
            draw->drawElements.firstVert, draw->drawElements.numVerts,
            draw->drawElements.firstElem, draw->drawElements.numElems,
            draw->drawElements.firstVert, draw->drawElements.numVerts,
            draw->drawElements.firstElem, draw->drawElements.numElems );
    }

    rb.numDynamicDraws = 0;

    RB_Scissor( sx, sy, sw, sh );

    // restore the original translation in the object matrix if it has been changed
    if( offsetx || offsety ) {
        m[12] = transx;
        m[13] = transy;
        RB_LoadObjectMatrix( m );
    }
}
Esempio n. 7
0
/*
* RB_AddDynamicMesh
*/
void RB_AddDynamicMesh( const entity_t *entity, const shader_t *shader,
                        const struct mfog_s *fog, const struct portalSurface_s *portalSurface, unsigned int shadowBits,
                        const struct mesh_s *mesh, int primitive, float x_offset, float y_offset )
{
    int numVerts = mesh->numVerts, numElems = mesh->numElems;
    bool trifan = false;
    int scissor[4];
    rbDynamicDraw_t *prev = NULL, *draw;
    bool merge = false;
    vattribmask_t vattribs;
    int streamId = RB_VBO_NONE;
    rbDynamicStream_t *stream;
    int destVertOffset;
    elem_t *destElems;

    // can't (and shouldn't because that would break batching) merge strip draw calls
    // (consider simply disabling merge later in this case if models with tristrips are added in the future, but that's slow)
    assert( ( primitive == GL_TRIANGLES ) || ( primitive == GL_LINES ) );

    if( !numElems ) {
        numElems = ( max( numVerts, 2 ) - 2 ) * 3;
        trifan = true;
    }
    if( !numVerts || !numElems || ( numVerts > MAX_STREAM_VBO_VERTS ) || ( numElems > MAX_STREAM_VBO_ELEMENTS ) ) {
        return;
    }

    RB_GetScissor( &scissor[0], &scissor[1], &scissor[2], &scissor[3] );

    if( rb.numDynamicDraws ) {
        prev = &rb.dynamicDraws[rb.numDynamicDraws - 1];
    }

    if( prev ) {
        int prevRenderFX = 0, renderFX = 0;
        if( prev->entity ) {
            prevRenderFX = prev->entity->renderfx;
        }
        if( entity ) {
            renderFX = entity->renderfx;
        }
        if( ( ( shader->flags & SHADER_ENTITY_MERGABLE ) || ( prev->entity == entity ) ) && ( prevRenderFX == renderFX ) &&
                ( prev->shader == shader ) && ( prev->fog == fog ) && ( prev->portalSurface == portalSurface ) &&
                ( ( prev->shadowBits && shadowBits ) || ( !prev->shadowBits && !shadowBits ) ) ) {
            // don't rebind the shader to get the VBO in this case
            streamId = prev->streamId;
            if( ( prev->shadowBits == shadowBits ) && ( prev->primitive == primitive ) &&
                    ( prev->offset[0] == x_offset ) && ( prev->offset[1] == y_offset ) &&
                    !memcmp( prev->scissor, scissor, sizeof( scissor ) ) ) {
                merge = true;
            }
        }
    }

    if( streamId == RB_VBO_NONE ) {
        RB_BindShader( entity, shader, fog );
        vattribs = rb.currentVAttribs;
        streamId = ( ( vattribs & ~COMPACT_STREAM_VATTRIBS ) ? RB_VBO_STREAM : RB_VBO_STREAM_COMPACT );
    }
    else {
        vattribs = prev->vattribs;
    }

    stream = &rb.dynamicStreams[-streamId - 1];

    if( ( !merge && ( ( rb.numDynamicDraws + 1 ) > MAX_DYNAMIC_DRAWS ) ) ||
            ( ( stream->drawElements.firstVert + stream->drawElements.numVerts + numVerts ) > MAX_STREAM_VBO_VERTS ) ||
            ( ( stream->drawElements.firstElem + stream->drawElements.numElems + numElems ) > MAX_STREAM_VBO_ELEMENTS ) ) {
        // wrap if overflows
        RB_FlushDynamicMeshes();

        stream->drawElements.firstVert = 0;
        stream->drawElements.numVerts = 0;
        stream->drawElements.firstElem = 0;
        stream->drawElements.numElems = 0;

        merge = false;
    }

    if( merge ) {
        // merge continuous draw calls
        draw = prev;
        draw->drawElements.numVerts += numVerts;
        draw->drawElements.numElems += numElems;
    }
    else {
        draw = &rb.dynamicDraws[rb.numDynamicDraws++];
        draw->entity = entity;
        draw->shader = shader;
        draw->fog = fog;
        draw->portalSurface = portalSurface;
        draw->shadowBits = shadowBits;
        draw->vattribs = vattribs;
        draw->streamId = streamId;
        draw->primitive = primitive;
        draw->offset[0] = x_offset;
        draw->offset[1] = y_offset;
        memcpy( draw->scissor, scissor, sizeof( scissor ) );
        draw->drawElements.firstVert = stream->drawElements.firstVert + stream->drawElements.numVerts;
        draw->drawElements.numVerts = numVerts;
        draw->drawElements.firstElem = stream->drawElements.firstElem + stream->drawElements.numElems;
        draw->drawElements.numElems = numElems;
        draw->drawElements.numInstances = 0;
    }

    destVertOffset = stream->drawElements.firstVert + stream->drawElements.numVerts;
    R_FillVBOVertexDataBuffer( stream->vbo, vattribs, mesh,
                               stream->vertexData + destVertOffset * stream->vbo->vertexSize );

    destElems = dynamicStreamElems[-streamId - 1] + stream->drawElements.firstElem + stream->drawElements.numElems;
    if( trifan ) {
        R_BuildTrifanElements( destVertOffset, numElems, destElems );
    }
    else {
        if( primitive == GL_TRIANGLES ) {
            R_CopyOffsetTriangles( mesh->elems, numElems, destVertOffset, destElems );
        }
        else {
            R_CopyOffsetElements( mesh->elems, numElems, destVertOffset, destElems );
        }
    }

    stream->drawElements.numVerts += numVerts;
    stream->drawElements.numElems += numElems;
}
Esempio n. 8
0
/*
* R_DrawSkySurf
*/
void R_DrawSkySurf( const entity_t *e, const shader_t *shader, const mfog_t *fog, const portalSurface_t *portalSurface, 
	                unsigned int shadowBits, drawSurfaceSky_t *drawSurf ) {
	int i;
	int numVisSides;
	visSkySide_t visSkySides[6];
	vec3_t mins, maxs;
	int umin, umax, vmin, vmax;
	bool skyportal = portalSurface != NULL && portalSurface->skyPortal;
	skydome_t *skydome = rsh.worldBrushModel->skydome;

	if( !skydome ) {
		return;
	}
	if( skyportal && !fog ) {
		return;
	}

	numVisSides = 0;
	ClearBounds( mins, maxs );

	memset( visSkySides, 0, sizeof( visSkySides ) );

	for( i = 0; i < 6; i++ ) {
		if( drawSurf->skyMins[0][i] >= drawSurf->skyMaxs[0][i] ||
			drawSurf->skyMins[1][i] >= drawSurf->skyMaxs[1][i] ) {
			continue;
		}

		// increase the visible sides counter
		numVisSides++;

		umin = (int)( ( drawSurf->skyMins[0][i] + 1.0f ) * 0.5f * (float)( SIDE_SIZE - 1 ) );
		umax = (int)( ( drawSurf->skyMaxs[0][i] + 1.0f ) * 0.5f * (float)( SIDE_SIZE - 1 ) ) + 1;
		vmin = (int)( ( drawSurf->skyMins[1][i] + 1.0f ) * 0.5f * (float)( SIDE_SIZE - 1 ) );
		vmax = (int)( ( drawSurf->skyMaxs[1][i] + 1.0f ) * 0.5f * (float)( SIDE_SIZE - 1 ) ) + 1;

		clamp( umin, 0, SIDE_SIZE - 1 );
		clamp( umax, 0, SIDE_SIZE - 1 );
		clamp( vmin, 0, SIDE_SIZE - 1 );
		clamp( vmax, 0, SIDE_SIZE - 1 );

		visSkySides[i].index = i;
		visSkySides[i].firstVert = vmin * SIDE_SIZE + umin;
		visSkySides[i].numVerts = ( vmax - vmin ) * SIDE_SIZE + ( umax - umin ) + 1;
		visSkySides[i].firstElem = ( vmin * ( SIDE_SIZE - 2 ) + umin ) * 6;
		visSkySides[i].numElems = ( ( vmax - vmin ) * ( SIDE_SIZE - 2 ) + ( umax - umin ) ) * 6;

		clamp( visSkySides[i].firstVert, 0, POINTS_LEN - 1 );
		clamp( visSkySides[i].numVerts, 0, POINTS_LEN );

		clamp( visSkySides[i].firstElem, 0, ELEM_LEN - 1 );
		clamp( visSkySides[i].numElems, 0, ELEM_LEN );

		skydome->meshes[i].numElems = visSkySides[i].numElems;
	}

	// no sides are truly visible, ignore
	if( !numVisSides ) {
		return;
	}

	// center skydome on camera to give the illusion of a larger space
	rsc.skyent->scale = shader->skyHeight;
	VectorCopy( rn.viewOrigin, rsc.skyent->origin );
	R_TransformForEntity( rsc.skyent );

	if( skyportal ) {
		// render fake fogged skybox
		R_DrawSkyBox( skydome, visSkySides, rsh.emptyFogShader, shader, fog, drawSurf );
	} else {
		if( shader->skyboxImages[0] ) {
			R_DrawSkyBox( skydome, visSkySides, rsh.skyShader, shader, fog, drawSurf );
		} else {
			R_DrawBlackBottom( skydome, visSkySides, fog, drawSurf );
		}

		if( shader->numpasses ) {
			for( i = 0; i < 5; i++ ) {
				const visSkySide_t *visSide = visSkySides + i;

				if( drawSurf->skyMins[0][i] >= drawSurf->skyMaxs[0][i] ||
					drawSurf->skyMins[1][i] >= drawSurf->skyMaxs[1][i] ) {
					continue;
				}

				RB_BindShader( rsc.skyent, shader, NULL ); // must be called for every side to reset backend state

				RB_BindVBO( skydome->sphereVbos[i]->index, GL_TRIANGLES );

				RB_DrawElements( visSide->firstVert, visSide->numVerts, visSide->firstElem, visSide->numElems, 0, 0, 0, 0 );
			}
		}
	}

	R_TransformForEntity( e );
}
Esempio n. 9
0
/*
* R_BlitTextureToScrFbo
*/
static void R_BlitTextureToScrFbo( const refdef_t *fd, image_t *image, int dstFbo, 
	int program_type, const vec4_t color, int blendMask, int numShaderImages, image_t **shaderImages )
{
	int x, y;
	int w, h, fw, fh;
	static char s_name[] = "$builtinpostprocessing";
	static shaderpass_t p;
	static shader_t s;
	int i;
	static tcmod_t tcmod;
	mat4_t m;

	assert( rsh.postProcessingVBO );

	// blit + flip using a static mesh to avoid redundant buffer uploads
	// (also using custom PP effects like FXAA with the stream VBO causes
	// Adreno to mark the VBO as "slow" (due to some weird bug)
	// for the rest of the frame and drop FPS to 10-20).
	RB_FlushDynamicMeshes();

	RB_BindFrameBufferObject( dstFbo );

	if( !dstFbo ) {
		// default framebuffer
		// set the viewport to full resolution
		// but keep the scissoring region
		x = fd->x;
		y = fd->y;
		w = fw = fd->width;
		h = fh = fd->height;
		RB_Viewport( 0, 0, glConfig.width, glConfig.height );
		RB_Scissor( rn.scissor[0], rn.scissor[1], rn.scissor[2], rn.scissor[3] );
	}
	else {
		// aux framebuffer
		// set the viewport to full resolution of the framebuffer (without the NPOT padding if there's one)
		// draw quad on the whole framebuffer texture
		// set scissor to default framebuffer resolution
		image_t *cb = RFB_GetObjectTextureAttachment( dstFbo, false );
		x = 0;
		y = 0;
		w = fw = rf.frameBufferWidth;
		h = fh = rf.frameBufferHeight;
		if( cb ) {
			fw = cb->upload_width;
			fh = cb->upload_height;
		}
		RB_Viewport( 0, 0, w, h );
		RB_Scissor( 0, 0, glConfig.width, glConfig.height );
	}

	s.vattribs = VATTRIB_POSITION_BIT|VATTRIB_TEXCOORDS_BIT;
	s.sort = SHADER_SORT_NEAREST;
	s.numpasses = 1;
	s.name = s_name;
	s.passes = &p;

	p.rgbgen.type = RGB_GEN_IDENTITY;
	p.alphagen.type = ALPHA_GEN_IDENTITY;
	p.tcgen = TC_GEN_NONE;
	p.images[0] = image;
	for( i = 0; i < numShaderImages; i++ )
		p.images[i + 1] = shaderImages[i];
	p.flags = blendMask;
	p.program_type = program_type;

	if( !dstFbo ) {
		tcmod.type = TC_MOD_TRANSFORM;
		tcmod.args[0] = ( float )( w ) / ( float )( image->upload_width );
		tcmod.args[1] = ( float )( h ) / ( float )( image->upload_height );
		tcmod.args[4] = ( float )( x ) / ( float )( image->upload_width );
		tcmod.args[5] = ( float )( image->upload_height - h - y ) / ( float )( image->upload_height );
		p.numtcmods = 1;
		p.tcmods = &tcmod;
	}
	else {
		p.numtcmods = 0;
	}

	Matrix4_Identity( m );
	Matrix4_Scale2D( m, fw, fh );
	Matrix4_Translate2D( m, x, y );
	RB_LoadObjectMatrix( m );

	RB_BindShader( NULL, &s, NULL );
	RB_BindVBO( rsh.postProcessingVBO->index, GL_TRIANGLES );
	RB_DrawElements( 0, 4, 0, 6, 0, 0, 0, 0 );

	RB_LoadObjectMatrix( mat4x4_identity );

	// restore 2D viewport and scissor
	RB_Viewport( 0, 0, rf.frameBufferWidth, rf.frameBufferHeight );
	RB_Scissor( 0, 0, rf.frameBufferWidth, rf.frameBufferHeight );
}
Esempio n. 10
0
/*
* R_DrawSkySurf
*/
qboolean R_DrawSkySurf( const entity_t *e, const shader_t *shader, const mfog_t *fog, drawSurfaceBSP_t *drawSurf )
{
	int i;
	int numVisSides;
	visSkySide_t visSkySides[6];
	vec3_t mins, maxs;
	int umin, umax, vmin, vmax;
	entity_t skyent;
	refdef_t *rd = &rn.refdef;
	skydome_t *skydome = r_worldbrushmodel->skydome;

	if( !skydome )
		return qfalse;

	numVisSides = 0;
	ClearBounds( mins, maxs );

	memset( visSkySides, 0, sizeof( visSkySides ) );

	for( i = 0; i < 6; i++ )
	{
		if( rn.skyMins[0][i] >= rn.skyMaxs[0][i] ||
			rn.skyMins[1][i] >= rn.skyMaxs[1][i] )
			continue;

		// increase the visible sides counter
		numVisSides++;

		umin = (int)( ( rn.skyMins[0][i]+1.0f )*0.5f*(float)( SIDE_SIZE-1 ) );
		umax = (int)( ( rn.skyMaxs[0][i]+1.0f )*0.5f*(float)( SIDE_SIZE-1 ) ) + 1;
		vmin = (int)( ( rn.skyMins[1][i]+1.0f )*0.5f*(float)( SIDE_SIZE-1 ) );
		vmax = (int)( ( rn.skyMaxs[1][i]+1.0f )*0.5f*(float)( SIDE_SIZE-1 ) ) + 1;

		clamp( umin, 0, SIDE_SIZE-1 );
		clamp( umax, 0, SIDE_SIZE-1 );
		clamp( vmin, 0, SIDE_SIZE-1 );
		clamp( vmax, 0, SIDE_SIZE-1 );

		visSkySides[i].index = i;
		visSkySides[i].firstVert = vmin * SIDE_SIZE + umin;
		visSkySides[i].numVerts = (vmax - vmin) * SIDE_SIZE + (umax - umin);
		visSkySides[i].firstElem = (vmin * (SIDE_SIZE-1) + umin) * 6;
		visSkySides[i].numElems = ((vmax - vmin) * (SIDE_SIZE-1) + (umax - umin)) * 6;

		AddPointToBounds( skydome->meshes[i].xyzArray[vmin*SIDE_SIZE+umin], mins, maxs );
		AddPointToBounds( skydome->meshes[i].xyzArray[vmax*SIDE_SIZE+umax], mins, maxs );

		skydome->meshes[i].numElems = visSkySides[i].numElems;
	}

	// no sides are truly visible, ignore
	if( !numVisSides )
		return qfalse;

	VectorAdd( mins, rn.viewOrigin, mins );
	VectorAdd( maxs, rn.viewOrigin, maxs );

	if( rd->rdflags & RDF_SKYPORTALINVIEW ) {
		R_DrawSkyPortal( e, &rd->skyportal, mins, maxs );
		return qfalse;
	}

	// center skydome on camera to give the illusion of a larger space
	skyent = *rsc.worldent;
	skyent.scale = shader->skyHeight;
	VectorCopy( rn.viewOrigin, skyent.origin );
	R_TransformForEntity( &skyent );

	if( shader->skyboxImages[0] )
		R_DrawSkyBox( skydome, visSkySides, shader );
	else
		R_DrawBlackBottom( skydome, visSkySides );

	if( shader->numpasses )
	{
		RB_BindShader( rsc.worldent, shader, rn.skyFog );

		for( i = 0; i < 5; i++ )
		{
			const visSkySide_t *visSide = visSkySides + i;

			if( rn.skyMins[0][i] >= rn.skyMaxs[0][i] ||
				rn.skyMins[1][i] >= rn.skyMaxs[1][i] )
				continue;

			RB_BindVBO( skydome->sphereVbos[i]->index, GL_TRIANGLES );

			RB_DrawElements( visSide->firstVert, visSide->numVerts, visSide->firstElem, visSide->numElems );
		}
	}

	R_TransformForEntity( e );

	return qfalse;
}