Beispiel #1
0
/*
==============
RenderBumpTriangles

==============
*/
static void RenderBumpTriangles( srfTriangles_t *lowMesh, renderBump_t *rb ) {
	int		i, j;

	RB_SetGL2D();

	qglDisable( GL_CULL_FACE );

	qglColor3f( 1, 1, 1 );

	qglMatrixMode( GL_PROJECTION );
	qglLoadIdentity();
	qglOrtho( 0, 1, 1, 0, -1, 1 );
	qglDisable( GL_BLEND );
	qglMatrixMode( GL_MODELVIEW );
	qglLoadIdentity();

	qglDisable( GL_DEPTH_TEST );

	qglClearColor(1,0,0,1);
	qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	qglColor3f( 1, 1, 1 );

	// create smoothed normals for the surface, which might be
	// different than the normals at the vertexes if the
	// surface uses unsmoothedNormals, which only takes the
	// normal from a single triangle.  We need properly smoothed
	// normals to make sure that the traces always go off normal
	// to the true surface.
	idVec3	*lowMeshNormals = (idVec3 *)Mem_ClearedAlloc( lowMesh->numVerts * sizeof( *lowMeshNormals ) );
	R_DeriveFacePlanes( lowMesh );
	R_CreateSilIndexes( lowMesh );	// recreate, merging the mirrored verts back together
	const idPlane *planes = lowMesh->facePlanes;
	for ( i = 0 ; i < lowMesh->numIndexes ; i += 3, planes++ ) {
		for ( j = 0 ; j < 3 ; j++ ) {
			int		index;

			index = lowMesh->silIndexes[i+j];
			lowMeshNormals[index] += (*planes).Normal();
		}
	}
	// normalize and replicate from silIndexes to all indexes
	for ( i = 0 ; i < lowMesh->numIndexes ; i++ ) {
		lowMeshNormals[lowMesh->indexes[i]] = lowMeshNormals[lowMesh->silIndexes[i]];
		lowMeshNormals[lowMesh->indexes[i]].Normalize();
	}


	// rasterize each low poly face
	for ( j = 0 ; j < lowMesh->numIndexes ; j+=3 ) {
		// pump the event loop so the window can be dragged around
		Sys_GenerateEvents();

		RasterizeTriangle( lowMesh, lowMeshNormals, j/3, rb );

		qglClearColor(1,0,0,1);
		qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
		qglRasterPos2f( 0, 1 );
		qglPixelZoom( glConfig.vidWidth / (float)rb->width, glConfig.vidHeight / (float)rb->height );
		qglDrawPixels( rb->width, rb->height, GL_RGBA, GL_UNSIGNED_BYTE, rb->localPic );
		qglPixelZoom( 1, 1 );
		qglFlush();
		GLimp_SwapBuffers();
	}

	Mem_Free( lowMeshNormals );
}
Beispiel #2
0
/*
==================
RB_ARB2_DrawInteractions
==================
*/
void RB_ARB2_DrawInteractions( void ) {
	viewLight_t		*vLight;
	const idMaterial	*lightShader;

	GL_SelectTexture( 0 );
	qglDisableClientState( GL_TEXTURE_COORD_ARRAY );

	//
	// for each light, perform adding and shadowing
	//
	for ( vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) {
		backEnd.vLight = vLight;

		// do fogging later
		if ( vLight->lightShader->IsFogLight() ) {
			continue;
		}
		if ( vLight->lightShader->IsBlendLight() ) {
			continue;
		}

		if ( !vLight->localInteractions && !vLight->globalInteractions
			&& !vLight->translucentInteractions ) {
			continue;
		}

		lightShader = vLight->lightShader;

		// clear the stencil buffer if needed
		if ( vLight->globalShadows || vLight->localShadows ) {
			backEnd.currentScissor = vLight->scissorRect;
			if ( r_useScissor.GetBool() ) {
				qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1, 
					backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1,
					backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1,
					backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 );
			}
			qglClear( GL_STENCIL_BUFFER_BIT );
		} else {
			// no shadows, so no need to read or write the stencil buffer
			// we might in theory want to use GL_ALWAYS instead of disabling
			// completely, to satisfy the invarience rules
			qglStencilFunc( GL_ALWAYS, 128, 255 );
		}

		if ( r_useShadowVertexProgram.GetBool() ) {
			qglEnable( GL_VERTEX_PROGRAM_ARB );
			qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_STENCIL_SHADOW );
			RB_StencilShadowPass( vLight->globalShadows );
			RB_ARB2_CreateDrawInteractions( vLight->localInteractions );
			qglEnable( GL_VERTEX_PROGRAM_ARB );
			qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_STENCIL_SHADOW );
			RB_StencilShadowPass( vLight->localShadows );
			RB_ARB2_CreateDrawInteractions( vLight->globalInteractions );
			qglDisable( GL_VERTEX_PROGRAM_ARB );	// if there weren't any globalInteractions, it would have stayed on
		} else {
			RB_StencilShadowPass( vLight->globalShadows );
			RB_ARB2_CreateDrawInteractions( vLight->localInteractions );
			RB_StencilShadowPass( vLight->localShadows );
			RB_ARB2_CreateDrawInteractions( vLight->globalInteractions );
		}

		// translucent surfaces never get stencil shadowed
		if ( r_skipTranslucent.GetBool() ) {
			continue;
		}

		qglStencilFunc( GL_ALWAYS, 128, 255 );

		backEnd.depthFunc = GLS_DEPTHFUNC_LESS;
		RB_ARB2_CreateDrawInteractions( vLight->translucentInteractions );

		backEnd.depthFunc = GLS_DEPTHFUNC_EQUAL;
	}

	// disable stencil shadow test
	qglStencilFunc( GL_ALWAYS, 128, 255 );

	GL_SelectTexture( 0 );
	qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
}
Beispiel #3
0
void idGLDrawableMaterial::draw(int x, int y, int w, int h) {
    const idMaterial *mat = material;
    if (mat) {
        qglViewport(x, y, w, h);
        qglScissor(x, y, w, h);
        qglMatrixMode(GL_PROJECTION);
        qglClearColor( 0.1f, 0.1f, 0.1f, 0.0f );
        qglClear(GL_COLOR_BUFFER_BIT);

        if (worldDirty) {
            InitWorld();
            renderLight_t	parms;
            idDict spawnArgs;
            spawnArgs.Set("classname", "light");
            spawnArgs.Set("name", "light_1");
            spawnArgs.Set("origin", "0 0 0");
            idStr str;
            sprintf(str, "%f %f %f", light, light, light);
            spawnArgs.Set("_color", str);
            gameEdit->ParseSpawnArgsToRenderLight( &spawnArgs, &parms );
            lightDef = world->AddLightDef( &parms );

            idImage *img = (mat->GetNumStages() > 0) ? mat->GetStage(0)->texture.image : mat->GetEditorImage();

            if (img == NULL) {
                common->Warning("Unable to load image for preview for %s", mat->GetName());
                return;
            }

            int width = img->uploadWidth;
            int height = img->uploadHeight;

            width *= scale;
            height *= scale;

            srfTriangles_t *tris = worldModel->AllocSurfaceTriangles( 4, 6 );
            tris->numVerts = 4;
            tris->numIndexes = 6;

            tris->indexes[0] = 0;
            tris->indexes[1] = 1;
            tris->indexes[2] = 2;
            tris->indexes[3] = 3;
            tris->indexes[4] = 1;
            tris->indexes[5] = 0;

            tris->verts[0].xyz.x = 64;
            tris->verts[0].xyz.y = -xOffset + 0 - width / 2;
            tris->verts[0].xyz.z = yOffset + 0 - height / 2;
            tris->verts[0].st.x = 1;
            tris->verts[0].st.y = 1;

            tris->verts[1].xyz.x = 64;
            tris->verts[1].xyz.y = -xOffset + width / 2;
            tris->verts[1].xyz.z = yOffset + height / 2;
            tris->verts[1].st.x = 0;
            tris->verts[1].st.y = 0;

            tris->verts[2].xyz.x = 64;
            tris->verts[2].xyz.y = -xOffset + 0 - width / 2;
            tris->verts[2].xyz.z = yOffset + height / 2;
            tris->verts[2].st.x = 1;
            tris->verts[2].st.y = 0;

            tris->verts[3].xyz.x = 64;
            tris->verts[3].xyz.y = -xOffset + width / 2;
            tris->verts[3].xyz.z = yOffset + 0 - height / 2;
            tris->verts[3].st.x = 0;
            tris->verts[3].st.y = 1;

            tris->verts[0].normal = tris->verts[1].xyz.Cross(tris->verts[3].xyz);
            tris->verts[1].normal = tris->verts[2].normal = tris->verts[3].normal = tris->verts[0].normal;
            AddTris(tris, mat);

            worldModel->FinishSurfaces();

            renderEntity_t worldEntity;

            memset( &worldEntity, 0, sizeof( worldEntity ) );
            if ( mat->HasGui() ) {
                worldEntity.gui[ 0 ] = mat->GlobalGui();
            }
            worldEntity.hModel = worldModel;
            worldEntity.axis = mat3_default;
            worldEntity.shaderParms[0] = 1;
            worldEntity.shaderParms[1] = 1;
            worldEntity.shaderParms[2] = 1;
            worldEntity.shaderParms[3] = 1;
            modelDef = world->AddEntityDef( &worldEntity );

            worldDirty = false;
        }

        renderView_t	refdef;
        // render it
        renderSystem->BeginFrame(w, h);
        memset( &refdef, 0, sizeof( refdef ) );
        refdef.vieworg.Set(viewAngle, 0, 0);

        refdef.viewaxis = idAngles(0,0,0).ToMat3();
        refdef.shaderParms[0] = 1;
        refdef.shaderParms[1] = 1;
        refdef.shaderParms[2] = 1;
        refdef.shaderParms[3] = 1;

        refdef.width = SCREEN_WIDTH;
        refdef.height = SCREEN_HEIGHT;
        refdef.fov_x = 90;
        refdef.fov_y = 2 * atan((float)h / w) * idMath::M_RAD2DEG;

        refdef.time = eventLoop->Milliseconds();

        world->RenderScene( &refdef );
        int frontEnd, backEnd;
        renderSystem->EndFrame( &frontEnd, &backEnd );

        qglMatrixMode( GL_MODELVIEW );
        qglLoadIdentity();
    }

}
Beispiel #4
0
/*
 * RB_RenderDrawSurfList
 */
void
RB_RenderDrawSurfList(drawSurf_t *drawSurfs, int numDrawSurfs)
{
	material_t	*shader, *oldShader;
	int		fogNum, oldFogNum;
	int		entityNum, oldEntityNum;
	int		dlighted, oldDlighted;
	int		pshadowed, oldPshadowed;
	qbool		depthRange, oldDepthRange, isCrosshair, wasCrosshair;
	int		i;
	drawSurf_t              *drawSurf;
	int		oldSort;
	float		originalTime;
	float		depth[2];
	FBO_t		* fbo	= NULL;
	qbool		inQuery = qfalse;

	/* save original time for entity shader offsets */
	originalTime = backEnd.refdef.floatTime;

	/* clear the z buffer, set the modelview, etc */
	RB_BeginDrawingView ();

	fbo = glState.currentFBO;

	/* draw everything */
	oldEntityNum = -1;
	backEnd.currentEntity = &tr.worldEntity;
	oldShader = NULL;
	oldFogNum = -1;
	oldDepthRange	= qfalse;
	wasCrosshair	= qfalse;
	oldDlighted	= qfalse;
	oldPshadowed	= qfalse;
	oldSort = -1;
	depthRange = qfalse;
	depth[0] = 0.f;
	depth[1] = 1.f;

	backEnd.pc.c_surfaces += numDrawSurfs;

	for(i = 0, drawSurf = drawSurfs; i < numDrawSurfs; i++, drawSurf++){
		if(drawSurf->sort == oldSort){
			/* fast path, same as previous sort */
			rb_surfaceTable[ *drawSurf->surface ](drawSurf->surface);
			continue;
		}
		oldSort = drawSurf->sort;
		R_DecomposeSort(drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed);

		/*
		 * change the tess parameters if needed
		 * a "entityMergable" shader is a shader that can have surfaces from seperate
		 * entities merged into a single batch, like smoke and blood puff sprites */
		if(shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted || pshadowed !=
		   oldPshadowed
		   || (entityNum != oldEntityNum && !shader->entityMergable)){
			if(oldShader != NULL){
				RB_EndSurface();
			}
			RB_BeginSurface(shader, fogNum);
			backEnd.pc.c_surfBatches++;
			oldShader = shader;
			oldFogNum = fogNum;
			oldDlighted = dlighted;
			oldPshadowed = pshadowed;
		}

		/*
		 * change the modelview matrix if needed
		 *  */
		if(entityNum != oldEntityNum){
			qbool sunflare = qfalse;
			depthRange = isCrosshair = qfalse;

#ifdef REACTION
			/* if we were rendering to a FBO and the previous entity was a sunflare
			 * and the current one isn't, switch back to the main fbo */
			if(oldEntityNum != -1 && fbo &&
			   RF_SUNFLARE == (backEnd.refdef.entities[oldEntityNum].e.renderfx & RF_SUNFLARE) &&
			   0 == (backEnd.refdef.entities[entityNum].e.renderfx & RF_SUNFLARE)){
				if(inQuery){
					inQuery = qfalse;
					qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
				}
				FBO_Bind(fbo);
				qglDepthRange(depth[0], depth[1]);
			}
#endif

			if(entityNum != ENTITYNUM_WORLD){
				backEnd.currentEntity = &backEnd.refdef.entities[entityNum];
				backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime;
				/* we have to reset the shaderTime as well otherwise image animations start
				 * from the wrong frame */
				tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;

				/* set up the transformation matrix */
				R_RotateForEntity(backEnd.currentEntity, &backEnd.viewParms, &backEnd.or);

				/* set up the dynamic lighting if needed */
				if(backEnd.currentEntity->needDlights){
					R_TransformDlights(backEnd.refdef.num_dlights, backEnd.refdef.dlights,
						&backEnd.or);
				}

#ifdef REACTION
				/* if the current entity is a sunflare */
				if(backEnd.currentEntity->e.renderfx & RF_SUNFLARE){
					/* if we're rendering to a fbo */
					if(fbo){
						copyv3(backEnd.currentEntity->e.origin,
							backEnd.sunFlarePos);
						/* switch FBO */
						FBO_Bind(tr.godRaysFbo);

						qglClearColor(0.0f, 0.0f, 0.0f, 1.0f);
						qglClear(GL_COLOR_BUFFER_BIT);

						qglDepthRange(1.f, 1.f);
						if(glRefConfig.occlusionQuery && !inQuery &&
						   !backEnd.hasSunFlare){
							inQuery = qtrue;
							tr.sunFlareQueryActive[tr.sunFlareQueryIndex] = qtrue;
							qglBeginQueryARB(
								GL_SAMPLES_PASSED_ARB,
								tr.sunFlareQuery[tr.sunFlareQueryIndex]);
						}
						/* backEnd.hasSunFlare = qtrue; */
						sunflare = qtrue;
					}else{
						depthRange = qtrue;
					}
				}
#endif

				if(backEnd.currentEntity->e.renderfx & RF_DEPTHHACK){
					/* hack the depth range to prevent view model from poking into walls */
					depthRange = qtrue;

					if(backEnd.currentEntity->e.renderfx & RF_CROSSHAIR)
						isCrosshair = qtrue;
				}
			}else{
				backEnd.currentEntity = &tr.worldEntity;
				backEnd.refdef.floatTime = originalTime;
				backEnd.or = backEnd.viewParms.world;
				/* we have to reset the shaderTime as well otherwise image animations on
				 * the world (like water) continue with the wrong frame */
				tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
				R_TransformDlights(backEnd.refdef.num_dlights, backEnd.refdef.dlights,
					&backEnd.or);
			}

			GL_SetModelviewMatrix(backEnd.or.modelMatrix);

			/*
			 * change depthrange. Also change projection matrix so first person weapon does not look like coming
			 * out of the screen.
			 *  */
			if(oldDepthRange != depthRange || wasCrosshair != isCrosshair){
				if(depthRange){
					if(backEnd.viewParms.stereoFrame != STEREO_CENTER){
						if(isCrosshair){
							if(oldDepthRange){
								/* was not a crosshair but now is, change back proj matrix */
								GL_SetProjectionMatrix(
									backEnd.viewParms.projectionMatrix);
							}
						}else{
							viewParms_t temp = backEnd.viewParms;

							R_SetupProjection(&temp, r_znear->value, 0, qfalse);

							GL_SetProjectionMatrix(temp.projectionMatrix);
						}
					}

#ifdef REACTION
					if(!oldDepthRange){
						depth[0] = 0;
						depth[1] = 0.3f;
						qglDepthRange (0, 0.3);
					}
#endif
				}else{
					if(!wasCrosshair && backEnd.viewParms.stereoFrame != STEREO_CENTER){
						GL_SetProjectionMatrix(backEnd.viewParms.projectionMatrix);
					}

					if(!sunflare)
						qglDepthRange (0, 1);
					depth[0] = 0;
					depth[1] = 1;
				}

				oldDepthRange	= depthRange;
				wasCrosshair	= isCrosshair;
			}

			oldEntityNum = entityNum;
		}

		/* add the triangles for this surface */
		rb_surfaceTable[ *drawSurf->surface ](drawSurf->surface);
	}

	backEnd.refdef.floatTime = originalTime;

	/* draw the contents of the last shader batch */
	if(oldShader != NULL){
		RB_EndSurface();
	}

	if(inQuery){
		inQuery = qfalse;
		qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
	}
	FBO_Bind(fbo);

	/* go back to the world modelview matrix */

	GL_SetModelviewMatrix(backEnd.viewParms.world.modelMatrix);
	/* if ( depthRange ) { */
	qglDepthRange (0, 1);
	/* } */

#if 0
	RB_DrawSun();
#endif
	/* darken down any stencil shadows */
	RB_ShadowFinish();

	/* add light flares on lights that aren't obscured */
	RB_RenderFlares();

	if(glRefConfig.framebufferObject)
		FBO_Bind(NULL);
}
Beispiel #5
0
/*
=================
RB_BeginDrawingView

Any mirrored or portaled views have already been drawn, so prepare
to actually render the visible surfaces for this view
=================
*/
void RB_BeginDrawingView (void) {
	int clearBits = 0;

	// sync with gl if needed
	if ( r_finish->integer == 1 && !glState.finishCalled ) {
		qglFinish ();
		glState.finishCalled = qtrue;
	}
	if ( r_finish->integer == 0 ) {
		glState.finishCalled = qtrue;
	}

	// we will need to change the projection matrix before drawing
	// 2D images again
	backEnd.projection2D = qfalse;

	//
	// set the modelview matrix for the viewer
	//
	SetViewportAndScissor();

	// ensures that depth writes are enabled for the depth clear
	GL_State( GLS_DEFAULT );
	// clear relevant buffers
	clearBits = GL_DEPTH_BUFFER_BIT;

	if ( r_measureOverdraw->integer || r_shadows->integer == 2 )
	{
		clearBits |= GL_STENCIL_BUFFER_BIT;
	}
	if ( r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) )
	{
		clearBits |= GL_COLOR_BUFFER_BIT;	// FIXME: only if sky shaders have been used
		qglClearColor( 0.8f, 0.7f, 0.4f, 1 );	// FIXME: get color of sky
	}
	qglClear( clearBits );

	if ( ( backEnd.refdef.rdflags & RDF_HYPERSPACE ) )
	{
		RB_Hyperspace();
		return;
	}
	else
	{
		backEnd.isHyperspace = qfalse;
	}

	glState.faceCulling = -1;		// force face culling to set next time

	// we will only draw a sun if there was sky rendered in this view
	backEnd.skyRenderedThisView = qfalse;

	// clip to the plane of the portal
	if ( backEnd.viewParms.isPortal ) {
		float	plane[4];
		double	plane2[4];

		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;

		plane2[0] = DotProduct (backEnd.viewParms.or.axis[0], plane);
		plane2[1] = DotProduct (backEnd.viewParms.or.axis[1], plane);
		plane2[2] = DotProduct (backEnd.viewParms.or.axis[2], plane);
		plane2[3] = DotProduct (plane, backEnd.viewParms.or.origin) - plane[3];

		qglLoadMatrixf( s_flipMatrix );
		qglClipPlane (GL_CLIP_PLANE0, plane2);
		qglEnable (GL_CLIP_PLANE0);
	} else {
		qglDisable (GL_CLIP_PLANE0);
	}
}
Beispiel #6
0
/*
================
RB_StageIteratorSky

All of the visible sky triangles are in tess

Other things could be stuck in here, like birds in the sky, etc
================
*/
void RB_StageIteratorSky( void ) {
	int clearBits = 0;

	if ( r_fastsky->integer ) {
		if (r_fastsky->integer == 2  &&  !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL)) {
			clearBits |= GL_COLOR_BUFFER_BIT;	// FIXME: only if sky shaders have been used
			if (*r_fastSkyColor->string) {
				int v, tr, tg, tb;

				v = r_fastSkyColor->integer;
				tr = (v & 0xff0000) / 0x010000;
				tg = (v & 0x00ff00) / 0x000100;
				tb = (v & 0x0000ff) / 0x000001;

				qglClearColor((float)tr / 255.0, (float)tg / 255.0, (float)tb / 255.0, 1.0);
			} else {
				qglClearColor(0.0f, 0.0f, 0.0f, 1.0f);	// FIXME: get color of sky
			}

			qglClear(clearBits);
		}

		return;
	}

	// go through all the polygons and project them onto
	// the sky box to see which blocks on each side need
	// to be drawn
	RB_ClipSkyPolygons( &tess );

	// r_showsky will let all the sky blocks be drawn in
	// front of everything to allow developers to see how
	// much sky is getting sucked in
	if ( r_showsky->integer ) {
		qglDepthRange( 0.0, 0.0 );
	} else {
		qglDepthRange( 1.0, 1.0 );
	}

	// draw the outer skybox
	if ( tess.shader->sky.outerbox[0] && tess.shader->sky.outerbox[0] != tr.defaultImage ) {
		qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight );

		qglPushMatrix ();
		GL_State( 0 );
		GL_Cull( CT_FRONT_SIDED );
		qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]);

		DrawSkyBox( tess.shader );

		qglPopMatrix();
	}

	// generate the vertexes for all the clouds, which will be drawn
	// by the generic shader routine
	R_BuildCloudData( &tess );

	if (tess.numVertexes) {
		// yes, sky has cloud stages
		RB_StageIteratorGeneric();
	}

	// draw the inner skybox

	//FIXME not even done

	// back to normal depth range
	qglDepthRange( 0.0, 1.0 );

	// note that sky was drawn so we will draw a sun later
	backEnd.skyRenderedThisView = qtrue;
}
Beispiel #7
0
/*
==============
Z_Draw
==============
*/
void Z_Draw (void)
{
#ifdef DBG_WINDOWPOS
  CheckWatchit ("Z_Draw");
#endif
  brush_t	*brush;
	float	w, h;
	double	start, end;
	qtexture_t	*q;
	float	top, bottom;
	vec3_t	org_top, org_bottom, dir_up, dir_down;
	int xCam = z.width/3;

	if (!active_brushes.next)
		return;	// not valid yet

	if (z.timing)
		start = Sys_DoubleTime ();

	//
	// clear
	//
	qglViewport(0, 0, z.width, z.height);

	qglClearColor (
		g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][0],
		g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][1],
		g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][2],
		0);

    /* GL Bug */ 
	/* When not using hw acceleration, gl will fault if we clear the depth 
	buffer bit on the first pass. The hack fix is to set the GL_DEPTH_BUFFER_BIT
	only after Z_Draw() has been called once. Yeah, right. */
	qglClear(glbitClear); 
	glbitClear |= GL_DEPTH_BUFFER_BIT;
	qglMatrixMode(GL_PROJECTION);

  qglLoadIdentity ();
	w = z.width/2 / z.scale;
	h = z.height/2 / z.scale;
	qglOrtho (-w, w, z.origin[2]-h, z.origin[2]+h, -8, 8);

	qglDisable(GL_TEXTURE_2D);
	qglDisable(GL_TEXTURE_1D);
	qglDisable(GL_DEPTH_TEST);
	qglDisable(GL_BLEND);


	//
	// now draw the grid
	//
	Z_DrawGrid ();

	//
	// draw stuff
	//

	qglDisable(GL_CULL_FACE);

	qglShadeModel (GL_FLAT);

	qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);

	qglDisable(GL_TEXTURE_2D);
	qglDisable(GL_BLEND);
	qglDisable(GL_DEPTH_TEST);


	// draw filled interiors and edges
	dir_up[0] = 0 ; dir_up[1] = 0; dir_up[2] = 1;
	dir_down[0] = 0 ; dir_down[1] = 0; dir_down[2] = -1;
	VectorCopy (z.origin, org_top);
	org_top[2] = g_MaxWorldCoord;
	VectorCopy (z.origin, org_bottom);
	org_bottom[2] = g_MinWorldCoord;

	for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next)
	{
		if (brush->bFiltered)
			continue;

		if (brush->mins[0] >= z.origin[0]
			|| brush->maxs[0] <= z.origin[0]
			|| brush->mins[1] >= z.origin[1]
			|| brush->maxs[1] <= z.origin[1])
			continue;

		if (!Brush_Ray (org_top, dir_down, brush, &top))
			continue;
		top = org_top[2] - top;
		if (!Brush_Ray (org_bottom, dir_up, brush, &bottom))
			continue;
		bottom = org_bottom[2] + bottom;

		q = brush->brush_faces->pShader->getTexture();
		qglColor3f (q->color[0], q->color[1], q->color[2]);
		qglBegin (GL_QUADS);
		qglVertex2f (-xCam, bottom);
		qglVertex2f (xCam, bottom);
		qglVertex2f (xCam, top);
		qglVertex2f (-xCam, top);
		qglEnd ();

		qglColor3f (1,1,1);
		qglBegin (GL_LINE_LOOP);
		qglVertex2f (-xCam, bottom);
		qglVertex2f (xCam, bottom);
		qglVertex2f (xCam, top);
		qglVertex2f (-xCam, top);
		qglEnd ();
	}

	//
	// now draw selected brushes
	//
	for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next)
	{
		if ( !(brush->mins[0] >= z.origin[0]
			|| brush->maxs[0] <= z.origin[0]
			|| brush->mins[1] >= z.origin[1]
			|| brush->maxs[1] <= z.origin[1]) )
		{
			if (Brush_Ray (org_top, dir_down, brush, &top))
			{
				top = org_top[2] - top;
				if (Brush_Ray (org_bottom, dir_up, brush, &bottom))
				{
					bottom = org_bottom[2] + bottom;

					q = brush->brush_faces->pShader->getTexture();
					qglColor3f (q->color[0], q->color[1], q->color[2]);
					qglBegin (GL_QUADS);
					qglVertex2f (-xCam, bottom);
					qglVertex2f (xCam, bottom);
					qglVertex2f (xCam, top);
					qglVertex2f (-xCam, top);
					qglEnd ();
				}
			}
		}

	  qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES]);
		qglBegin (GL_LINE_LOOP);
		qglVertex2f (-xCam, brush->mins[2]);
		qglVertex2f (xCam, brush->mins[2]);
		qglVertex2f (xCam, brush->maxs[2]);
		qglVertex2f (-xCam, brush->maxs[2]);
		qglEnd ();
	}


	ZDrawCameraIcon ();

  qglFinish();
	QE_CheckOpenGLForErrors();

	if (z.timing)
	{
		end = Sys_DoubleTime ();
		Sys_Printf ("z: %i ms\n", (int)(1000*(end-start)));
	}
}
Beispiel #8
0
/*
=============
RB_DrawSurfs

=============
*/
const void	*RB_DrawSurfs( const void *data ) {
	const drawSurfsCommand_t	*cmd;

	// finish any 2D drawing if needed
	if ( tess.numIndexes ) {
		RB_EndSurface();
	}

	cmd = (const drawSurfsCommand_t *)data;

	backEnd.refdef = cmd->refdef;
	backEnd.viewParms = cmd->viewParms;

	RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs );

	// Dynamic Glow/Flares:
	/*
		The basic idea is to render the glowing parts of the scene to an offscreen buffer, then take
		that buffer and blur it. After it is sufficiently blurred, re-apply that image back to
		the normal screen using a additive blending. To blur the scene I use a vertex program to supply
		four texture coordinate offsets that allow 'peeking' into adjacent pixels. In the register
		combiner (pixel shader), I combine the adjacent pixels using a weighting factor. - Aurelio
	*/

	// Render dynamic glowing/flaring objects.
	if ( !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL) && g_bDynamicGlowSupported && r_DynamicGlow->integer )
	{
		// Copy the normal scene to texture.
		qglDisable( GL_TEXTURE_2D );
		qglEnable( GL_TEXTURE_RECTANGLE_EXT ); 
		qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, tr.sceneImage ); 
		qglCopyTexSubImage2D( GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight); 
		qglDisable( GL_TEXTURE_RECTANGLE_EXT );
		qglEnable( GL_TEXTURE_2D );    

		// Just clear colors, but leave the depth buffer intact so we can 'share' it.
		qglClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
		qglClear( GL_COLOR_BUFFER_BIT ); 

		// Render the glowing objects.
		g_bRenderGlowingObjects = true;
		RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs );  
		g_bRenderGlowingObjects = false;
		qglFinish();

		// Copy the glow scene to texture.
		qglDisable( GL_TEXTURE_2D );
		qglEnable( GL_TEXTURE_RECTANGLE_EXT ); 
		qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, tr.screenGlow ); 
		qglCopyTexSubImage2D( GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0,  backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); 
		qglDisable( GL_TEXTURE_RECTANGLE_EXT );
		qglEnable( GL_TEXTURE_2D );
		
		// Resize the viewport to the blur texture size.
		const int oldViewWidth = backEnd.viewParms.viewportWidth;
		const int oldViewHeight = backEnd.viewParms.viewportHeight;
		backEnd.viewParms.viewportWidth = r_DynamicGlowWidth->integer;
		backEnd.viewParms.viewportHeight = r_DynamicGlowHeight->integer;
		SetViewportAndScissor();

		// Blur the scene.
		RB_BlurGlowTexture();

		// Copy the finished glow scene back to texture.
		qglDisable( GL_TEXTURE_2D );
		qglEnable( GL_TEXTURE_RECTANGLE_EXT );
		qglBindTexture( GL_TEXTURE_RECTANGLE_EXT, tr.blurImage );
		qglCopyTexSubImage2D( GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, 0, 0, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); 
		qglDisable( GL_TEXTURE_RECTANGLE_EXT );
		qglEnable( GL_TEXTURE_2D );
		
		// Set the viewport back to normal.
		backEnd.viewParms.viewportWidth = oldViewWidth;
		backEnd.viewParms.viewportHeight = oldViewHeight;
		SetViewportAndScissor();
		qglClear( GL_COLOR_BUFFER_BIT ); 

		// Draw the glow additively over the screen.
		RB_DrawGlowOverlay(); 
	}

	return (const void *)(cmd + 1);
}
Beispiel #9
0
/*
=============
RB_DrawBuffer

=============
*/
const void	*RB_DrawBuffer( const void *data ) {
	const drawBufferCommand_t	*cmd;

	cmd = (const drawBufferCommand_t *)data;

	qglDrawBuffer( cmd->buffer );

		// clear screen for debugging
	if (!( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) && tr.world && tr.refdef.rdflags & RDF_doLAGoggles)
	{
		const fog_t		*fog = &tr.world->fogs[tr.world->numfogs];

		qglClearColor(fog->parms.color[0],  fog->parms.color[1], fog->parms.color[2], 1.0f );
		qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	}
	else if (!( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) && tr.world && tr.world->globalFog != -1 && tr.sceneCount)//don't clear during menus, wait for real scene
	{
		const fog_t		*fog = &tr.world->fogs[tr.world->globalFog];

		qglClearColor(fog->parms.color[0],  fog->parms.color[1], fog->parms.color[2], 1.0f );
		qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	}
	else if ( r_clear->integer ) 
	{	// clear screen for debugging
		int i = r_clear->integer;
		if (i == 42) {
			i = Q_irand(0,8);
		}
		switch (i)
		{
		default:
			qglClearColor( 1, 0, 0.5, 1 );
			break;
		case 1:
			qglClearColor( 1.0, 0.0, 0.0, 1.0); //red
			break;
		case 2:
			qglClearColor( 0.0, 1.0, 0.0, 1.0); //green
			break;
		case 3:
			qglClearColor( 1.0, 1.0, 0.0, 1.0); //yellow
			break;
		case 4:
			qglClearColor( 0.0, 0.0, 1.0, 1.0); //blue
			break;
		case 5:
			qglClearColor( 0.0, 1.0, 1.0, 1.0); //cyan
			break;
		case 6:
			qglClearColor( 1.0, 0.0, 1.0, 1.0); //magenta
			break;
		case 7:
			qglClearColor( 1.0, 1.0, 1.0, 1.0); //white
			break;
		case 8:
			qglClearColor( 0.0, 0.0, 0.0, 1.0); //black
			break;
		}		
		qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	}

	return (const void *)(cmd + 1);
}
Beispiel #10
0
/*
====================
RE_BeginFrame

If running in stereo, RE_BeginFrame will be called twice
for each RE_EndFrame
====================
*/
void RE_BeginFrame(stereoFrame_t stereoFrame)
{
	drawBufferCommand_t *cmd    = NULL;
	colorMaskCommand_t  *colcmd = NULL;

	if (!tr.registered)
	{
		return;
	}
	glState.finishCalled = qfalse;

	tr.frameCount++;
	tr.frameSceneNum = 0;

	//
	// do overdraw measurement
	//
	if (r_measureOverdraw->integer)
	{
		if (glConfig.stencilBits < 4)
		{
			ri.Printf(PRINT_ALL, "Warning: not enough stencil bits to measure overdraw: %d\n", glConfig.stencilBits);
			ri.Cvar_Set("r_measureOverdraw", "0");
			r_measureOverdraw->modified = qfalse;
		}
		else if (r_shadows->integer == 2)
		{
			ri.Printf(PRINT_ALL, "Warning: stencil shadows and overdraw measurement are mutually exclusive\n");
			ri.Cvar_Set("r_measureOverdraw", "0");
			r_measureOverdraw->modified = qfalse;
		}
		else
		{
			R_IssuePendingRenderCommands();
			qglEnable(GL_STENCIL_TEST);
			qglStencilMask(~0U);
			qglClearStencil(0U);
			qglStencilFunc(GL_ALWAYS, 0U, ~0U);
			qglStencilOp(GL_KEEP, GL_INCR, GL_INCR);
		}
		r_measureOverdraw->modified = qfalse;
	}
	else
	{
		// this is only reached if it was on and is now off
		if (r_measureOverdraw->modified)
		{
			R_IssuePendingRenderCommands();
			qglDisable(GL_STENCIL_TEST);
		}
		r_measureOverdraw->modified = qfalse;
	}

	//
	// texturemode stuff
	//
	if (r_textureMode->modified)
	{
		R_IssuePendingRenderCommands();
		GL_TextureMode(r_textureMode->string);
		r_textureMode->modified = qfalse;
	}

	//
	// NVidia stuff
	//

	// fog control
	if (glConfig.NVFogAvailable && r_nv_fogdist_mode->modified)
	{
		r_nv_fogdist_mode->modified = qfalse;
		if (!Q_stricmp(r_nv_fogdist_mode->string, "GL_EYE_PLANE_ABSOLUTE_NV"))
		{
			glConfig.NVFogMode = (int)GL_EYE_PLANE_ABSOLUTE_NV;
		}
		else if (!Q_stricmp(r_nv_fogdist_mode->string, "GL_EYE_PLANE"))
		{
			glConfig.NVFogMode = (int)GL_EYE_PLANE;
		}
		else if (!Q_stricmp(r_nv_fogdist_mode->string, "GL_EYE_RADIAL_NV"))
		{
			glConfig.NVFogMode = (int)GL_EYE_RADIAL_NV;
		}
		else
		{
			// in case this was really 'else', store a valid value for next time
			glConfig.NVFogMode = (int)GL_EYE_RADIAL_NV;
			ri.Cvar_Set("r_nv_fogdist_mode", "GL_EYE_RADIAL_NV");
		}
	}

	//
	// gamma stuff
	//
	if (r_gamma->modified)
	{
		r_gamma->modified = qfalse;

		R_IssuePendingRenderCommands();
		R_SetColorMappings();
	}

	// check for errors
	if (!r_ignoreGLErrors->integer)
	{
		int err;

		R_IssuePendingRenderCommands();
		if ((err = qglGetError()) != GL_NO_ERROR)
		{
			ri.Error(ERR_FATAL, "RE_BeginFrame() - glGetError() failed (0x%x)!", err);
		}
	}

	if (glConfig.stereoEnabled)
	{
		if (!(cmd = R_GetCommandBuffer(sizeof(*cmd))))
		{
			return;
		}

		cmd->commandId = RC_DRAW_BUFFER;

		if (stereoFrame == STEREO_LEFT)
		{
			cmd->buffer = (int)GL_BACK_LEFT;
		}
		else if (stereoFrame == STEREO_RIGHT)
		{
			cmd->buffer = (int)GL_BACK_RIGHT;
		}
		else
		{
			ri.Error(ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame);
		}
	}
	else
	{
		if (r_anaglyphMode->integer)
		{
			if (r_anaglyphMode->modified)
			{
				// clear both, front and backbuffer.
				qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
				backEnd.colorMask[0] = GL_FALSE;
				backEnd.colorMask[1] = GL_FALSE;
				backEnd.colorMask[2] = GL_FALSE;
				backEnd.colorMask[3] = GL_FALSE;
				qglClearColor(0.0f, 0.0f, 0.0f, 1.0f);

				if (glRefConfig.framebufferObject)
				{
					// clear all framebuffers
					if (tr.msaaResolveFbo)
					{
						FBO_Bind(tr.msaaResolveFbo);
						qglClear(GL_COLOR_BUFFER_BIT);
					}

					if (tr.renderFbo)
					{
						FBO_Bind(tr.renderFbo);
						qglClear(GL_COLOR_BUFFER_BIT);
					}

					if (tr.screenScratchFbo)
					{
						FBO_Bind(tr.screenScratchFbo);
						qglClear(GL_COLOR_BUFFER_BIT);
					}

					FBO_Bind(NULL);
				}

				qglDrawBuffer(GL_FRONT);
				qglClear(GL_COLOR_BUFFER_BIT);
				qglDrawBuffer(GL_BACK);
				qglClear(GL_COLOR_BUFFER_BIT);

				r_anaglyphMode->modified = qfalse;
			}

			if (stereoFrame == STEREO_LEFT)
			{
				if (!(cmd = R_GetCommandBuffer(sizeof(*cmd))))
				{
					return;
				}

				if (!(colcmd = R_GetCommandBuffer(sizeof(*colcmd))))
				{
					return;
				}
			}
			else if (stereoFrame == STEREO_RIGHT)
			{
				clearDepthCommand_t *cldcmd;

				if (!(cldcmd = R_GetCommandBuffer(sizeof(*cldcmd))))
				{
					return;
				}

				cldcmd->commandId = RC_CLEARDEPTH;

				if (!(colcmd = R_GetCommandBuffer(sizeof(*colcmd))))
				{
					return;
				}
			}
			else
			{
				ri.Error(ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame);
			}

			R_SetColorMode(colcmd->rgba, stereoFrame, r_anaglyphMode->integer);
			colcmd->commandId = RC_COLORMASK;
		}
		else
		{
			if (stereoFrame != STEREO_CENTER)
			{
				ri.Error(ERR_FATAL, "RE_BeginFrame: Stereo is disabled, but stereoFrame was %i", stereoFrame);
			}

			if (!(cmd = R_GetCommandBuffer(sizeof(*cmd))))
			{
				return;
			}
		}

		if (cmd)
		{
			cmd->commandId = RC_DRAW_BUFFER;

			if (r_anaglyphMode->modified)
			{
				qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
				backEnd.colorMask[0]     = 0;
				backEnd.colorMask[1]     = 0;
				backEnd.colorMask[2]     = 0;
				backEnd.colorMask[3]     = 0;
				r_anaglyphMode->modified = qfalse;
			}

			if (!Q_stricmp(r_drawBuffer->string, "GL_FRONT"))
			{
				cmd->buffer = (int)GL_FRONT;
			}
			else
			{
				cmd->buffer = (int)GL_BACK;
			}
		}
	}

	tr.refdef.stereoFrame = stereoFrame;
}
Beispiel #11
0
/*
===============
RB_ShowImages

Draw all the images to the screen, on top of whatever
was there.  This is used to test for texture thrashing.

Also called by RE_EndRegistration
===============
*/
void RB_ShowImages( void ) {
	int i;
	image_t *image;
	float x, y, w, h;
	int start, end;

	if ( !backEnd.projection2D ) {
		RB_SetGL2D();
	}

	qglClear( GL_COLOR_BUFFER_BIT );

	qglFinish();


	start = ri.Milliseconds();

	for ( i = 0 ; i < tr.numImages ; i++ ) {
		image = tr.images[i];

		w = glConfig.vidWidth / 40;
		h = glConfig.vidHeight / 30;

		x = i % 40 * w;
		y = i / 30 * h;

		// show in proportional size in mode 2
		if ( r_showImages->integer == 2 ) {
			w *= image->uploadWidth / 512.0f;
			h *= image->uploadHeight / 512.0f;
		}

#ifdef USE_OPENGLES
		GLfloat tex[] = {
		 0, 0, 
		 1, 0,
		 1, 1, 
		 0, 1 };
		GLfloat vtx[] = {
		 x, y,
		 x + w, y,
		 x + w, y + h,
		 x, y + h };
		GLboolean text = qglIsEnabled(GL_TEXTURE_COORD_ARRAY);
		GLboolean glcol = qglIsEnabled(GL_COLOR_ARRAY);
		if (glcol)
			qglDisableClientState(GL_COLOR_ARRAY);
		if (!text)
			qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
		qglTexCoordPointer( 2, GL_FLOAT, 0, tex );
		qglVertexPointer  ( 2, GL_FLOAT, 0, vtx );
		qglDrawArrays( GL_TRIANGLE_FAN, 0, 4 );
		if (glcol)
			qglEnableClientState(GL_COLOR_ARRAY);
		if (!text)
			qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
#else
		GL_Bind( image );
		qglBegin( GL_QUADS );
		qglTexCoord2f( 0, 0 );
		qglVertex2f( x, y );
		qglTexCoord2f( 1, 0 );
		qglVertex2f( x + w, y );
		qglTexCoord2f( 1, 1 );
		qglVertex2f( x + w, y + h );
		qglTexCoord2f( 0, 1 );
		qglVertex2f( x, y + h );
		qglEnd();
#endif
	}

	qglFinish();

	end = ri.Milliseconds();
	ri.Printf( PRINT_ALL, "%i msec to draw all images\n", end - start );

}
Beispiel #12
0
/*
=================
RB_BeginDrawingView

Any mirrored or portaled views have already been drawn, so prepare
to actually render the visible surfaces for this view
=================
*/
void RB_BeginDrawingView (void) {
	int clearBits = 0;

	// sync with gl if needed
	if ( r_finish->integer == 1 && !glState.finishCalled ) {
		qglFinish ();
		glState.finishCalled = qtrue;
	}
	if ( r_finish->integer == 0 ) {
		glState.finishCalled = qtrue;
	}

	// we will need to change the projection matrix before drawing
	// 2D images again
	backEnd.projection2D = qfalse;

	if (glRefConfig.framebufferObject)
	{
		FBO_t *fbo = backEnd.viewParms.targetFbo;

		// FIXME: HUGE HACK: render to the screen fbo if we've already postprocessed the frame and aren't drawing more world
		// drawing more world check is in case of double renders, such as skyportals
		if (fbo == NULL && !(backEnd.framePostProcessed && (backEnd.refdef.rdflags & RDF_NOWORLDMODEL)))
			fbo = tr.renderFbo;

		if (tr.renderCubeFbo && fbo == tr.renderCubeFbo)
		{
			cubemap_t *cubemap = &tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex];
			FBO_AttachImage(fbo, cubemap->image, GL_COLOR_ATTACHMENT0_EXT, backEnd.viewParms.targetFboLayer);
		}

		FBO_Bind(fbo);
	}

	//
	// set the modelview matrix for the viewer
	//
	SetViewportAndScissor();

	// ensures that depth writes are enabled for the depth clear
	GL_State( GLS_DEFAULT );
	// clear relevant buffers
	clearBits = GL_DEPTH_BUFFER_BIT;

	if ( r_measureOverdraw->integer || r_shadows->integer == 2 )
	{
		clearBits |= GL_STENCIL_BUFFER_BIT;
	}
	if ( r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) )
	{
		clearBits |= GL_COLOR_BUFFER_BIT;	// FIXME: only if sky shaders have been used
	}

	// clear to black for cube maps
	if (tr.renderCubeFbo && backEnd.viewParms.targetFbo == tr.renderCubeFbo)
	{
		clearBits |= GL_COLOR_BUFFER_BIT;
	}

	qglClear( clearBits );

	if ( ( backEnd.refdef.rdflags & RDF_HYPERSPACE ) )
	{
		RB_Hyperspace();
		return;
	}
	else
	{
		backEnd.isHyperspace = qfalse;
	}

	// we will only draw a sun if there was sky rendered in this view
	backEnd.skyRenderedThisView = qfalse;

	// clip to the plane of the portal
	if ( backEnd.viewParms.isPortal ) {
#if 0
		float	plane[4];
		GLdouble	plane2[4];

		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;

		plane2[0] = DotProduct (backEnd.viewParms.or.axis[0], plane);
		plane2[1] = DotProduct (backEnd.viewParms.or.axis[1], plane);
		plane2[2] = DotProduct (backEnd.viewParms.or.axis[2], plane);
		plane2[3] = DotProduct (plane, backEnd.viewParms.or.origin) - plane[3];
#endif
		GL_SetModelviewMatrix( s_flipMatrix );
	}
}
Beispiel #13
0
/*
 ==================
 GL_Setup3D

 TODO: time is messed up
 ==================
*/
void GL_Setup3D (int time){

	double	clipPlane[4];

	QGL_LogPrintf("---------- RB_Setup3D ----------\n");

	backEnd.projection2D = false;

	backEnd.time = time;
	backEnd.floatTime = MS2SEC(Sys_Milliseconds());

	backEnd.viewport.x = backEnd.viewParms.viewport.x;
	backEnd.viewport.y = backEnd.viewParms.viewport.y;
	backEnd.viewport.width = backEnd.viewParms.viewport.width;
	backEnd.viewport.height = backEnd.viewParms.viewport.height;

	backEnd.scissor.x = backEnd.viewParms.scissor.x;
	backEnd.scissor.y = backEnd.viewParms.scissor.y;
	backEnd.scissor.width = backEnd.viewParms.scissor.width;
	backEnd.scissor.height = backEnd.viewParms.scissor.height;

	backEnd.coordScale[0] = 1.0f / backEnd.viewport.width;
	backEnd.coordScale[1] = 1.0f / backEnd.viewport.height;

	backEnd.coordBias[0] = -backEnd.viewport.x * backEnd.coordScale[0];
	backEnd.coordBias[1] = -backEnd.viewport.y * backEnd.coordScale[1];

	backEnd.depthFilling = false;
	backEnd.debugRendering = false;

	backEnd.currentColorCaptured = SORT_BAD;
	backEnd.currentDepthCaptured = false;

	// Set up the viewport
	GL_Viewport(backEnd.viewport);

	// Set up the scissor
	GL_Scissor(backEnd.viewport);

	// Set up the depth bounds
	if (glConfig.depthBoundsTestAvailable)
		GL_DepthBounds(0.0f, 1.0f);

	// Set the projection matrix
	GL_LoadMatrix(GL_PROJECTION, backEnd.viewParms.projectionMatrix);

	// Set the modelview matrix
	GL_LoadIdentity(GL_MODELVIEW);

	// Set the GL state
	GL_PolygonMode(GL_FILL);

	GL_Disable(GL_CULL_FACE);
	GL_Disable(GL_POLYGON_OFFSET_FILL);
	GL_Disable(GL_BLEND);
	GL_Disable(GL_ALPHA_TEST);
	GL_Disable(GL_DEPTH_TEST);
	GL_Disable(GL_STENCIL_TEST);

	GL_DepthRange(0.0f, 1.0f);

	GL_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
	GL_DepthMask(GL_TRUE);
	GL_StencilMask(255);

	// Enable the clip plane if needed
	if (backEnd.viewParms.viewType != VIEW_MIRROR)
		qglDisable(GL_CLIP_PLANE0);
	else {
		clipPlane[0] = -DotProduct(backEnd.viewParms.axis[1], backEnd.viewParms.clipPlane.normal);
		clipPlane[1] = DotProduct(backEnd.viewParms.axis[2], backEnd.viewParms.clipPlane.normal);
		clipPlane[2] = -DotProduct(backEnd.viewParms.axis[0], backEnd.viewParms.clipPlane.normal);
		clipPlane[3] = DotProduct(backEnd.viewParms.origin, backEnd.viewParms.clipPlane.normal) - backEnd.viewParms.clipPlane.dist;

		qglEnable(GL_CLIP_PLANE0);
		qglClipPlane(GL_CLIP_PLANE0, clipPlane);
	}

	// Enable multisampling if available
	if (glConfig.multiSamples > 1)
		qglEnable(GL_MULTISAMPLE);

	// Clear the buffers
	qglClearColor(0.0f, 0.0f, 0.0f, 1.0f);
	qglClearDepth(1.0f);
	qglClearStencil(0);

	if (backEnd.viewParms.primaryView)
		qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
	else
		qglClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

	// Check for errors
	if (!r_ignoreGLErrors->integerValue)
		GL_CheckForErrors();

	QGL_LogPrintf("--------------------\n");
}
Beispiel #14
0
/*
===============
GLimp_SetMode
===============
*/
static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder)
{
	const char *glstring;
	int perChannelColorBits;
	int colorBits, depthBits, stencilBits;
	int samples;
	int i = 0;
	SDL_Surface *icon = NULL;
	Uint32 flags = SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL;
	SDL_DisplayMode desktopMode;
	int display = 0;
	int x = SDL_WINDOWPOS_UNDEFINED, y = SDL_WINDOWPOS_UNDEFINED;

	ri.Printf( PRINT_ALL, "Initializing OpenGL display\n");

	if ( r_allowResize->integer )
		flags |= SDL_WINDOW_RESIZABLE;

#ifdef USE_ICON
	icon = SDL_CreateRGBSurfaceFrom(
			(void *)CLIENT_WINDOW_ICON.pixel_data,
			CLIENT_WINDOW_ICON.width,
			CLIENT_WINDOW_ICON.height,
			CLIENT_WINDOW_ICON.bytes_per_pixel * 8,
			CLIENT_WINDOW_ICON.bytes_per_pixel * CLIENT_WINDOW_ICON.width,
#ifdef Q3_LITTLE_ENDIAN
			0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000
#else
			0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF
#endif
			);
#endif

	// If a window exists, note its display index
	if( SDL_window != NULL )
		display = SDL_GetWindowDisplayIndex( SDL_window );

	if( SDL_GetDesktopDisplayMode( display, &desktopMode ) == 0 )
	{
		displayAspect = (float)desktopMode.w / (float)desktopMode.h;

		ri.Printf( PRINT_ALL, "Display aspect: %.3f\n", displayAspect );
	}
	else
	{
		Com_Memset( &desktopMode, 0, sizeof( SDL_DisplayMode ) );

		ri.Printf( PRINT_ALL,
				"Cannot determine display aspect, assuming 1.333\n" );
	}

	ri.Printf (PRINT_ALL, "...setting mode %d:", mode );

	if (mode == -2)
	{
		// use desktop video resolution
		if( desktopMode.h > 0 )
		{
			glConfig.vidWidth = desktopMode.w;
			glConfig.vidHeight = desktopMode.h;
		}
		else
		{
			glConfig.vidWidth = 640;
			glConfig.vidHeight = 480;
			ri.Printf( PRINT_ALL,
					"Cannot determine display resolution, assuming 640x480\n" );
		}

		glConfig.windowAspect = (float)glConfig.vidWidth / (float)glConfig.vidHeight;
	}
	else if ( !R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, mode ) )
	{
		ri.Printf( PRINT_ALL, " invalid mode\n" );
		return RSERR_INVALID_MODE;
	}
	ri.Printf( PRINT_ALL, " %d %d\n", glConfig.vidWidth, glConfig.vidHeight);

	// Center window
	if( r_centerWindow->integer && !fullscreen )
	{
		x = ( desktopMode.w / 2 ) - ( glConfig.vidWidth / 2 );
		y = ( desktopMode.h / 2 ) - ( glConfig.vidHeight / 2 );
	}

	// Destroy existing state if it exists
	if( SDL_glContext != NULL )
	{
		SDL_GL_DeleteContext( SDL_glContext );
		SDL_glContext = NULL;
	}

	if( SDL_window != NULL )
	{
		SDL_GetWindowPosition( SDL_window, &x, &y );
		ri.Printf( PRINT_DEVELOPER, "Existing window at %dx%d before being destroyed\n", x, y );
		SDL_DestroyWindow( SDL_window );
		SDL_window = NULL;
	}

	if( fullscreen )
	{
		flags |= SDL_WINDOW_FULLSCREEN;
		glConfig.isFullscreen = qtrue;
	}
	else
	{
		if( noborder )
			flags |= SDL_WINDOW_BORDERLESS;

		glConfig.isFullscreen = qfalse;
	}

	colorBits = r_colorbits->value;
	if ((!colorBits) || (colorBits >= 32))
		colorBits = 24;

	if (!r_depthbits->value)
		depthBits = 24;
	else
		depthBits = r_depthbits->value;

	stencilBits = r_stencilbits->value;
	samples = r_ext_multisample->value;

	for (i = 0; i < 16; i++)
	{
		int testColorBits, testDepthBits, testStencilBits;

		// 0 - default
		// 1 - minus colorBits
		// 2 - minus depthBits
		// 3 - minus stencil
		if ((i % 4) == 0 && i)
		{
			// one pass, reduce
			switch (i / 4)
			{
				case 2 :
					if (colorBits == 24)
						colorBits = 16;
					break;
				case 1 :
					if (depthBits == 24)
						depthBits = 16;
					else if (depthBits == 16)
						depthBits = 8;
				case 3 :
					if (stencilBits == 24)
						stencilBits = 16;
					else if (stencilBits == 16)
						stencilBits = 8;
			}
		}

		testColorBits = colorBits;
		testDepthBits = depthBits;
		testStencilBits = stencilBits;

		if ((i % 4) == 3)
		{ // reduce colorBits
			if (testColorBits == 24)
				testColorBits = 16;
		}

		if ((i % 4) == 2)
		{ // reduce depthBits
			if (testDepthBits == 24)
				testDepthBits = 16;
			else if (testDepthBits == 16)
				testDepthBits = 8;
		}

		if ((i % 4) == 1)
		{ // reduce stencilBits
			if (testStencilBits == 24)
				testStencilBits = 16;
			else if (testStencilBits == 16)
				testStencilBits = 8;
			else
				testStencilBits = 0;
		}

		if (testColorBits == 24)
			perChannelColorBits = 8;
		else
			perChannelColorBits = 4;

#ifdef __sgi /* Fix for SGIs grabbing too many bits of color */
		if (perChannelColorBits == 4)
			perChannelColorBits = 0; /* Use minimum size for 16-bit color */

		/* Need alpha or else SGIs choose 36+ bit RGB mode */
		SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 1);
#endif

		SDL_GL_SetAttribute( SDL_GL_RED_SIZE, perChannelColorBits );
		SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, perChannelColorBits );
		SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, perChannelColorBits );
		SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, testDepthBits );
		SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, testStencilBits );

		SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, samples ? 1 : 0 );
		SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, samples );

		if(r_stereoEnabled->integer)
		{
			glConfig.stereoEnabled = qtrue;
			SDL_GL_SetAttribute(SDL_GL_STEREO, 1);
		}
		else
		{
			glConfig.stereoEnabled = qfalse;
			SDL_GL_SetAttribute(SDL_GL_STEREO, 0);
		}
		
		SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );

#if 0 // if multisampling is enabled on X11, this causes create window to fail.
		// If not allowing software GL, demand accelerated
		if( !r_allowSoftwareGL->integer )
			SDL_GL_SetAttribute( SDL_GL_ACCELERATED_VISUAL, 1 );
#endif

		if( ( SDL_window = SDL_CreateWindow( CLIENT_WINDOW_TITLE, x, y,
				glConfig.vidWidth, glConfig.vidHeight, flags ) ) == 0 )
		{
			ri.Printf( PRINT_DEVELOPER, "SDL_CreateWindow failed: %s\n", SDL_GetError( ) );
			continue;
		}

		if( fullscreen )
		{
			SDL_DisplayMode mode;

			switch( testColorBits )
			{
				case 16: mode.format = SDL_PIXELFORMAT_RGB565; break;
				case 24: mode.format = SDL_PIXELFORMAT_RGB24;  break;
				default: ri.Printf( PRINT_DEVELOPER, "testColorBits is %d, can't fullscreen\n", testColorBits ); continue;
			}

			mode.w = glConfig.vidWidth;
			mode.h = glConfig.vidHeight;
			mode.refresh_rate = glConfig.displayFrequency = ri.Cvar_VariableIntegerValue( "r_displayRefresh" );
			mode.driverdata = NULL;

			if( SDL_SetWindowDisplayMode( SDL_window, &mode ) < 0 )
			{
				ri.Printf( PRINT_DEVELOPER, "SDL_SetWindowDisplayMode failed: %s\n", SDL_GetError( ) );
				continue;
			}
		}

		SDL_SetWindowIcon( SDL_window, icon );

		if( ( SDL_glContext = SDL_GL_CreateContext( SDL_window ) ) == NULL )
		{
			ri.Printf( PRINT_DEVELOPER, "SDL_GL_CreateContext failed: %s\n", SDL_GetError( ) );
			continue;
		}

		qglClearColor( 0, 0, 0, 1 );
		qglClear( GL_COLOR_BUFFER_BIT );
		SDL_GL_SwapWindow( SDL_window );

		SDL_GL_SetSwapInterval( r_swapInterval->integer );

		glConfig.colorBits = testColorBits;
		glConfig.depthBits = testDepthBits;
		glConfig.stencilBits = testStencilBits;

		ri.Printf( PRINT_ALL, "Using %d color bits, %d depth, %d stencil display.\n",
				glConfig.colorBits, glConfig.depthBits, glConfig.stencilBits );
		break;
	}

	SDL_FreeSurface( icon );

	if( !SDL_window )
	{
		ri.Printf( PRINT_ALL, "Couldn't get a visual\n" );
		return RSERR_INVALID_MODE;
	}

	GLimp_DetectAvailableModes();

	glstring = (char *) qglGetString (GL_RENDERER);
	ri.Printf( PRINT_ALL, "GL_RENDERER: %s\n", glstring );

	return RSERR_OK;
}
Beispiel #15
0
/*
=================
RB_BeginDrawingView

Any mirrored or portaled views have already been drawn, so prepare
to actually render the visible surfaces for this view
=================
*/
void RB_BeginDrawingView (void) {
	int clearBits = 0;

	// sync with gl if needed
	if ( r_finish->integer == 1 && !glState.finishCalled ) {
		qglFinish ();
		glState.finishCalled = qtrue;
	}
	if ( r_finish->integer == 0 ) {
		glState.finishCalled = qtrue;
	}

	// we will need to change the projection matrix before drawing
	// 2D images again
	backEnd.projection2D = qfalse;

	if (glRefConfig.framebufferObject)
	{
		// FIXME: HUGE HACK: render to the screen fbo if we've already postprocessed the frame and aren't drawing more world
		// drawing more world check is in case of double renders, such as skyportals
		if (backEnd.viewParms.targetFbo == NULL)
		{
			if (!tr.renderFbo || (backEnd.framePostProcessed && (backEnd.refdef.rdflags & RDF_NOWORLDMODEL)))
			{
				FBO_Bind(NULL);
			}
			else
			{
				FBO_Bind(tr.renderFbo);
			}
		}
		else
		{
			FBO_Bind(backEnd.viewParms.targetFbo);

			// FIXME: hack for cubemap testing
			if (tr.renderCubeFbo && backEnd.viewParms.targetFbo == tr.renderCubeFbo)
			{
				//qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + backEnd.viewParms.targetFboLayer, backEnd.viewParms.targetFbo->colorImage[0]->texnum, 0);
				qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + backEnd.viewParms.targetFboLayer, tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex]->texnum, 0);
			}
		}
	}

	//
	// set the modelview matrix for the viewer
	//
	SetViewportAndScissor();

	// ensures that depth writes are enabled for the depth clear
	GL_State( GLS_DEFAULT );
	// clear relevant buffers
	clearBits = GL_DEPTH_BUFFER_BIT;

	if ( r_measureOverdraw->integer || r_shadows->integer == 2 )
	{
		clearBits |= GL_STENCIL_BUFFER_BIT;
	}
	if ( r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) )
	{
		clearBits |= GL_COLOR_BUFFER_BIT;	// FIXME: only if sky shaders have been used
#ifdef _DEBUG
		qglClearColor( 0.8f, 0.7f, 0.4f, 1.0f );	// FIXME: get color of sky
#else
		qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f );	// FIXME: get color of sky
#endif
	}

	// clear to white for shadow maps
	if (backEnd.viewParms.flags & VPF_SHADOWMAP)
	{
		clearBits |= GL_COLOR_BUFFER_BIT;
		qglClearColor( 1.0f, 1.0f, 1.0f, 1.0f );
	}

	// clear to black for cube maps
	if (tr.renderCubeFbo && backEnd.viewParms.targetFbo == tr.renderCubeFbo)
	{
		clearBits |= GL_COLOR_BUFFER_BIT;
		qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
	}

	qglClear( clearBits );

	if ( ( backEnd.refdef.rdflags & RDF_HYPERSPACE ) )
	{
		RB_Hyperspace();
		return;
	}
	else
	{
		backEnd.isHyperspace = qfalse;
	}

	glState.faceCulling = -1;		// force face culling to set next time

	// we will only draw a sun if there was sky rendered in this view
	backEnd.skyRenderedThisView = qfalse;

	// clip to the plane of the portal
	if ( backEnd.viewParms.isPortal ) {
#if 0
		float	plane[4];
		double	plane2[4];

		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;

		plane2[0] = DotProduct (backEnd.viewParms.or.axis[0], plane);
		plane2[1] = DotProduct (backEnd.viewParms.or.axis[1], plane);
		plane2[2] = DotProduct (backEnd.viewParms.or.axis[2], plane);
		plane2[3] = DotProduct (plane, backEnd.viewParms.or.origin) - plane[3];
#endif
		GL_SetModelviewMatrix( s_flipMatrix );
	}
}
Beispiel #16
0
/*
=================
RB_BeginDrawingView

Any mirrored or portaled views have already been drawn, so prepare
to actually render the visible surfaces for this view
=================
*/
static void RB_BeginDrawingView (void) {
	int clearBits = GL_DEPTH_BUFFER_BIT;

	// sync with gl if needed
	if ( r_finish->integer == 1 && !glState.finishCalled ) {
		qglFinish ();
		glState.finishCalled = qtrue;
	}
	if ( r_finish->integer == 0 ) {
		glState.finishCalled = qtrue;
	}

	// we will need to change the projection matrix before drawing
	// 2D images again
	backEnd.projection2D = qfalse;

	//
	// set the modelview matrix for the viewer
	//
	SetViewportAndScissor();

	// ensures that depth writes are enabled for the depth clear
	GL_State( GLS_DEFAULT );

	// clear relevant buffers
	if ( r_measureOverdraw->integer || r_shadows->integer == 2 || tr_stencilled )
	{
		clearBits |= GL_STENCIL_BUFFER_BIT;
		tr_stencilled = false;
	}

	if (skyboxportal)
	{
		if ( backEnd.refdef.rdflags & RDF_SKYBOXPORTAL )
		{	// portal scene, clear whatever is necessary
			if (r_fastsky->integer || (backEnd.refdef.rdflags & RDF_NOWORLDMODEL) )
			{	// fastsky: clear color
				// try clearing first with the portal sky fog color, then the world fog color, then finally a default
				clearBits |= GL_COLOR_BUFFER_BIT;
				if (tr.world && tr.world->globalFog != -1)
				{
					const fog_t		*fog = &tr.world->fogs[tr.world->globalFog];
					qglClearColor(fog->parms.color[0],  fog->parms.color[1], fog->parms.color[2], 1.0f );
				}
				else
				{
					qglClearColor ( 0.3f, 0.3f, 0.3f, 1.0 );
				}
			}			
		}
	}
	else
	{
		if ( r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) && !g_bRenderGlowingObjects )
		{
			if (tr.world && tr.world->globalFog != -1)
			{
				const fog_t		*fog = &tr.world->fogs[tr.world->globalFog];
				qglClearColor(fog->parms.color[0],  fog->parms.color[1], fog->parms.color[2], 1.0f );
			}
			else
			{
				qglClearColor( 0.3f, 0.3f, 0.3f, 1 );	// FIXME: get color of sky
			}
			clearBits |= GL_COLOR_BUFFER_BIT;	// FIXME: only if sky shaders have been used
		}
	}

	if ( !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) && ( r_DynamicGlow->integer && !g_bRenderGlowingObjects ) )
	{
		if (tr.world && tr.world->globalFog != -1)
		{ //this is because of a bug in multiple scenes I think, it needs to clear for the second scene but it doesn't normally.
			const fog_t		*fog = &tr.world->fogs[tr.world->globalFog];

			qglClearColor(fog->parms.color[0],  fog->parms.color[1], fog->parms.color[2], 1.0f );
			clearBits |= GL_COLOR_BUFFER_BIT;
		}
	}
	// If this pass is to just render the glowing objects, don't clear the depth buffer since
	// we're sharing it with the main scene (since the main scene has already been rendered). -AReis
	if ( g_bRenderGlowingObjects )
	{
		clearBits &= ~GL_DEPTH_BUFFER_BIT;
	}

	if (clearBits)
	{
		qglClear( clearBits );
	}

	if ( ( backEnd.refdef.rdflags & RDF_HYPERSPACE ) )
	{
		RB_Hyperspace();
		return;
	}
	else
	{
		backEnd.isHyperspace = qfalse;
	}

	glState.faceCulling = -1;		// force face culling to set next time

	// we will only draw a sun if there was sky rendered in this view
	backEnd.skyRenderedThisView = qfalse;

	// clip to the plane of the portal
	if ( backEnd.viewParms.isPortal ) {
		float	plane[4];
		double	plane2[4];

		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;

		plane2[0] = DotProduct (backEnd.viewParms.ori.axis[0], plane);
		plane2[1] = DotProduct (backEnd.viewParms.ori.axis[1], plane);
		plane2[2] = DotProduct (backEnd.viewParms.ori.axis[2], plane);
		plane2[3] = DotProduct (plane, backEnd.viewParms.ori.origin) - plane[3];

		qglLoadMatrixf( s_flipMatrix );
		qglClipPlane (GL_CLIP_PLANE0, plane2);
		qglEnable (GL_CLIP_PLANE0);
	} else {
		qglDisable (GL_CLIP_PLANE0);
	}
}
Beispiel #17
0
/*
====================
RE_BeginFrame

If running in stereo, RE_BeginFrame will be called twice
for each RE_EndFrame
====================
*/
void RE_BeginFrame( stereoFrame_t stereoFrame ) {
	drawBufferCommand_t *cmd = NULL;
	colorMaskCommand_t *colcmd = NULL;

	if ( !tr.registered ) {
		return;
	}
	glState.finishCalled = qfalse;

	tr.frameCount++;
	tr.frameSceneNum = 0;

	//
	// do overdraw measurement
	//
	if ( r_measureOverdraw->integer ) {
		if ( glConfig.stencilBits < 4 ) {
			ri.Printf( PRINT_ALL, "Warning: not enough stencil bits to measure overdraw: %d\n", glConfig.stencilBits );
			ri.Cvar_Set( "r_measureOverdraw", "0" );
			r_measureOverdraw->modified = qfalse;
		} else if ( r_shadows->integer == 2 )   {
			ri.Printf( PRINT_ALL, "Warning: stencil shadows and overdraw measurement are mutually exclusive\n" );
			ri.Cvar_Set( "r_measureOverdraw", "0" );
			r_measureOverdraw->modified = qfalse;
		} else
		{
			R_IssuePendingRenderCommands();
			qglEnable( GL_STENCIL_TEST );
			qglStencilMask( ~0U );
			qglClearStencil( 0U );
			qglStencilFunc( GL_ALWAYS, 0U, ~0U );
			qglStencilOp( GL_KEEP, GL_INCR, GL_INCR );
		}
		r_measureOverdraw->modified = qfalse;
	} else
	{
		// this is only reached if it was on and is now off
		if ( r_measureOverdraw->modified ) {
			R_IssuePendingRenderCommands();
			qglDisable( GL_STENCIL_TEST );
		}
		r_measureOverdraw->modified = qfalse;
	}

	//
	// texturemode stuff
	//
	if ( r_textureMode->modified ) {
		R_IssuePendingRenderCommands();
		GL_TextureMode( r_textureMode->string );
		r_textureMode->modified = qfalse;
	}

	//
	// ATI stuff
	//

	// TRUFORM
	if ( qglPNTrianglesiATI ) {

		// tess
		if ( r_ati_truform_tess->modified ) {
			r_ati_truform_tess->modified = qfalse;
			// cap if necessary
			if ( r_ati_truform_tess->value > glConfig.ATIMaxTruformTess ) {
				ri.Cvar_Set( "r_ati_truform_tess", va( "%d",glConfig.ATIMaxTruformTess ) );
			}

			qglPNTrianglesiATI( GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI, r_ati_truform_tess->value );
		}

		// point mode
		if ( r_ati_truform_pointmode->modified ) {
			r_ati_truform_pointmode->modified = qfalse;
			// GR - shorten the mode name
			if ( !Q_stricmp( r_ati_truform_pointmode->string, "LINEAR" ) ) {
				glConfig.ATIPointMode = (int)GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI;
				// GR - fix point mode change
			} else if ( !Q_stricmp( r_ati_truform_pointmode->string, "CUBIC" ) ) {
				glConfig.ATIPointMode = (int)GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI;
			} else {
				// bogus value, set to valid
				glConfig.ATIPointMode = (int)GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI;
				ri.Cvar_Set( "r_ati_truform_pointmode", "LINEAR" );
			}
			qglPNTrianglesiATI( GL_PN_TRIANGLES_POINT_MODE_ATI, glConfig.ATIPointMode );
		}

		// normal mode
		if ( r_ati_truform_normalmode->modified ) {
			r_ati_truform_normalmode->modified = qfalse;
			// GR - shorten the mode name
			if ( !Q_stricmp( r_ati_truform_normalmode->string, "LINEAR" ) ) {
				glConfig.ATINormalMode = (int)GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI;
				// GR - fix normal mode change
			} else if ( !Q_stricmp( r_ati_truform_normalmode->string, "QUADRATIC" ) ) {
				glConfig.ATINormalMode = (int)GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI;
			} else {
				// bogus value, set to valid
				glConfig.ATINormalMode = (int)GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI;
				ri.Cvar_Set( "r_ati_truform_normalmode", "LINEAR" );
			}
			qglPNTrianglesiATI( GL_PN_TRIANGLES_NORMAL_MODE_ATI, glConfig.ATINormalMode );
		}
	}

	//
	// NVidia stuff
	//

	// fog control
	if ( glConfig.NVFogAvailable && r_nv_fogdist_mode->modified ) {
		r_nv_fogdist_mode->modified = qfalse;
		if ( !Q_stricmp( r_nv_fogdist_mode->string, "GL_EYE_PLANE_ABSOLUTE_NV" ) ) {
			glConfig.NVFogMode = (int)GL_EYE_PLANE_ABSOLUTE_NV;
		} else if ( !Q_stricmp( r_nv_fogdist_mode->string, "GL_EYE_PLANE" ) ) {
			glConfig.NVFogMode = (int)GL_EYE_PLANE;
		} else if ( !Q_stricmp( r_nv_fogdist_mode->string, "GL_EYE_RADIAL_NV" ) ) {
			glConfig.NVFogMode = (int)GL_EYE_RADIAL_NV;
		} else {
			// in case this was really 'else', store a valid value for next time
			glConfig.NVFogMode = (int)GL_EYE_RADIAL_NV;
			ri.Cvar_Set( "r_nv_fogdist_mode", "GL_EYE_RADIAL_NV" );
		}
	}


	//
	// gamma stuff
	//
	if ( r_gamma->modified ) {
		r_gamma->modified = qfalse;

		R_IssuePendingRenderCommands();
		R_SetColorMappings();
	}

	// check for errors
	if ( !r_ignoreGLErrors->integer ) {
		int err;

		R_IssuePendingRenderCommands();
		if ( ( err = qglGetError() ) != GL_NO_ERROR ) {
			ri.Error( ERR_FATAL, "RE_BeginFrame() - glGetError() failed (0x%x)!", err );
		}
	}

	if (glConfig.stereoEnabled) {
		if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) )
			return;
			
		cmd->commandId = RC_DRAW_BUFFER;
		if ( stereoFrame == STEREO_LEFT ) {
			cmd->buffer = (int)GL_BACK_LEFT;
		} else if ( stereoFrame == STEREO_RIGHT ) {
			cmd->buffer = (int)GL_BACK_RIGHT;
		} else {
			ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame );
		}
	}
	else
	{
		if(r_anaglyphMode->integer)
		{
			if(r_anaglyphMode->modified)
			{
				// clear both, front and backbuffer.
				qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
				backEnd.colorMask[0] = GL_FALSE;
				backEnd.colorMask[1] = GL_FALSE;
				backEnd.colorMask[2] = GL_FALSE;
				backEnd.colorMask[3] = GL_FALSE;

				if (glRefConfig.framebufferObject)
				{
					// clear all framebuffers
					if (tr.msaaResolveFbo)
					{
						FBO_Bind(tr.msaaResolveFbo);
						qglClear(GL_COLOR_BUFFER_BIT);
					}

					if (tr.renderFbo)
					{
						FBO_Bind(tr.renderFbo);
						qglClear(GL_COLOR_BUFFER_BIT);
					}

					FBO_Bind(NULL);
				}

				qglDrawBuffer(GL_FRONT);
				qglClear(GL_COLOR_BUFFER_BIT);
				qglDrawBuffer(GL_BACK);
				qglClear(GL_COLOR_BUFFER_BIT);
				
				r_anaglyphMode->modified = qfalse;
			}
			
			if(stereoFrame == STEREO_LEFT)
			{
				if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) )
					return;
				
				if( !(colcmd = R_GetCommandBuffer(sizeof(*colcmd))) )
					return;
			}
			else if(stereoFrame == STEREO_RIGHT)
			{
				clearDepthCommand_t *cldcmd;
				
				if( !(cldcmd = R_GetCommandBuffer(sizeof(*cldcmd))) )
					return;

				cldcmd->commandId = RC_CLEARDEPTH;

				if( !(colcmd = R_GetCommandBuffer(sizeof(*colcmd))) )
					return;
			}
			else
				ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame );

			R_SetColorMode(colcmd->rgba, stereoFrame, r_anaglyphMode->integer);
			colcmd->commandId = RC_COLORMASK;
		}
		else
		{
			if(stereoFrame != STEREO_CENTER)
				ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is disabled, but stereoFrame was %i", stereoFrame );

			if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) )
				return;
		}

		if(cmd)
		{
			cmd->commandId = RC_DRAW_BUFFER;

			if(r_anaglyphMode->modified)
			{
				qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
				backEnd.colorMask[0] = 0;
				backEnd.colorMask[1] = 0;
				backEnd.colorMask[2] = 0;
				backEnd.colorMask[3] = 0;
				r_anaglyphMode->modified = qfalse;
			}

			if (!Q_stricmp(r_drawBuffer->string, "GL_FRONT"))
				cmd->buffer = (int)GL_FRONT;
			else
				cmd->buffer = (int)GL_BACK;
		}
	}

	tr.refdef.stereoFrame = stereoFrame;
}
Beispiel #18
0
/*
===============
RB_ShowImages

Draw all the images to the screen, on top of whatever
was there.  This is used to test for texture thrashing.

Also called by RE_EndRegistration
===============
*/
void RB_ShowImages( void ) {
	int		i;
	image_t	*image;
	float	x, y, w, h;
	int		start, end;
#ifdef VCMODS_OPENGLES
	vec2_t  texcoords[4] = { {0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f} };
	vec2_t  verts[4];
	glIndex_t indicies[6] = { 0, 1, 2, 0, 3, 2};
#endif

	if ( !backEnd.projection2D ) {
		RB_SetGL2D();
	}

	qglClear( GL_COLOR_BUFFER_BIT );

	qglFinish();

	start = ri.Milliseconds();
#ifdef VCMODS_OPENGLES
	qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
#endif

	for ( i=0 ; i<tr.numImages ; i++ ) {
		image = tr.images[i];

		w = glConfig.vidWidth / 20;
		h = glConfig.vidHeight / 15;
		x = i % 20 * w;
		y = i / 20 * h;

		// show in proportional size in mode 2
		if ( r_showImages->integer == 2 ) {
			w *= image->uploadWidth / 512.0f;
			h *= image->uploadHeight / 512.0f;
		}

#ifdef VCMODS_OPENGLES
		verts[0][0] = x;  verts[0][1] = y;
		verts[1][0] = x+w;  verts[1][1] = y;
		verts[2][0] = x+w;  verts[2][1] = y+h;
		verts[3][0] = x;  verts[3][1] = y+h;

		qglTexCoordPointer( 2, GL_FLOAT, 0, texcoords );
		qglVertexPointer  ( 2, GL_FLOAT, 0, verts );
		qglDrawElements( GL_TRIANGLE_STRIP, 6, GL_INDEX_TYPE, indicies );
#else
		GL_Bind( image );
		qglBegin (GL_QUADS);
		qglTexCoord2f( 0, 0 );
		qglVertex2f( x, y );
		qglTexCoord2f( 1, 0 );
		qglVertex2f( x + w, y );
		qglTexCoord2f( 1, 1 );
		qglVertex2f( x + w, y + h );
		qglTexCoord2f( 0, 1 );
		qglVertex2f( x, y + h );
		qglEnd();
#endif
	}

#ifdef VCMODS_OPENGLES
	qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
#endif
	qglFinish();

	end = ri.Milliseconds();
	ri.Printf( PRINT_ALL, "%i msec to draw all images\n", end - start );

}
Beispiel #19
0
/*
=================
RB_BeginDrawingView

Any mirrored or portaled views have already been drawn, so prepare
to actually render the visible surfaces for this view
=================
*/
void RB_BeginDrawingView(void)
{
	int clearBits = 0;

	// sync with gl if needed
	if(r_finish->integer == 1 && !glState.finishCalled)
	{
		qglFinish();
		glState.finishCalled = qtrue;
	}

	if(r_finish->integer == 0)
	{
		glState.finishCalled = qtrue;
	}

	// we will need to change the projection matrix before drawing
	// 2D images again
	backEnd.projection2D = qfalse;

	//
	// set the modelview matrix for the viewer
	//
	SetViewportAndScissor();

	// ensures that depth writes are enabled for the depth clear
	GL_State(GLS_DEFAULT);


////////// (SA) modified to ensure one glclear() per frame at most

	// clear relevant buffers
	clearBits = 0;

	if(r_measureOverdraw->integer || r_shadows->integer == 2)
	{
		clearBits |= GL_STENCIL_BUFFER_BIT;
	}

	if(r_uiFullScreen->integer)
	{
		clearBits = GL_DEPTH_BUFFER_BIT;    // (SA) always just clear depth for menus

	}
	else if(skyboxportal)
	{
		if(backEnd.refdef.rdflags & RDF_SKYBOXPORTAL)        // portal scene, clear whatever is necessary
		{
			clearBits |= GL_DEPTH_BUFFER_BIT;

			if(r_fastsky->integer || backEnd.refdef.rdflags & RDF_NOWORLDMODEL)       // fastsky: clear color
			{

				// try clearing first with the portal sky fog color, then the world fog color, then finally a default
				clearBits |= GL_COLOR_BUFFER_BIT;

				if(glfogsettings[FOG_PORTALVIEW].registered)
				{
					qglClearColor(glfogsettings[FOG_PORTALVIEW].color[0], glfogsettings[FOG_PORTALVIEW].color[1], glfogsettings[FOG_PORTALVIEW].color[2], glfogsettings[FOG_PORTALVIEW].color[3]);
				}
				else if(glfogNum > FOG_NONE && glfogsettings[FOG_CURRENT].registered)
				{
					qglClearColor(glfogsettings[FOG_CURRENT].color[0], glfogsettings[FOG_CURRENT].color[1], glfogsettings[FOG_CURRENT].color[2], glfogsettings[FOG_CURRENT].color[3]);
				}
				else
				{
//					qglClearColor ( 1.0, 0.0, 0.0, 1.0 );    // red clear for testing portal sky clear
					qglClearColor(0.5, 0.5, 0.5, 1.0);
				}
			}
			else                                                        // rendered sky (either clear color or draw quake sky)
			{
				if(glfogsettings[FOG_PORTALVIEW].registered)
				{
					qglClearColor(glfogsettings[FOG_PORTALVIEW].color[0], glfogsettings[FOG_PORTALVIEW].color[1], glfogsettings[FOG_PORTALVIEW].color[2], glfogsettings[FOG_PORTALVIEW].color[3]);

					if(glfogsettings[FOG_PORTALVIEW].clearscreen)         // portal fog requests a screen clear (distance fog rather than quake sky)
					{
						clearBits |= GL_COLOR_BUFFER_BIT;
					}
				}

			}
		}
		else                                            // world scene with portal sky, don't clear any buffers, just set the fog color if there is one
		{

			clearBits |= GL_DEPTH_BUFFER_BIT;   // this will go when I get the portal sky rendering way out in the zbuffer (or not writing to zbuffer at all)

			if(glfogNum > FOG_NONE && glfogsettings[FOG_CURRENT].registered)
			{
				if(backEnd.refdef.rdflags & RDF_UNDERWATER)
				{
					if(glfogsettings[FOG_CURRENT].mode == GL_LINEAR)
					{
						clearBits |= GL_COLOR_BUFFER_BIT;
					}

				}
				else if(!(r_portalsky->integer))             // portal skies have been manually turned off, clear bg color
				{
					clearBits |= GL_COLOR_BUFFER_BIT;
				}

				qglClearColor(glfogsettings[FOG_CURRENT].color[0], glfogsettings[FOG_CURRENT].color[1], glfogsettings[FOG_CURRENT].color[2], glfogsettings[FOG_CURRENT].color[3]);
			}
		}
	}
	else                                                  // world scene with no portal sky
	{
		clearBits |= GL_DEPTH_BUFFER_BIT;

		// NERVE - SMF - we don't want to clear the buffer when no world model is specified
		if(backEnd.refdef.rdflags & RDF_NOWORLDMODEL)
		{
			clearBits &= ~GL_COLOR_BUFFER_BIT;
		}
		// -NERVE - SMF
		// (SA) well, this is silly then
		else if(r_fastsky->integer)        //  || backEnd.refdef.rdflags & RDF_NOWORLDMODEL
		{

			clearBits |= GL_COLOR_BUFFER_BIT;

			if(glfogsettings[FOG_CURRENT].registered)      // try to clear fastsky with current fog color
			{
				qglClearColor(glfogsettings[FOG_CURRENT].color[0], glfogsettings[FOG_CURRENT].color[1], glfogsettings[FOG_CURRENT].color[2], glfogsettings[FOG_CURRENT].color[3]);
			}
			else
			{
//				qglClearColor ( 0.0, 0.0, 1.0, 1.0 ); // blue clear for testing world sky clear
				qglClearColor(0.5, 0.5, 0.5, 1.0);
			}
		}
		else            // world scene, no portal sky, not fastsky, clear color if fog says to, otherwise, just set the clearcolor
		{
			if(glfogsettings[FOG_CURRENT].registered)      // try to clear fastsky with current fog color
			{
				qglClearColor(glfogsettings[FOG_CURRENT].color[0], glfogsettings[FOG_CURRENT].color[1], glfogsettings[FOG_CURRENT].color[2], glfogsettings[FOG_CURRENT].color[3]);

				if(glfogsettings[FOG_CURRENT].clearscreen)        // world fog requests a screen clear (distance fog rather than quake sky)
				{
					clearBits |= GL_COLOR_BUFFER_BIT;
				}
			}
		}
	}


	if(clearBits)
	{
		qglClear(clearBits);
	}

//----(SA)  done

	if((backEnd.refdef.rdflags & RDF_HYPERSPACE))
	{
		RB_Hyperspace();
		return;
	}
	else
	{
		backEnd.isHyperspace = qfalse;
	}

	glState.faceCulling = -1;       // force face culling to set next time

	// we will only draw a sun if there was sky rendered in this view
	backEnd.skyRenderedThisView = qfalse;

	// clip to the plane of the portal
	if(backEnd.viewParms.isPortal)
	{
		float plane[4];
		double plane2[4];

		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;

		plane2[0] = DotProduct(backEnd.viewParms.or.axis[0], plane);
		plane2[1] = DotProduct(backEnd.viewParms.or.axis[1], plane);
		plane2[2] = DotProduct(backEnd.viewParms.or.axis[2], plane);
		plane2[3] = DotProduct(plane, backEnd.viewParms.or.origin) - plane[3];

		qglLoadMatrixf(s_flipMatrix);
		qglClipPlane(GL_CLIP_PLANE0, plane2);
		qglEnable(GL_CLIP_PLANE0);
	}
	else
	{
		qglDisable(GL_CLIP_PLANE0);
	}
}
Beispiel #20
0
/*
============
FBO_Init
============
*/
void FBO_Init(void)
{
	int             i;
	int             hdrFormat, multisample = 0;

	ri.Printf(PRINT_ALL, "------- FBO_Init -------\n");

	if(!glRefConfig.framebufferObject)
		return;

	tr.numFBOs = 0;

	GL_CheckErrors();

	R_IssuePendingRenderCommands();

	hdrFormat = GL_RGBA8;
	if (r_hdr->integer && glRefConfig.textureFloat)
		hdrFormat = GL_RGBA16F_ARB;

	if (glRefConfig.framebufferMultisample)
		qglGetIntegerv(GL_MAX_SAMPLES, &multisample);

	if (r_ext_framebuffer_multisample->integer < multisample)
		multisample = r_ext_framebuffer_multisample->integer;

	if (multisample < 2 || !glRefConfig.framebufferBlit)
		multisample = 0;

	if (multisample != r_ext_framebuffer_multisample->integer)
		ri.Cvar_SetValue("r_ext_framebuffer_multisample", (float)multisample);
	
	// only create a render FBO if we need to resolve MSAA or do HDR
	// otherwise just render straight to the screen (tr.renderFbo = NULL)
	if (multisample && glRefConfig.framebufferMultisample)
	{
		tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height);
		FBO_CreateBuffer(tr.renderFbo, hdrFormat, 0, multisample);
		FBO_CreateBuffer(tr.renderFbo, GL_DEPTH_COMPONENT24, 0, multisample);
		R_CheckFBO(tr.renderFbo);

		tr.msaaResolveFbo = FBO_Create("_msaaResolve", tr.renderDepthImage->width, tr.renderDepthImage->height);
		FBO_AttachImage(tr.msaaResolveFbo, tr.renderImage, GL_COLOR_ATTACHMENT0, 0);
		FBO_AttachImage(tr.msaaResolveFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT, 0);
		R_CheckFBO(tr.msaaResolveFbo);
	}
	else if (r_hdr->integer)
	{
		tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height);
		FBO_AttachImage(tr.renderFbo, tr.renderImage, GL_COLOR_ATTACHMENT0, 0);
		FBO_AttachImage(tr.renderFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT, 0);
		R_CheckFBO(tr.renderFbo);
	}

	// clear render buffer
	// this fixes the corrupt screen bug with r_hdr 1 on older hardware
	if (tr.renderFbo)
	{
		GL_BindFramebuffer(GL_FRAMEBUFFER, tr.renderFbo->frameBuffer);
		qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	}

	if (tr.screenScratchImage)
	{
		tr.screenScratchFbo = FBO_Create("screenScratch", tr.screenScratchImage->width, tr.screenScratchImage->height);
		FBO_AttachImage(tr.screenScratchFbo, tr.screenScratchImage, GL_COLOR_ATTACHMENT0, 0);
		FBO_AttachImage(tr.screenScratchFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT, 0);
		R_CheckFBO(tr.screenScratchFbo);
	}

	if (tr.sunRaysImage)
	{
		tr.sunRaysFbo = FBO_Create("_sunRays", tr.renderDepthImage->width, tr.renderDepthImage->height);
		FBO_AttachImage(tr.sunRaysFbo, tr.sunRaysImage, GL_COLOR_ATTACHMENT0, 0);
		FBO_AttachImage(tr.sunRaysFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT, 0);
		R_CheckFBO(tr.sunRaysFbo);
	}

	if (MAX_DRAWN_PSHADOWS && tr.pshadowMaps[0])
	{
		for( i = 0; i < MAX_DRAWN_PSHADOWS; i++)
		{
			tr.pshadowFbos[i] = FBO_Create(va("_shadowmap%d", i), tr.pshadowMaps[i]->width, tr.pshadowMaps[i]->height);
			// FIXME: this next line wastes 16mb with 16x512x512 sun shadow maps, skip if OpenGL 4.3+ or ARB_framebuffer_no_attachments
			FBO_CreateBuffer(tr.pshadowFbos[i], GL_RGBA8, 0, 0);
			FBO_AttachImage(tr.pshadowFbos[i], tr.pshadowMaps[i], GL_DEPTH_ATTACHMENT, 0);
			R_CheckFBO(tr.pshadowFbos[i]);
		}
	}

	if (tr.sunShadowDepthImage[0])
	{
		for (i = 0; i < 4; i++)
		{
			tr.sunShadowFbo[i] = FBO_Create("_sunshadowmap", tr.sunShadowDepthImage[i]->width, tr.sunShadowDepthImage[i]->height);
			// FIXME: this next line wastes 16mb with 4x1024x1024 sun shadow maps, skip if OpenGL 4.3+ or ARB_framebuffer_no_attachments
			// This at least gets sun shadows working on older GPUs (Intel)
			FBO_CreateBuffer(tr.sunShadowFbo[i], GL_RGBA8, 0, 0);
			FBO_AttachImage(tr.sunShadowFbo[i], tr.sunShadowDepthImage[i], GL_DEPTH_ATTACHMENT, 0);
			R_CheckFBO(tr.sunShadowFbo[i]);
		}
	}

	if (tr.screenShadowImage)
	{
		tr.screenShadowFbo = FBO_Create("_screenshadow", tr.screenShadowImage->width, tr.screenShadowImage->height);
		FBO_AttachImage(tr.screenShadowFbo, tr.screenShadowImage, GL_COLOR_ATTACHMENT0, 0);
		R_CheckFBO(tr.screenShadowFbo);
	}

	if (tr.textureScratchImage[0])
	{
		for (i = 0; i < 2; i++)
		{
			tr.textureScratchFbo[i] = FBO_Create(va("_texturescratch%d", i), tr.textureScratchImage[i]->width, tr.textureScratchImage[i]->height);
			FBO_AttachImage(tr.textureScratchFbo[i], tr.textureScratchImage[i], GL_COLOR_ATTACHMENT0, 0);
			R_CheckFBO(tr.textureScratchFbo[i]);
		}
	}

	if (tr.calcLevelsImage)
	{
		tr.calcLevelsFbo = FBO_Create("_calclevels", tr.calcLevelsImage->width, tr.calcLevelsImage->height);
		FBO_AttachImage(tr.calcLevelsFbo, tr.calcLevelsImage, GL_COLOR_ATTACHMENT0, 0);
		R_CheckFBO(tr.calcLevelsFbo);
	}

	if (tr.targetLevelsImage)
	{
		tr.targetLevelsFbo = FBO_Create("_targetlevels", tr.targetLevelsImage->width, tr.targetLevelsImage->height);
		FBO_AttachImage(tr.targetLevelsFbo, tr.targetLevelsImage, GL_COLOR_ATTACHMENT0, 0);
		R_CheckFBO(tr.targetLevelsFbo);
	}

	if (tr.quarterImage[0])
	{
		for (i = 0; i < 2; i++)
		{
			tr.quarterFbo[i] = FBO_Create(va("_quarter%d", i), tr.quarterImage[i]->width, tr.quarterImage[i]->height);
			FBO_AttachImage(tr.quarterFbo[i], tr.quarterImage[i], GL_COLOR_ATTACHMENT0, 0);
			R_CheckFBO(tr.quarterFbo[i]);
		}
	}

	if (tr.hdrDepthImage)
	{
		tr.hdrDepthFbo = FBO_Create("_hdrDepth", tr.hdrDepthImage->width, tr.hdrDepthImage->height);
		FBO_AttachImage(tr.hdrDepthFbo, tr.hdrDepthImage, GL_COLOR_ATTACHMENT0, 0);
		R_CheckFBO(tr.hdrDepthFbo);
	}

	if (tr.screenSsaoImage)
	{
		tr.screenSsaoFbo = FBO_Create("_screenssao", tr.screenSsaoImage->width, tr.screenSsaoImage->height);
		FBO_AttachImage(tr.screenSsaoFbo, tr.screenSsaoImage, GL_COLOR_ATTACHMENT0, 0);
		R_CheckFBO(tr.screenSsaoFbo);
	}

	if (tr.renderCubeImage)
	{
		tr.renderCubeFbo = FBO_Create("_renderCubeFbo", tr.renderCubeImage->width, tr.renderCubeImage->height);
		FBO_AttachImage(tr.renderCubeFbo, tr.renderCubeImage, GL_COLOR_ATTACHMENT0, 0);
		FBO_CreateBuffer(tr.renderCubeFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);
		R_CheckFBO(tr.renderCubeFbo);
	}

	GL_CheckErrors();

	GL_BindFramebuffer(GL_FRAMEBUFFER, 0);
	glState.currentFBO = NULL;
}
Beispiel #21
0
/*
 * RB_BeginDrawingView
 *
 * Any mirrored or portaled views have already been drawn, so prepare
 * to actually render the visible surfaces for this view
 */
void
RB_BeginDrawingView(void)
{
	int clearBits = 0;

	/* sync with gl if needed */
	if(r_finish->integer == 1 && !glState.finishCalled){
		qglFinish ();
		glState.finishCalled = qtrue;
	}
	if(r_finish->integer == 0){
		glState.finishCalled = qtrue;
	}

	/* we will need to change the projection matrix before drawing
	 * 2D images again */
	backEnd.projection2D = qfalse;

	if(glRefConfig.framebufferObject){
		/* FIXME: HUGE HACK: render to the screen fbo if we've already postprocessed the frame and aren't drawing more world */
		if(backEnd.viewParms.targetFbo == tr.renderFbo && backEnd.framePostProcessed &&
		   (backEnd.refdef.rdflags & RDF_NOWORLDMODEL)){
			FBO_Bind(tr.screenScratchFbo);
		}else{
			FBO_Bind(backEnd.viewParms.targetFbo);
		}
	}

	/*
	 * set the modelview matrix for the viewer
	 *  */
	SetViewportAndScissor();

	/* ensures that depth writes are enabled for the depth clear */
	GL_State(GLS_DEFAULT);
	/* clear relevant buffers */
	clearBits = GL_DEPTH_BUFFER_BIT;

	if(r_measureOverdraw->integer || r_shadows->integer == 2){
		clearBits |= GL_STENCIL_BUFFER_BIT;
	}
	if(r_fastsky->integer && !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL)){
		clearBits |= GL_COLOR_BUFFER_BIT;	/* FIXME: only if sky shaders have been used */
#ifdef _DEBUG
		qglClearColor(0.8f, 0.7f, 0.4f, 1.0f);	/* FIXME: get color of sky */
#else
		qglClearColor(0.0f, 0.0f, 0.0f, 1.0f);	/* FIXME: get color of sky */
#endif
	}

	/* clear to white for shadow maps */
	if(backEnd.viewParms.isShadowmap){
		clearBits |= GL_COLOR_BUFFER_BIT;
		qglClearColor(1.0f, 1.0f, 1.0f, 1.0f);
	}

	qglClear(clearBits);

	if((backEnd.refdef.rdflags & RDF_HYPERSPACE)){
		RB_Hyperspace();
		return;
	}else{
		backEnd.isHyperspace = qfalse;
	}

	glState.faceCulling = -1;	/* force face culling to set next time */

	/* we will only draw a sun if there was sky rendered in this view */
	backEnd.skyRenderedThisView = qfalse;

#ifdef REACTION
	backEnd.hasSunFlare = qfalse;
#endif

	/* clip to the plane of the portal */
	if(backEnd.viewParms.isPortal){
		float plane[4];
		double plane2[4];

		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;

		plane2[0] = dotv3 (backEnd.viewParms.or.axis[0], plane);
		plane2[1] = dotv3 (backEnd.viewParms.or.axis[1], plane);
		plane2[2] = dotv3 (backEnd.viewParms.or.axis[2], plane);
		plane2[3] = dotv3 (plane, backEnd.viewParms.or.origin) - plane[3];

		GL_SetModelviewMatrix(s_flipMatrix);
	}
}
Beispiel #22
0
/*
==================
RB_R200_DrawInteractions

==================
*/
void RB_R200_DrawInteractions( void ) {
	qglEnable( GL_STENCIL_TEST );

	for ( viewLight_t *vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) {
		// do fogging later
		if ( vLight->lightShader->IsFogLight() ) {
			continue;
		}
		if ( vLight->lightShader->IsBlendLight() ) {
			continue;
		}

		backEnd.vLight = vLight;

		RB_LogComment( "---------- RB_RenderViewLight 0x%p ----------\n", vLight );

		// clear the stencil buffer if needed
		if ( vLight->globalShadows || vLight->localShadows ) {
			backEnd.currentScissor = vLight->scissorRect;
			if ( r_useScissor.GetBool() ) {
				qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1, 
					backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1,
					backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1,
					backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 );
			}
			qglClear( GL_STENCIL_BUFFER_BIT );
		} else {
			// no shadows, so no need to read or write the stencil buffer
			// we might in theory want to use GL_ALWAYS instead of disabling
			// completely, to satisfy the invarience rules
			qglStencilFunc( GL_ALWAYS, 128, 255 );
		}

		if ( r_useShadowVertexProgram.GetBool() ) {
			qglEnable( GL_VERTEX_PROGRAM_ARB );
			qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_STENCIL_SHADOW );
			RB_StencilShadowPass( vLight->globalShadows );

			RB_R200_ARB_CreateDrawInteractions( vLight->localInteractions );

			qglEnable( GL_VERTEX_PROGRAM_ARB );
			qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_STENCIL_SHADOW );
			RB_StencilShadowPass( vLight->localShadows );

			RB_R200_ARB_CreateDrawInteractions( vLight->globalInteractions );

			qglDisable( GL_VERTEX_PROGRAM_ARB );	// if there weren't any globalInteractions, it would have stayed on
		} else {
			RB_StencilShadowPass( vLight->globalShadows );
			RB_R200_ARB_CreateDrawInteractions( vLight->localInteractions );

			RB_StencilShadowPass( vLight->localShadows );
			RB_R200_ARB_CreateDrawInteractions( vLight->globalInteractions );
		}

		if ( r_skipTranslucent.GetBool() ) {
			continue;
		}

		// disable stencil testing for translucent interactions, because
		// the shadow isn't calculated at their point, and the shadow
		// behind them may be depth fighting with a back side, so there
		// isn't any reasonable thing to do
		qglStencilFunc( GL_ALWAYS, 128, 255 );
		RB_R200_ARB_CreateDrawInteractions( vLight->translucentInteractions );
	}
}
Beispiel #23
0
/*
====================
RE_BeginFrame

If running in stereo, RE_BeginFrame will be called twice
for each RE_EndFrame
====================
*/
void RE_BeginFrame( stereoFrame_t stereoFrame ) {
	drawBufferCommand_t	*cmd = NULL;
	colorMaskCommand_t *colcmd = NULL;

	if ( !tr.registered ) {
		return;
	}
	glState.finishCalled = qfalse;

	tr.frameCount++;
	tr.frameSceneNum = 0;

	//
	// do overdraw measurement
	//
	#ifndef HAVE_GLES
	if ( r_measureOverdraw->integer )
	{
		if ( glConfig.stencilBits < 4 )
		{
			ri.Printf( PRINT_ALL, "Warning: not enough stencil bits to measure overdraw: %d\n", glConfig.stencilBits );
			ri.Cvar_Set( "r_measureOverdraw", "0" );
			r_measureOverdraw->modified = qfalse;
		}
		else if ( r_shadows->integer == 2 )
		{
			ri.Printf( PRINT_ALL, "Warning: stencil shadows and overdraw measurement are mutually exclusive\n" );
			ri.Cvar_Set( "r_measureOverdraw", "0" );
			r_measureOverdraw->modified = qfalse;
		}
		else
		{
			R_IssuePendingRenderCommands();
			qglEnable( GL_STENCIL_TEST );
			qglStencilMask( ~0U );
			qglClearStencil( 0U );
			qglStencilFunc( GL_ALWAYS, 0U, ~0U );
			qglStencilOp( GL_KEEP, GL_INCR, GL_INCR );
		}
		r_measureOverdraw->modified = qfalse;
	}
	else
	{
		// this is only reached if it was on and is now off
		if ( r_measureOverdraw->modified ) {
			R_IssuePendingRenderCommands();
			qglDisable( GL_STENCIL_TEST );
		}
		r_measureOverdraw->modified = qfalse;
	}
	#endif

	//
	// texturemode stuff
	//
	if ( r_textureMode->modified ) {
		R_IssuePendingRenderCommands();
		GL_TextureMode( r_textureMode->string );
		r_textureMode->modified = qfalse;
	}

	//
	// gamma stuff
	//
	if ( r_gamma->modified ) {
		r_gamma->modified = qfalse;

		R_IssuePendingRenderCommands();
		R_SetColorMappings();
	}

	// check for errors
	if ( !r_ignoreGLErrors->integer )
	{
		int	err;

		R_IssuePendingRenderCommands();
		if ((err = qglGetError()) != GL_NO_ERROR)
			ri.Error(ERR_FATAL, "RE_BeginFrame() - glGetError() failed (0x%x)!", err);
	}

	#ifndef HAVE_GLES
	if (glConfig.stereoEnabled) {
		if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) )
			return;
			
		cmd->commandId = RC_DRAW_BUFFER;
		
		if ( stereoFrame == STEREO_LEFT ) {
			cmd->buffer = (int)GL_BACK_LEFT;
		} else if ( stereoFrame == STEREO_RIGHT ) {
			cmd->buffer = (int)GL_BACK_RIGHT;
		} else {
			ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame );
		}
	}
	else
	{
		if(r_anaglyphMode->integer)
		{
			if(r_anaglyphMode->modified)
			{
				// clear both, front and backbuffer.
				qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
				qglClearColor(0.0f, 0.0f, 0.0f, 1.0f);
				
				qglDrawBuffer(GL_FRONT);
				qglClear(GL_COLOR_BUFFER_BIT);
				qglDrawBuffer(GL_BACK);
				qglClear(GL_COLOR_BUFFER_BIT);
				
				r_anaglyphMode->modified = qfalse;
			}
			
			if(stereoFrame == STEREO_LEFT)
			{
				if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) )
					return;
				
				if( !(colcmd = R_GetCommandBuffer(sizeof(*colcmd))) )
					return;
			}
			else if(stereoFrame == STEREO_RIGHT)
			{
				clearDepthCommand_t *cldcmd;
				
				if( !(cldcmd = R_GetCommandBuffer(sizeof(*cldcmd))) )
					return;

				cldcmd->commandId = RC_CLEARDEPTH;

				if( !(colcmd = R_GetCommandBuffer(sizeof(*colcmd))) )
					return;
			}
			else
				ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame );

			R_SetColorMode(colcmd->rgba, stereoFrame, r_anaglyphMode->integer);
			colcmd->commandId = RC_COLORMASK;
		}
		else
#endif
		{
			if(stereoFrame != STEREO_CENTER)
				ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is disabled, but stereoFrame was %i", stereoFrame );

			if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) )
				return;
		}

		if(cmd)
		{
			cmd->commandId = RC_DRAW_BUFFER;

#ifndef HAVE_GLES
			if(r_anaglyphMode->modified)
			{
				qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
				r_anaglyphMode->modified = qfalse;
			}

			if (!Q_stricmp(r_drawBuffer->string, "GL_FRONT"))
				cmd->buffer = (int)GL_FRONT;
			else
#endif
				cmd->buffer = (int)GL_BACK;
		}
#ifndef HAVE_GLES
	}
#endif
	
	tr.refdef.stereoFrame = stereoFrame;
}
/*
==================
RB_STD_FogAllLights
==================
*/
void RB_STD_FogAllLights(void)
{
	viewLight_t	*vLight;

	if (r_skipFogLights.GetBool() || r_showOverDraw.GetInteger() != 0
	    || backEnd.viewDef->isXraySubview /* dont fog in xray mode*/
	   ) {
		return;
	}

	RB_LogComment("---------- RB_STD_FogAllLights ----------\n");

	qglDisable(GL_STENCIL_TEST);

	for (vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next) {
		backEnd.vLight = vLight;

		if (!vLight->lightShader->IsFogLight() && !vLight->lightShader->IsBlendLight()) {
			continue;
		}

#if 0 // _D3XP disabled that

		if (r_ignore.GetInteger()) {
			// we use the stencil buffer to guarantee that no pixels will be
			// double fogged, which happens in some areas that are thousands of
			// units from the origin
			backEnd.currentScissor = vLight->scissorRect;

			if (r_useScissor.GetBool()) {
				qglScissor(backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1,
				           backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1,
				           backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1,
				           backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1);
			}

			qglClear(GL_STENCIL_BUFFER_BIT);

			qglEnable(GL_STENCIL_TEST);

			// only pass on the cleared stencil values
			qglStencilFunc(GL_EQUAL, 128, 255);

			// when we pass the stencil test and depth test and are going to draw,
			// increment the stencil buffer so we don't ever draw on that pixel again
			qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
		}

#endif

		if (vLight->lightShader->IsFogLight()) {
			RB_FogPass(vLight->globalInteractions, vLight->localInteractions);
		} else if (vLight->lightShader->IsBlendLight()) {
			RB_BlendLight(vLight->globalInteractions, vLight->localInteractions);
		}

		qglDisable(GL_STENCIL_TEST);
	}

	qglEnable(GL_STENCIL_TEST);
}
Beispiel #25
0
/*
=============
RB_DrawBuffer

=============
*/
const void	*RB_DrawBuffer( const void *data ) {
	const drawBufferCommand_t	*cmd;

	cmd = (const drawBufferCommand_t *)data;

	qglDrawBuffer( cmd->buffer );

		// clear screen for debugging
	if (tr.world && tr.refdef.doLAGoggles)
	{
		fog_t		*fog = &tr.world->fogs[tr.world->numfogs];

		qglClearColor(fog->parms.color[0],  fog->parms.color[1], fog->parms.color[2], 1.0f );
		qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	}
	else if (tr.world && tr.world->globalFog != -1)
	{
		const unsigned int i = tr.world->fogs[tr.world->globalFog].colorInt;

		qglClearColor( ( (byte *)&i )[0] / 255.0, ( (byte *)&i )[1] / 255.0, ( (byte *)&i )[2] / 255.0,  1.0 );
		qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	}
	else if ( r_clear->integer ) 
	{	// clear screen for debugging
		int i = r_clear->integer;
		if (i == 42) {
			i = Q_irand(0,8);
		}
		switch (i)
		{
		default:
			qglClearColor( 1, 0, 0.5, 1 );
			break;
		case 1:
			qglClearColor( 1.0, 0.0, 0.0, 1.0); //red
			break;
		case 2:
			qglClearColor( 0.0, 1.0, 0.0, 1.0); //green
			break;
		case 3:
			qglClearColor( 1.0, 1.0, 0.0, 1.0); //yellow
			break;
		case 4:
			qglClearColor( 0.0, 0.0, 1.0, 1.0); //blue
			break;
		case 5:
			qglClearColor( 0.0, 1.0, 1.0, 1.0); //cyan
			break;
		case 6:
			qglClearColor( 1.0, 0.0, 1.0, 1.0); //magenta
			break;
		case 7:
			qglClearColor( 1.0, 1.0, 1.0, 1.0); //white
			break;
		case 8:
			qglClearColor( 0.0, 0.0, 0.0, 1.0); //black
			break;
		}		
		qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	}

	return (const void *)(cmd + 1);
}
Beispiel #26
0
/*
============
FBO_Init
============
*/
void FBO_Init(void)
{
	int             i;
	// int             width, height, hdrFormat, multisample;
	int             hdrFormat, multisample;

	ri.Printf(PRINT_ALL, "------- FBO_Init -------\n");

	if(!glRefConfig.framebufferObject)
		return;

	tr.numFBOs = 0;

	GL_CheckErrors();

	R_IssuePendingRenderCommands();

/*	if(glRefConfig.textureNonPowerOfTwo)
	{
		width = glConfig.vidWidth;
		height = glConfig.vidHeight;
	}
	else
	{
		width = NextPowerOfTwo(glConfig.vidWidth);
		height = NextPowerOfTwo(glConfig.vidHeight);
	} */

	hdrFormat = GL_RGBA8;
	if (r_hdr->integer && glRefConfig.framebufferObject && glRefConfig.textureFloat)
	{
		hdrFormat = GL_RGBA16F_ARB;
	}

	qglGetIntegerv(GL_MAX_SAMPLES_EXT, &multisample);

	if (r_ext_framebuffer_multisample->integer < multisample)
	{
		multisample = r_ext_framebuffer_multisample->integer;
	}

	if (multisample < 2 || !glRefConfig.framebufferBlit)
		multisample = 0;

	if (multisample != r_ext_framebuffer_multisample->integer)
	{
		ri.Cvar_SetValue("r_ext_framebuffer_multisample", (float)multisample);
	}
	
	// only create a render FBO if we need to resolve MSAA or do HDR
	// otherwise just render straight to the screen (tr.renderFbo = NULL)
	if (multisample && glRefConfig.framebufferMultisample)
	{
		tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height);
		FBO_Bind(tr.renderFbo);

		FBO_CreateBuffer(tr.renderFbo, hdrFormat, 0, multisample);
		FBO_CreateBuffer(tr.renderFbo, GL_DEPTH_COMPONENT24_ARB, 0, multisample);

		R_CheckFBO(tr.renderFbo);


		tr.msaaResolveFbo = FBO_Create("_msaaResolve", tr.renderDepthImage->width, tr.renderDepthImage->height);
		FBO_Bind(tr.msaaResolveFbo);

		//FBO_CreateBuffer(tr.msaaResolveFbo, hdrFormat, 0, 0);
		FBO_AttachTextureImage(tr.renderImage, 0);

		//FBO_CreateBuffer(tr.msaaResolveFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);
		R_AttachFBOTextureDepth(tr.renderDepthImage->texnum);

		R_CheckFBO(tr.msaaResolveFbo);
	}
	else if (r_hdr->integer)
	{
		tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height);
		FBO_Bind(tr.renderFbo);

		//FBO_CreateBuffer(tr.renderFbo, hdrFormat, 0, 0);
		FBO_AttachTextureImage(tr.renderImage, 0);

		//FBO_CreateBuffer(tr.renderFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);
		R_AttachFBOTextureDepth(tr.renderDepthImage->texnum);

		R_CheckFBO(tr.renderFbo);
	}

	// clear render buffer
	// this fixes the corrupt screen bug with r_hdr 1 on older hardware
	if (tr.renderFbo)
	{
		FBO_Bind(tr.renderFbo);
		qglClearColor( 1, 0, 0.5, 1 );
		qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
		FBO_Bind(NULL);
	}

	if (r_drawSunRays->integer)
	{
		tr.sunRaysFbo = FBO_Create("_sunRays", tr.renderDepthImage->width, tr.renderDepthImage->height);
		FBO_Bind(tr.sunRaysFbo);

		FBO_AttachTextureImage(tr.sunRaysImage, 0);

		R_AttachFBOTextureDepth(tr.renderDepthImage->texnum);

		R_CheckFBO(tr.sunRaysFbo);
	}

	// FIXME: Don't use separate color/depth buffers for a shadow buffer
	if (MAX_DRAWN_PSHADOWS && tr.pshadowMaps[0])
	{
		for( i = 0; i < MAX_DRAWN_PSHADOWS; i++)
		{
			tr.pshadowFbos[i] = FBO_Create(va("_shadowmap%d", i), tr.pshadowMaps[i]->width, tr.pshadowMaps[i]->height);
			FBO_Bind(tr.pshadowFbos[i]);

			//FBO_CreateBuffer(tr.pshadowFbos[i], GL_RGBA8, 0, 0);
			FBO_AttachTextureImage(tr.pshadowMaps[i], 0);

			FBO_CreateBuffer(tr.pshadowFbos[i], GL_DEPTH_COMPONENT24_ARB, 0, 0);
			//R_AttachFBOTextureDepth(tr.textureDepthImage->texnum);

			R_CheckFBO(tr.pshadowFbos[i]);
		}
	}

	if (tr.sunShadowDepthImage[0])
	{
		for ( i = 0; i < 4; i++)
		{
			tr.sunShadowFbo[i] = FBO_Create("_sunshadowmap", tr.sunShadowDepthImage[i]->width, tr.sunShadowDepthImage[i]->height);
			FBO_Bind(tr.sunShadowFbo[i]);

			//FBO_CreateBuffer(tr.sunShadowFbo[i], GL_RGBA8, 0, 0);
			//FBO_AttachTextureImage(tr.sunShadowImage, 0);
			qglDrawBuffer(GL_NONE);
			qglReadBuffer(GL_NONE);

			//FBO_CreateBuffer(tr.sunShadowFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);
			R_AttachFBOTextureDepth(tr.sunShadowDepthImage[i]->texnum);

			R_CheckFBO(tr.sunShadowFbo[i]);

		}

		tr.screenShadowFbo = FBO_Create("_screenshadow", tr.screenShadowImage->width, tr.screenShadowImage->height);
		FBO_Bind(tr.screenShadowFbo);

		FBO_AttachTextureImage(tr.screenShadowImage, 0);

		R_CheckFBO(tr.screenShadowFbo);
	}

	for (i = 0; i < 2; i++)
	{
		tr.textureScratchFbo[i] = FBO_Create(va("_texturescratch%d", i), tr.textureScratchImage[i]->width, tr.textureScratchImage[i]->height);
		FBO_Bind(tr.textureScratchFbo[i]);

		//FBO_CreateBuffer(tr.textureScratchFbo[i], GL_RGBA8, 0, 0);
		FBO_AttachTextureImage(tr.textureScratchImage[i], 0);

		R_CheckFBO(tr.textureScratchFbo[i]);
	}

	{
		tr.calcLevelsFbo = FBO_Create("_calclevels", tr.calcLevelsImage->width, tr.calcLevelsImage->height);
		FBO_Bind(tr.calcLevelsFbo);

		//FBO_CreateBuffer(tr.calcLevelsFbo, hdrFormat, 0, 0);
		FBO_AttachTextureImage(tr.calcLevelsImage, 0);

		R_CheckFBO(tr.calcLevelsFbo);
	}

	{
		tr.targetLevelsFbo = FBO_Create("_targetlevels", tr.targetLevelsImage->width, tr.targetLevelsImage->height);
		FBO_Bind(tr.targetLevelsFbo);

		//FBO_CreateBuffer(tr.targetLevelsFbo, hdrFormat, 0, 0);
		FBO_AttachTextureImage(tr.targetLevelsImage, 0);

		R_CheckFBO(tr.targetLevelsFbo);
	}

	for (i = 0; i < 2; i++)
	{
		tr.quarterFbo[i] = FBO_Create(va("_quarter%d", i), tr.quarterImage[i]->width, tr.quarterImage[i]->height);
		FBO_Bind(tr.quarterFbo[i]);

		//FBO_CreateBuffer(tr.quarterFbo[i], hdrFormat, 0, 0);
		FBO_AttachTextureImage(tr.quarterImage[i], 0);

		R_CheckFBO(tr.quarterFbo[i]);
	}

	if (r_ssao->integer)
	{
		tr.hdrDepthFbo = FBO_Create("_hdrDepth", tr.hdrDepthImage->width, tr.hdrDepthImage->height);
		FBO_Bind(tr.hdrDepthFbo);

		FBO_AttachTextureImage(tr.hdrDepthImage, 0);

		R_CheckFBO(tr.hdrDepthFbo);

		tr.screenSsaoFbo = FBO_Create("_screenssao", tr.screenSsaoImage->width, tr.screenSsaoImage->height);
		FBO_Bind(tr.screenSsaoFbo);
		
		FBO_AttachTextureImage(tr.screenSsaoImage, 0);

		R_CheckFBO(tr.screenSsaoFbo);
	}

	if (tr.renderCubeImage)
	{
		tr.renderCubeFbo = FBO_Create("_renderCubeFbo", tr.renderCubeImage->width, tr.renderCubeImage->height);
		FBO_Bind(tr.renderCubeFbo);
		
		//FBO_AttachTextureImage(tr.renderCubeImage, 0);
		R_AttachFBOTexture2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, tr.renderCubeImage->texnum, 0);
		glState.currentFBO->colorImage[0] = tr.renderCubeImage;

		FBO_CreateBuffer(tr.renderCubeFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);

		R_CheckFBO(tr.renderCubeFbo);
	}

	GL_CheckErrors();

	FBO_Bind(NULL);
}
Beispiel #27
0
void Glimp_ClearScreen(void)
{
	qglClearColor(0, 0, 0, 1);
	qglClear(GL_COLOR_BUFFER_BIT);
	ri.GLimp_SwapFrame();
}
Beispiel #28
0
/*
=============
RB_DrawSurfs

=============
*/
const void	*RB_DrawSurfs( const void *data ) {
	const drawSurfsCommand_t	*cmd;

	// finish any 2D drawing if needed
	if ( tess.numIndexes ) {
		RB_EndSurface();
	}

	cmd = (const drawSurfsCommand_t *)data;

	backEnd.refdef = cmd->refdef;
	backEnd.viewParms = cmd->viewParms;

	// clear the z buffer, set the modelview, etc
	RB_BeginDrawingView ();

	if (glRefConfig.framebufferObject && (backEnd.viewParms.flags & VPF_DEPTHCLAMP) && glRefConfig.depthClamp)
	{
		qglEnable(GL_DEPTH_CLAMP);
	}

	if (glRefConfig.framebufferObject && !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL) && (r_depthPrepass->integer || (backEnd.viewParms.flags & VPF_DEPTHSHADOW)))
	{
		FBO_t *oldFbo = glState.currentFBO;

		backEnd.depthFill = qtrue;
		qglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
		RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs );
		qglColorMask(!backEnd.colorMask[0], !backEnd.colorMask[1], !backEnd.colorMask[2], !backEnd.colorMask[3]);
		backEnd.depthFill = qfalse;

		if (tr.msaaResolveFbo)
		{
			// If we're using multisampling, resolve the depth first
			FBO_FastBlit(tr.renderFbo, NULL, tr.msaaResolveFbo, NULL, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
		}
		else if (tr.renderFbo == NULL)
		{
			// If we're rendering directly to the screen, copy the depth to a texture
			GL_BindToTMU(tr.renderDepthImage, 0);
			qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, 0, 0, glConfig.vidWidth, glConfig.vidHeight, 0);
		}

		if (r_ssao->integer)
		{
			// need the depth in a texture we can do GL_LINEAR sampling on, so copy it to an HDR image
			FBO_BlitFromTexture(tr.renderDepthImage, NULL, NULL, tr.hdrDepthFbo, NULL, NULL, NULL, 0);
		}

		if (r_sunlightMode->integer && backEnd.viewParms.flags & VPF_USESUNLIGHT)
		{
			vec4_t quadVerts[4];
			vec2_t texCoords[4];
			vec4_t box;

			FBO_Bind(tr.screenShadowFbo);

			box[0] = backEnd.viewParms.viewportX      * tr.screenShadowFbo->width  / (float)glConfig.vidWidth;
			box[1] = backEnd.viewParms.viewportY      * tr.screenShadowFbo->height / (float)glConfig.vidHeight;
			box[2] = backEnd.viewParms.viewportWidth  * tr.screenShadowFbo->width  / (float)glConfig.vidWidth;
			box[3] = backEnd.viewParms.viewportHeight * tr.screenShadowFbo->height / (float)glConfig.vidHeight;

			qglViewport(box[0], box[1], box[2], box[3]);
			qglScissor(box[0], box[1], box[2], box[3]);

			box[0] = backEnd.viewParms.viewportX               / (float)glConfig.vidWidth;
			box[1] = backEnd.viewParms.viewportY               / (float)glConfig.vidHeight;
			box[2] = box[0] + backEnd.viewParms.viewportWidth  / (float)glConfig.vidWidth;
			box[3] = box[1] + backEnd.viewParms.viewportHeight / (float)glConfig.vidHeight;

			texCoords[0][0] = box[0]; texCoords[0][1] = box[3];
			texCoords[1][0] = box[2]; texCoords[1][1] = box[3];
			texCoords[2][0] = box[2]; texCoords[2][1] = box[1];
			texCoords[3][0] = box[0]; texCoords[3][1] = box[1];

			box[0] = -1.0f;
			box[1] = -1.0f;
			box[2] =  1.0f;
			box[3] =  1.0f;

			VectorSet4(quadVerts[0], box[0], box[3], 0, 1);
			VectorSet4(quadVerts[1], box[2], box[3], 0, 1);
			VectorSet4(quadVerts[2], box[2], box[1], 0, 1);
			VectorSet4(quadVerts[3], box[0], box[1], 0, 1);

			GL_State( GLS_DEPTHTEST_DISABLE );

			GLSL_BindProgram(&tr.shadowmaskShader);

			GL_BindToTMU(tr.renderDepthImage, TB_COLORMAP);
			
			if (r_shadowCascadeZFar->integer != 0)
			{
				GL_BindToTMU(tr.sunShadowDepthImage[0], TB_SHADOWMAP);
				GL_BindToTMU(tr.sunShadowDepthImage[1], TB_SHADOWMAP2);
				GL_BindToTMU(tr.sunShadowDepthImage[2], TB_SHADOWMAP3);
				GL_BindToTMU(tr.sunShadowDepthImage[3], TB_SHADOWMAP4);

				GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP,  backEnd.refdef.sunShadowMvp[0]);
				GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP2, backEnd.refdef.sunShadowMvp[1]);
				GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP3, backEnd.refdef.sunShadowMvp[2]);
				GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP4, backEnd.refdef.sunShadowMvp[3]);
			}
			else
			{
				GL_BindToTMU(tr.sunShadowDepthImage[3], TB_SHADOWMAP);
				GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP, backEnd.refdef.sunShadowMvp[3]);
			}
			
			GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWORIGIN,  backEnd.refdef.vieworg);
			{
				vec4_t viewInfo;
				vec3_t viewVector;

				float zmax = backEnd.viewParms.zFar;
				float ymax = zmax * tan(backEnd.viewParms.fovY * M_PI / 360.0f);
				float xmax = zmax * tan(backEnd.viewParms.fovX * M_PI / 360.0f);

				float zmin = r_znear->value;

				VectorScale(backEnd.refdef.viewaxis[0], zmax, viewVector);
				GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWFORWARD, viewVector);
				VectorScale(backEnd.refdef.viewaxis[1], xmax, viewVector);
				GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWLEFT,    viewVector);
				VectorScale(backEnd.refdef.viewaxis[2], ymax, viewVector);
				GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWUP,      viewVector);

				VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0);

				GLSL_SetUniformVec4(&tr.shadowmaskShader, UNIFORM_VIEWINFO, viewInfo);
			}


			RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes);
		}

		if (r_ssao->integer)
		{
			vec4_t quadVerts[4];
			vec2_t texCoords[4];

			FBO_Bind(tr.quarterFbo[0]);

			qglViewport(0, 0, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height);
			qglScissor(0, 0, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height);

			VectorSet4(quadVerts[0], -1,  1, 0, 1);
			VectorSet4(quadVerts[1],  1,  1, 0, 1);
			VectorSet4(quadVerts[2],  1, -1, 0, 1);
			VectorSet4(quadVerts[3], -1, -1, 0, 1);

			texCoords[0][0] = 0; texCoords[0][1] = 1;
			texCoords[1][0] = 1; texCoords[1][1] = 1;
			texCoords[2][0] = 1; texCoords[2][1] = 0;
			texCoords[3][0] = 0; texCoords[3][1] = 0;

			GL_State( GLS_DEPTHTEST_DISABLE );

			GLSL_BindProgram(&tr.ssaoShader);

			GL_BindToTMU(tr.hdrDepthImage, TB_COLORMAP);

			{
				vec4_t viewInfo;

				float zmax = backEnd.viewParms.zFar;
				float zmin = r_znear->value;

				VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0);

				GLSL_SetUniformVec4(&tr.ssaoShader, UNIFORM_VIEWINFO, viewInfo);
			}

			RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes);


			FBO_Bind(tr.quarterFbo[1]);

			qglViewport(0, 0, tr.quarterFbo[1]->width, tr.quarterFbo[1]->height);
			qglScissor(0, 0, tr.quarterFbo[1]->width, tr.quarterFbo[1]->height);

			GLSL_BindProgram(&tr.depthBlurShader[0]);

			GL_BindToTMU(tr.quarterImage[0],  TB_COLORMAP);
			GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP);

			{
				vec4_t viewInfo;

				float zmax = backEnd.viewParms.zFar;
				float zmin = r_znear->value;

				VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0);

				GLSL_SetUniformVec4(&tr.depthBlurShader[0], UNIFORM_VIEWINFO, viewInfo);
			}

			RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes);


			FBO_Bind(tr.screenSsaoFbo);

			qglViewport(0, 0, tr.screenSsaoFbo->width, tr.screenSsaoFbo->height);
			qglScissor(0, 0, tr.screenSsaoFbo->width, tr.screenSsaoFbo->height);

			GLSL_BindProgram(&tr.depthBlurShader[1]);

			GL_BindToTMU(tr.quarterImage[1],  TB_COLORMAP);
			GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP);

			{
				vec4_t viewInfo;

				float zmax = backEnd.viewParms.zFar;
				float zmin = r_znear->value;

				VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0);

				GLSL_SetUniformVec4(&tr.depthBlurShader[1], UNIFORM_VIEWINFO, viewInfo);
			}


			RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes);
		}

		// reset viewport and scissor
		FBO_Bind(oldFbo);
		SetViewportAndScissor();
	}

	if (glRefConfig.framebufferObject && (backEnd.viewParms.flags & VPF_DEPTHCLAMP) && glRefConfig.depthClamp)
	{
		qglDisable(GL_DEPTH_CLAMP);
	}

	if (!(backEnd.viewParms.flags & VPF_DEPTHSHADOW))
	{
		RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs );

		if (r_drawSun->integer)
		{
			RB_DrawSun(0.1, tr.sunShader);
		}

		if (r_drawSunRays->integer)
		{
			FBO_t *oldFbo = glState.currentFBO;
			FBO_Bind(tr.sunRaysFbo);
			
			qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
			qglClear( GL_COLOR_BUFFER_BIT );

			if (glRefConfig.occlusionQuery)
			{
				tr.sunFlareQueryActive[tr.sunFlareQueryIndex] = qtrue;
				qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, tr.sunFlareQuery[tr.sunFlareQueryIndex]);
			}

			RB_DrawSun(0.3, tr.sunFlareShader);

			if (glRefConfig.occlusionQuery)
			{
				qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
			}

			FBO_Bind(oldFbo);
		}

		// darken down any stencil shadows
		RB_ShadowFinish();		

		// add light flares on lights that aren't obscured
		RB_RenderFlares();
	}

	if (glRefConfig.framebufferObject && tr.renderCubeFbo && backEnd.viewParms.targetFbo == tr.renderCubeFbo)
	{
		FBO_Bind(NULL);
		GL_SelectTexture(TB_CUBEMAP);
		GL_BindToTMU(tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex], TB_CUBEMAP);
		qglGenerateMipmapEXT(GL_TEXTURE_CUBE_MAP);
		GL_SelectTexture(0);
	}

	return (const void *)(cmd + 1);
}
Beispiel #29
0
void idGLDrawableModel::draw(int x, int y, int w, int h) {
    if ( !worldModel ) {
        return;
    }
    if ( worldModel->IsDynamicModel() != DM_STATIC ) {
        //return;
    }

    rect.Set( x, y, w, h );

    qglViewport(x, y, w, h);
    qglScissor(x, y, w, h);
    qglMatrixMode(GL_PROJECTION);
    qglClearColor( 0.1f, 0.1f, 0.1f, 0.0f );
    qglClear(GL_COLOR_BUFFER_BIT);

    if (worldDirty) {
        //InitWorld();
        world->InitFromMap( NULL );
        renderLight_t	parms;
        idDict spawnArgs;
        spawnArgs.Set("classname", "light");
        spawnArgs.Set("name", "light_1");
        spawnArgs.Set("origin", "-128 0 0");
        idStr str;
        sprintf(str, "%f %f %f", light, light, light);
        spawnArgs.Set("_color", str);
        gameEdit->ParseSpawnArgsToRenderLight( &spawnArgs, &parms );
        lightDef = world->AddLightDef( &parms );

        renderEntity_t worldEntity;
        memset( &worldEntity, 0, sizeof( worldEntity ) );
        spawnArgs.Clear();
        spawnArgs.Set("classname", "func_static");
        spawnArgs.Set("name", spawnArgs.GetString("model"));
        spawnArgs.Set("origin", "0 0 0");
        if ( skinStr.Length() ) {
            spawnArgs.Set( "skin", skinStr );
        }
        gameEdit->ParseSpawnArgsToRenderEntity(&spawnArgs, &worldEntity);
        worldEntity.hModel = worldModel;

        worldEntity.axis = rotation.ToMat3();

        worldEntity.shaderParms[0] = 1;
        worldEntity.shaderParms[1] = 1;
        worldEntity.shaderParms[2] = 1;
        worldEntity.shaderParms[3] = 1;
        modelDef = world->AddEntityDef( &worldEntity );

        worldDirty = false;
    }

    renderView_t	refdef;
    // render it
    renderSystem->BeginFrame(w, h);
    memset( &refdef, 0, sizeof( refdef ) );
    refdef.vieworg.Set(zOffset, xOffset, -yOffset);

    refdef.viewaxis = idAngles(0,0,0).ToMat3();
    refdef.shaderParms[0] = 1;
    refdef.shaderParms[1] = 1;
    refdef.shaderParms[2] = 1;
    refdef.shaderParms[3] = 1;

    refdef.width = SCREEN_WIDTH;
    refdef.height = SCREEN_HEIGHT;
    refdef.fov_x = 90;
    refdef.fov_y = 2 * atan((float)h / w) * idMath::M_RAD2DEG;

    refdef.time = eventLoop->Milliseconds();

    world->RenderScene( &refdef );
    int frontEnd, backEnd;
    renderSystem->EndFrame( &frontEnd, &backEnd );

    qglMatrixMode( GL_MODELVIEW );
    qglLoadIdentity();
}
Beispiel #30
0
/*
==============
RenderBumpFlat_f

==============
*/
void RenderBumpFlat_f( const idCmdArgs &args ) {
	int		width, height;
	idStr	source;
	int		i;
	idBounds	bounds;
	srfTriangles_t	*mesh;

	// update the screen as we print
	common->SetRefreshOnPrint( true );

	width = height = 256;

	// check options
	for ( i = 1 ; i < args.Argc() - 1; i++ ) {
		const char *s;

		s = args.Argv( i );
		if ( s[0] == '-' ) {
			i++;
			s = args.Argv( i );
		}

		if ( !idStr::Icmp( s, "size" ) ) {
			if ( i + 2 >= args.Argc() ) {
				i = args.Argc();
				break;
			}
			width = atoi( args.Argv( i + 1 ) );
			height = atoi( args.Argv( i + 2 ) );
			i += 2;
		} else {
			common->Printf( "WARNING: Unknown option \"%s\"\n", s );
			break;
		}
	}

	if ( i != ( args.Argc() - 1 ) ) {
		common->Error( "usage: renderBumpFlat [-size width height] asefile" );
		return;
	}

	common->Printf( "Final image size: %i, %i\n", width, height );

	// load the source in "fastload" mode, because we don't
	// need tangent and shadow information
	source = args.Argv( i );

	idRenderModel *highPolyModel = renderModelManager->AllocModel();

	highPolyModel->PartialInitFromFile( source );

	if ( highPolyModel->IsDefaultModel() ) {
		common->Error( "failed to load %s", source.c_str() );
	}

	// combine the high poly model into a single polyset
	if ( highPolyModel->NumSurfaces() != 1 ) {
		highPolyModel = CombineModelSurfaces( highPolyModel );
	}

	// create normals if not present in file
	const modelSurface_t *surf = highPolyModel->Surface( 0 );
	mesh = surf->geometry;

	// bound the entire file
	R_BoundTriSurf( mesh );
	bounds = mesh->bounds;

	SaveWindow();
	ResizeWindow( width, height );

	// for small images, the viewport may be less than the minimum window
	qglViewport( 0, 0, width, height );

	qglEnable( GL_CULL_FACE );
	qglCullFace( GL_FRONT );
	qglDisable( GL_STENCIL_TEST );
	qglDisable( GL_SCISSOR_TEST );
	qglDisable( GL_ALPHA_TEST );
	qglDisable( GL_BLEND );
	qglEnable( GL_DEPTH_TEST );
	qglDisable( GL_TEXTURE_2D );
	qglDepthMask( GL_TRUE );
	qglDepthFunc( GL_LEQUAL );

	qglColor3f( 1, 1, 1 );

	qglMatrixMode( GL_PROJECTION );
	qglLoadIdentity();
	qglOrtho( bounds[0][0], bounds[1][0], bounds[0][2],
		bounds[1][2], -( bounds[0][1] - 1 ), -( bounds[1][1] + 1 ) );

	qglMatrixMode( GL_MODELVIEW );
	qglLoadIdentity();

	// flat maps are automatically anti-aliased

	idStr	filename;
	int		j, k, c;
	byte	*buffer;
	int		*sumBuffer, *colorSumBuffer;
	bool	flat;
	int		sample;

	sumBuffer = (int *)Mem_Alloc( width * height * 4 * 4 );
	memset( sumBuffer, 0, width * height * 4 * 4 );
	buffer = (byte *)Mem_Alloc( width * height * 4 );

	colorSumBuffer = (int *)Mem_Alloc( width * height * 4 * 4 );
	memset( sumBuffer, 0, width * height * 4 * 4 );

	flat = false;
//flat = true;

	for ( sample = 0 ; sample < 16 ; sample++ ) {
		float	xOff, yOff;

		xOff = ( ( sample & 3 ) / 4.0 ) * ( bounds[1][0] - bounds[0][0] ) / width;
		yOff = ( ( sample / 4 ) / 4.0 ) * ( bounds[1][2] - bounds[0][2] ) / height;

		for ( int colorPass = 0 ; colorPass < 2 ; colorPass++ ) {
			qglClearColor(0.5,0.5,0.5,0);
			qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

			qglBegin( GL_TRIANGLES );
			for ( i = 0 ; i < highPolyModel->NumSurfaces() ; i++ ) {
				const modelSurface_t *surf = highPolyModel->Surface( i );

				mesh = surf->geometry;

				if ( colorPass ) {
					// just render the surface color for artist visualization
					for ( j = 0 ; j < mesh->numIndexes ; j+=3 ) {
						for ( k = 0 ; k < 3 ; k++ ) {
							int		v;
							float	*a;

							v = mesh->indexes[j+k];
							qglColor3ubv( mesh->verts[v].color );
							a = mesh->verts[v].xyz.ToFloatPtr();
							qglVertex3f( a[0] + xOff, a[2] + yOff, a[1] );
						}
					}
				} else {
					// render as normal map
					// we can either flat shade from the plane,
					// or smooth shade from the vertex normals
					for ( j = 0 ; j < mesh->numIndexes ; j+=3 ) {
						if ( flat ) {
							idPlane		plane;
							idVec3		*a, *b, *c;
							int			v1, v2, v3;

							v1 = mesh->indexes[j+0];
							v2 = mesh->indexes[j+1];
							v3 = mesh->indexes[j+2];

							a = &mesh->verts[ v1 ].xyz;
							b = &mesh->verts[ v2 ].xyz;
							c = &mesh->verts[ v3 ].xyz;

							plane.FromPoints( *a, *b, *c );

							// NULLNORMAL is used by the artists to force an area to reflect no
							// light at all
							if ( surf->shader->GetSurfaceFlags() & SURF_NULLNORMAL ) {
								qglColor3f( 0.5, 0.5, 0.5 );
							} else {
								qglColor3f( 0.5 + 0.5*plane[0], 0.5 - 0.5*plane[2], 0.5 - 0.5*plane[1] );
							}

							qglVertex3f( (*a)[0] + xOff, (*a)[2] + yOff, (*a)[1] );
							qglVertex3f( (*b)[0] + xOff, (*b)[2] + yOff, (*b)[1] );
							qglVertex3f( (*c)[0] + xOff, (*c)[2] + yOff, (*c)[1] );
						} else {
							for ( k = 0 ; k < 3 ; k++ ) {
								int		v;
								float	*n;
								float	*a;

								v = mesh->indexes[j+k];
								n = mesh->verts[v].normal.ToFloatPtr();

								// NULLNORMAL is used by the artists to force an area to reflect no
								// light at all
								if ( surf->shader->GetSurfaceFlags() & SURF_NULLNORMAL ) {
									qglColor3f( 0.5, 0.5, 0.5 );
								} else {
								// we are going to flip the normal Z direction
									qglColor3f( 0.5 + 0.5*n[0], 0.5 - 0.5*n[2], 0.5 - 0.5*n[1] );
								}

								a = mesh->verts[v].xyz.ToFloatPtr();
								qglVertex3f( a[0] + xOff, a[2] + yOff, a[1] );
							}
						}
					}
				}
			}

			qglEnd();
			qglFlush();
			GLimp_SwapBuffers();
			qglReadPixels( 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer );

			c = width * height;

			if ( colorPass ) {
				// add to the sum buffer
				for ( i = 0 ; i < c ; i++ ) {
					colorSumBuffer[i*4+0] += buffer[i*4+0];
					colorSumBuffer[i*4+1] += buffer[i*4+1];
					colorSumBuffer[i*4+2] += buffer[i*4+2];
					colorSumBuffer[i*4+3] += buffer[i*4+3];
				}
			} else {
				// normalize
				for ( i = 0 ; i < c ; i++ ) {
					idVec3	v;

					v[0] = ( buffer[i*4+0] - 128 ) / 127.0;
					v[1] = ( buffer[i*4+1] - 128 ) / 127.0;
					v[2] = ( buffer[i*4+2] - 128 ) / 127.0;

					v.Normalize();

					buffer[i*4+0] = 128 + 127 * v[0];
					buffer[i*4+1] = 128 + 127 * v[1];
					buffer[i*4+2] = 128 + 127 * v[2];
				}

				// outline into non-drawn areas
				for ( i = 0 ; i < 8 ; i++ ) {
					OutlineNormalMap( buffer, width, height, 128, 128, 128 );
				}

				// add to the sum buffer
				for ( i = 0 ; i < c ; i++ ) {
					sumBuffer[i*4+0] += buffer[i*4+0];
					sumBuffer[i*4+1] += buffer[i*4+1];
					sumBuffer[i*4+2] += buffer[i*4+2];
					sumBuffer[i*4+3] += buffer[i*4+3];
				}
			}
		}
	}

	c = width * height;

	// save out the color map
	for ( i = 0 ; i < c ; i++ ) {
		buffer[i*4+0] = colorSumBuffer[i*4+0] / 16;
		buffer[i*4+1] = colorSumBuffer[i*4+1] / 16;
		buffer[i*4+2] = colorSumBuffer[i*4+2] / 16;
		buffer[i*4+3] = colorSumBuffer[i*4+3] / 16;
	}
	filename = source;
	filename.StripFileExtension();
	filename.Append( "_color.tga" );
	R_VerticalFlip( buffer, width, height );
	R_WriteTGA( filename, buffer, width, height );

	// save out the local map
	// scale the sum buffer back down to the sample buffer
	// we allow this to denormalize
	for ( i = 0 ; i < c ; i++ ) {
		buffer[i*4+0] = sumBuffer[i*4+0] / 16;
		buffer[i*4+1] = sumBuffer[i*4+1] / 16;
		buffer[i*4+2] = sumBuffer[i*4+2] / 16;
		buffer[i*4+3] = sumBuffer[i*4+3] / 16;
	}

	filename = source;
	filename.StripFileExtension();
	filename.Append( "_local.tga" );
	common->Printf( "writing %s (%i,%i)\n", filename.c_str(), width, height );
	R_VerticalFlip( buffer, width, height );
	R_WriteTGA( filename, buffer, width, height );


	// free the model
	renderModelManager->FreeModel( highPolyModel );

	// free our work buffer
	Mem_Free( buffer );
	Mem_Free( sumBuffer );
	Mem_Free( colorSumBuffer );

	RestoreWindow();

	// stop updating the screen as we print
	common->SetRefreshOnPrint( false );

	common->Error( "Completed." );
}