Пример #1
0
/*
=============
RE_StretchRaw

FIXME: not exactly backend
Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle.
Used for cinematics.
=============
*/
void RE_StretchRaw( int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty ) {
	int i, j;
	int start, end;

	if ( !tr.registered ) {
		return;
	}
	R_IssuePendingRenderCommands();

	if ( tess.numIndexes ) {
		RB_EndSurface();
	}

	// we definately want to sync every frame for the cinematics
	qglFinish();

	start = 0;
	if ( r_speeds->integer ) {
		start = ri.Milliseconds();
	}

	// make sure rows and cols are powers of 2
	for ( i = 0 ; ( 1 << i ) < cols ; i++ ) {
	}
	for ( j = 0 ; ( 1 << j ) < rows ; j++ ) {
	}
	if ( ( 1 << i ) != cols || ( 1 << j ) != rows ) {
		ri.Error( ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows );
	}

	GL_Bind( tr.scratchImage[client] );

	// if the scratchImage isn't in the format we want, specify it as a new texture
	if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) {
		tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols;
		tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows;
#ifdef USE_OPENGLES
		qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
#else
		qglTexImage2D( GL_TEXTURE_2D, 0, 3, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
#endif
		qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
		qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
		qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
		qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
	} else {
		if ( dirty ) {
			// otherwise, just subimage upload it so that drivers can tell we are going to be changing
			// it and don't try and do a texture compression
			qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data );
		}
	}

	if ( r_speeds->integer ) {
		end = ri.Milliseconds();
		ri.Printf( PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start );
	}

	RB_SetGL2D();

	qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight );

#ifdef USE_OPENGLES
	GLfloat tex[] = {
	 0.5f / cols,  0.5f / rows,
	 ( cols - 0.5f ) / cols ,  0.5f / rows,
	 ( cols - 0.5f ) / cols, ( rows - 0.5f ) / rows,
	 0.5f / cols, ( rows - 0.5f ) / rows };
	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 (!text)
		qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
	if (glcol)
		qglEnableClientState(GL_COLOR_ARRAY);
#else
	qglBegin( GL_QUADS );
	qglTexCoord2f( 0.5f / cols,  0.5f / rows );
	qglVertex2f( x, y );
	qglTexCoord2f( ( cols - 0.5f ) / cols,  0.5f / rows );
	qglVertex2f( x + w, y );
	qglTexCoord2f( ( cols - 0.5f ) / cols, ( rows - 0.5f ) / rows );
	qglVertex2f( x + w, y + h );
	qglTexCoord2f( 0.5f / cols, ( rows - 0.5f ) / rows );
	qglVertex2f( x, y + h );
	qglEnd();
#endif
}
Пример #2
0
qhandle_t RE_RegisterSkin( const char *name ) {
	qhandle_t	hSkin;
	skin_t		*skin;

	if ( !name || !name[0] ) {
		ri->Printf( PRINT_ALL, "Empty name passed to RE_RegisterSkin\n" );
		return 0;
	}

	if ( strlen( name ) >= MAX_QPATH ) {
		ri->Printf( PRINT_ALL, "Skin name exceeds MAX_QPATH\n" );
		return 0;
	}

	// see if the skin is already loaded
	for ( hSkin = 1; hSkin < tr.numSkins ; hSkin++ ) {
		skin = tr.skins[hSkin];
		if ( !Q_stricmp( skin->name, name ) ) {
			if( skin->numSurfaces == 0 ) {
				return 0;		// default skin
			}
			return hSkin;
		}
	}

	// allocate a new skin
	if ( tr.numSkins == MAX_SKINS ) {
		ri->Printf( PRINT_ALL, "WARNING: RE_RegisterSkin( '%s' ) MAX_SKINS hit\n", name );
		return 0;
	}
	tr.numSkins++;
	skin = (struct skin_s *)Hunk_Alloc( sizeof( skin_t ), h_low );
	tr.skins[hSkin] = skin;
	Q_strncpyz( skin->name, name, sizeof( skin->name ) );
	skin->numSurfaces = 0;

	// make sure the render thread is stopped
	R_IssuePendingRenderCommands();

	// If not a .skin file, load as a single shader
	if ( strcmp( name + strlen( name ) - 5, ".skin" ) ) {
/*		skin->numSurfaces = 1;
		skin->surfaces[0] = (skinSurface_t *)Hunk_Alloc( sizeof(skin->surfaces[0]), h_low );
		skin->surfaces[0]->shader = R_FindShader( name, lightmapsNone, stylesDefault, qtrue );
		return hSkin;
*/
	}

	char skinhead[MAX_QPATH]={0};
	char skintorso[MAX_QPATH]={0};
	char skinlower[MAX_QPATH]={0};
	if ( RE_SplitSkins(name, (char*)&skinhead, (char*)&skintorso, (char*)&skinlower ) )
	{//three part
		hSkin = RE_RegisterIndividualSkin(skinhead, hSkin);
		if (hSkin && strcmp(skinhead, skintorso))
		{
			hSkin = RE_RegisterIndividualSkin(skintorso, hSkin);
		}

		if (hSkin && strcmp(skinhead, skinlower) && strcmp(skintorso, skinlower))
		{
			hSkin = RE_RegisterIndividualSkin(skinlower, hSkin);
		}
	}
	else
	{//single skin
		hSkin = RE_RegisterIndividualSkin(name, hSkin);
	}
	return(hSkin);
}
Пример #3
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;
	}

	//
	// 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;
}
Пример #4
0
/*
=============
RE_EndRegistration

Touch all images to make sure they are resident
=============
*/
void RE_EndRegistration( void ) {
	R_IssuePendingRenderCommands();
	if (!ri.Sys_LowPhysicalMemory()) {
		RB_ShowImages();
	}
}
Пример #5
0
/*
====================
RE_RegisterModel

Loads in a model for the given name

Zero will be returned if the model fails to load.
An entry will be retained for failed models as an
optimization to prevent disk rescanning if they are
asked for again.
====================
*/
qhandle_t RE_RegisterModel(const char *name)
{
	model_t   *mod;
	byte      *buffer;
	int       bufferLen = 0;
	int       lod;
	int       ident;
	qboolean  loaded;
	qhandle_t hModel;
	int       numLoaded;

	if (!name || !name[0])
	{
		Ren_Developer("RE_RegisterModel: NULL name\n");
		return 0;
	}
	else
	{
		Ren_Developer("RE_RegisterModel model: %s\n", name);
	}

	if (strlen(name) >= MAX_QPATH)
	{
		Ren_Print("Model name exceeds MAX_QPATH\n");
		return 0;
	}

	// search the currently loaded models
	for (hModel = 1; hModel < tr.numModels; hModel++)
	{
		mod = tr.models[hModel];
		if (!strcmp(mod->name, name))
		{
			if (mod->type == MOD_BAD)
			{
				return 0;
			}
			return hModel;
		}
	}

	// allocate a new model_t
	if ((mod = R_AllocModel()) == NULL)
	{
		Ren_Warning("RE_RegisterModel: R_AllocModel() failed for '%s'\n", name);
		return 0;
	}

	// only set the name after the model has been successfully loaded
	Q_strncpyz(mod->name, name, sizeof(mod->name));

	// make sure the render thread is stopped
	R_IssuePendingRenderCommands();

	mod->numLods = 0;

	// load the files
	numLoaded = 0;

	if (strstr(name, ".mds") || strstr(name, ".mdm") || strstr(name, ".mdx") || strstr(name, ".md5mesh") || strstr(name, ".psk"))
	{
		// try loading skeletal file

		loaded    = qfalse;
		bufferLen = ri.FS_ReadFile(name, (void **)&buffer);
		if (buffer)
		{
			loadmodel = mod;

			ident = LittleLong(*(unsigned *)buffer);
#if 0
			if (ident == MDS_IDENT)
			{
				loaded = R_LoadMDS(mod, buffer, name);
			}
			else
#endif
			if (ident == MDM_IDENT)
			{
				loaded = R_LoadMDM(mod, buffer, name);
			}
			else if (ident == MDX_IDENT)
			{
				loaded = R_LoadMDX(mod, buffer, name);
			}

#if defined(USE_REFENTITY_ANIMATIONSYSTEM)
			if (!Q_stricmpn((const char *)buffer, "MD5Version", 10))
			{
				loaded = R_LoadMD5(mod, buffer, bufferLen, name);
			}
			else if (!Q_stricmpn((const char *)buffer, PSK_IDENTSTRING, PSK_IDENTLEN))
			{
				loaded = R_LoadPSK(mod, buffer, bufferLen, name);
			}
#endif
			ri.FS_FreeFile(buffer);
		}

		if (loaded)
		{
			// make sure the VBO glState entries are save
			R_BindNullVBO();
			R_BindNullIBO();

			return mod->index;
		}
	}

	for (lod = MD3_MAX_LODS - 1; lod >= 0; lod--)
	{
		char filename[1024];
		buffer = NULL;

		strcpy(filename, name);
		if (lod != 0)
		{
			char namebuf[80];

			if (strrchr(filename, '.'))
			{
				*strrchr(filename, '.') = 0;
			}
			sprintf(namebuf, "_%d.md3", lod);
			strcat(filename, namebuf);
		}

		filename[strlen(filename) - 1] = 'c';   // try MDC first
		if (ri.FS_FOpenFileRead(filename, NULL, qfalse))
		{
			ri.FS_ReadFile(filename, (void **)&buffer);
		}
		if (!buffer)
		{
			filename[strlen(filename) - 1] = '3';   // try MD3 second
			if (ri.FS_FOpenFileRead(filename, NULL, qfalse))
			{
				ri.FS_ReadFile(filename, (void **)&buffer);
			}
			if (!buffer)
			{
				continue;
			}
		}

		loadmodel = mod;

		ident = LittleLong(*(unsigned *)buffer);
		if (ident != MD3_IDENT && ident != MDC_IDENT)
		{
			Ren_Warning("RE_RegisterModel: unknown fileid for %s\n", name);
			ri.FS_FreeFile(buffer);
			goto fail;
		}

		if (ident == MD3_IDENT)
		{
			loaded = R_LoadMD3(mod, lod, buffer, bufferLen, name);
		}
		else if (ident == MDC_IDENT)
		{
			loaded = R_LoadMDC(mod, lod, buffer, bufferLen, name);
		}

		ri.FS_FreeFile(buffer);

		if (!loaded)
		{
			if (lod == 0)
			{
				goto fail;
			}
			else
			{
				break;
			}
		}
		else
		{
			// make sure the VBO glState entries are save
			R_BindNullVBO();
			R_BindNullIBO();

			mod->numLods++;
			numLoaded++;
			// if we have a valid model and are biased
			// so that we won't see any higher detail ones,
			// stop loading them
			//if ( lod <= r_lodbias->integer ) {
			//break;
			//}
		}
	}

	// make sure the VBO glState entries are save
	R_BindNullVBO();
	R_BindNullIBO();

	if (numLoaded)
	{
		// duplicate into higher lod spots that weren't
		// loaded, in case the user changes r_lodbias on the fly
		for (lod--; lod >= 0; lod--)
		{
			mod->numLods++;
			mod->mdv[lod] = mod->mdv[lod + 1];
		}
		return mod->index;
	}
#ifdef LEGACY_DEBUG
	else
	{
		Ren_Warning("couldn't load '%s'\n", name);
	}
#endif

fail:
	// we still keep the model_t around, so if the model name is asked for
	// again, we won't bother scanning the filesystem
	mod->type = MOD_BAD;

	// make sure the VBO glState entries are save
	R_BindNullVBO();
	R_BindNullIBO();

	return 0;
}
Пример #6
0
/*
=============
RE_StretchRaw

FIXME: not exactly backend
Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle.
Used for cinematics.
=============
*/
void RE_StretchRaw(int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty)
{
	int i, j;
	int start;

	if (!tr.registered)
	{
		return;
	}
	R_IssuePendingRenderCommands();

	// we definately want to sync every frame for the cinematics
	qglFinish();

	start = 0;
	if (r_speeds->integer)
	{
		start = ri.Milliseconds();
	}

	// make sure rows and cols are powers of 2
	for (i = 0 ; (1 << i) < cols ; i++)
	{
	}
	for (j = 0 ; (1 << j) < rows ; j++)
	{
	}
	if ((1 << i) != cols || (1 << j) != rows)
	{
		Ren_Drop("Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows);
	}

	GL_Bind(tr.scratchImage[client]);

	// if the scratchImage isn't in the format we want, specify it as a new texture
	if (cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height)
	{
		tr.scratchImage[client]->width  = tr.scratchImage[client]->uploadWidth = cols;
		tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows;
		qglTexImage2D(GL_TEXTURE_2D, 0, 3, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
		qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	}
	else
	{
		if (dirty)
		{
			// otherwise, just subimage upload it so that drivers can tell we are going to be changing
			// it and don't try and do a texture compression
			qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data);
		}
	}

	if (r_speeds->integer)
	{
		int end = ri.Milliseconds();

		Ren_Print("qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start);
	}

	RB_SetGL2D();

	qglColor3f(tr.identityLight, tr.identityLight, tr.identityLight);

	qglBegin(GL_QUADS);
	qglTexCoord2f(0.5f / cols, 0.5f / rows);
	qglVertex2f(x, y);
	qglTexCoord2f((cols - 0.5f) / cols, 0.5f / rows);
	qglVertex2f(x + w, y);
	qglTexCoord2f((cols - 0.5f) / cols, (rows - 0.5f) / rows);
	qglVertex2f(x + w, y + h);
	qglTexCoord2f(0.5f / cols, (rows - 0.5f) / rows);
	qglVertex2f(x, y + h);
	qglEnd();
}
Пример #7
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);
		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);
}
Пример #8
0
/*
====================
RE_RegisterModel

Loads in a model for the given name

Zero will be returned if the model fails to load.
An entry will be retained for failed models as an
optimization to prevent disk rescanning if they are
asked for again.
====================
*/
qhandle_t RE_RegisterModel( const char *name ) {
	model_t		*mod;
	qhandle_t	hModel;
	qboolean	orgNameFailed = qfalse;
	int			orgLoader = -1;
	int			i;
	char		localName[ MAX_QPATH ];
	const char	*ext;
	char		altName[ MAX_QPATH ];

	if ( !name || !name[0] ) {
		ri.Printf( PRINT_ALL, "RE_RegisterModel: NULL name\n" );
		return 0;
	}

	if ( strlen( name ) >= MAX_QPATH ) {
		ri.Printf( PRINT_ALL, "Model name exceeds MAX_QPATH\n" );
		return 0;
	}

	//
	// search the currently loaded models
	//
	for ( hModel = 1 ; hModel < tr.numModels; hModel++ ) {
		mod = tr.models[hModel];
		if ( !strcmp( mod->name, name ) ) {
			if( mod->type == MOD_BAD ) {
				return 0;
			}
			return hModel;
		}
	}

	// allocate a new model_t

	if ( ( mod = R_AllocModel() ) == NULL ) {
		ri.Printf( PRINT_WARNING, "RE_RegisterModel: R_AllocModel() failed for '%s'\n", name);
		return 0;
	}

	// only set the name after the model has been successfully loaded
	Q_strncpyz( mod->name, name, sizeof( mod->name ) );


	R_IssuePendingRenderCommands();

	mod->type = MOD_BAD;
	mod->numLods = 0;

	//
	// load the files
	//
	Q_strncpyz( localName, name, MAX_QPATH );

	ext = COM_GetExtension( localName );

	if( *ext )
	{
		// Look for the correct loader and use it
		for( i = 0; i < numModelLoaders; i++ )
		{
			if( !Q_stricmp( ext, modelLoaders[ i ].ext ) )
			{
				// Load
				hModel = modelLoaders[ i ].ModelLoader( localName, mod );
				break;
			}
		}

		// A loader was found
		if( i < numModelLoaders )
		{
			if( !hModel )
			{
				// Loader failed, most likely because the file isn't there;
				// try again without the extension
				orgNameFailed = qtrue;
				orgLoader = i;
				COM_StripExtension( name, localName, MAX_QPATH );
			}
			else
			{
				// Something loaded
				return mod->index;
			}
		}
	}

	// Try and find a suitable match using all
	// the model formats supported
	for( i = 0; i < numModelLoaders; i++ )
	{
		if (i == orgLoader)
			continue;

		Com_sprintf( altName, sizeof (altName), "%s.%s", localName, modelLoaders[ i ].ext );

		// Load
		hModel = modelLoaders[ i ].ModelLoader( altName, mod );

		if( hModel )
		{
			if( orgNameFailed )
			{
				ri.Printf( PRINT_DEVELOPER, "WARNING: %s not present, using %s instead\n",
						name, altName );
			}

			break;
		}
	}

	return hModel;
}
Пример #9
0
/**
 * @brief Will be called once for each RE_EndFrame
 */
void RE_BeginFrame()
{
	drawBufferCommand_t *cmd;

	if (!tr.registered)
	{
		return;
	}

	Ren_LogComment("--- RE_BeginFrame ---\n");

	glState.finishCalled = qfalse;

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

	// do overdraw measurement
	if (r_measureOverdraw->integer)
	{
		if (glConfig.stencilBits < 4)
		{
			Ren_Print("Warning: not enough stencil bits to measure overdraw: %d\n", glConfig.stencilBits);
			ri.Cvar_Set("r_measureOverdraw", "0");
		}
		else if (r_shadows->integer == 2)
		{
			Ren_Print("Warning: stencil shadows and overdraw measurement are mutually exclusive\n");
			ri.Cvar_Set("r_measureOverdraw", "0");
		}
		else
		{
			R_IssuePendingRenderCommands();
			glEnable(GL_STENCIL_TEST);
			glStencilMask(~0U);
			GL_ClearStencil(0U);
			glStencilFunc(GL_ALWAYS, 0U, ~0U);
			glStencilOp(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();
			glDisable(GL_STENCIL_TEST);
		}
		r_measureOverdraw->modified = qfalse;
	}

	// 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;
		char s[128];

		R_IssuePendingRenderCommands();

		if ((err = glGetError()) != GL_NO_ERROR)
		{
			switch (err)
			{
			case GL_INVALID_ENUM:
				Q_strcpy(s, "GL_INVALID_ENUM");
				break;
			case GL_INVALID_VALUE:
				Q_strcpy(s, "GL_INVALID_VALUE");
				break;
			case GL_INVALID_OPERATION:
				Q_strcpy(s, "GL_INVALID_OPERATION");
				break;
			case GL_STACK_OVERFLOW:
				Q_strcpy(s, "GL_STACK_OVERFLOW");
				break;
			case GL_STACK_UNDERFLOW:
				Q_strcpy(s, "GL_STACK_UNDERFLOW");
				break;
			case GL_OUT_OF_MEMORY:
				Q_strcpy(s, "GL_OUT_OF_MEMORY");
				break;
			case GL_TABLE_TOO_LARGE:
				Q_strcpy(s, "GL_TABLE_TOO_LARGE");
				break;
			case GL_INVALID_FRAMEBUFFER_OPERATION_EXT:
				Q_strcpy(s, "GL_INVALID_FRAMEBUFFER_OPERATION_EXT");
				break;
			default:
				Com_sprintf(s, sizeof(s), "0x%X", err);
				break;
			}

			//Ren_Fatal( "caught OpenGL error: %s in file %s line %i", s, filename, line);
			Ren_Fatal("RE_BeginFrame() - glGetError() failed (%s)!\n", s);
		}
	}

	// draw buffer stuff
	cmd = (drawBufferCommand_t *)R_GetCommandBuffer(sizeof(*cmd));
	if (!cmd)
	{
		return;
	}

	cmd->commandId = RC_DRAW_BUFFER;

	if (!Q_stricmp(r_drawBuffer->string, "GL_FRONT"))
	{
		cmd->buffer = (int)GL_FRONT;
	}
	else
	{
		cmd->buffer = (int)GL_BACK;
	}
}
Пример #10
0
/*
=============
RE_StretchRaw

FIXME: not exactly backend
Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle.
Used for cinematics.
=============
*/
void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) {
	int			i, j;
	int			start, end;
	vec4_t quadVerts[4];
	vec2_t texCoords[4];

	if ( !tr.registered ) {
		return;
	}
	R_IssuePendingRenderCommands();

	// we definately want to sync every frame for the cinematics
	qglFinish();

	start = 0;
	if ( r_speeds->integer ) {
		start = ri.Milliseconds();
	}

	// make sure rows and cols are powers of 2
	for ( i = 0 ; ( 1 << i ) < cols ; i++ ) {
	}
	for ( j = 0 ; ( 1 << j ) < rows ; j++ ) {
	}
	if ( ( 1 << i ) != cols || ( 1 << j ) != rows) {
		ri.Error (ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows);
	}

	RE_UploadCinematic (w, h, cols, rows, data, client, dirty);

	if ( r_speeds->integer ) {
		end = ri.Milliseconds();
		ri.Printf( PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start );
	}

	// FIXME: HUGE hack
	if (glRefConfig.framebufferObject)
	{
		if (!tr.renderFbo || backEnd.framePostProcessed)
		{
			FBO_Bind(tr.screenScratchFbo);
		}
		else
		{
			FBO_Bind(tr.renderFbo);
		}
	}

	RB_SetGL2D();

	VectorSet4(quadVerts[0], x,     y,     0.0f, 1.0f);
	VectorSet4(quadVerts[1], x + w, y,     0.0f, 1.0f);
	VectorSet4(quadVerts[2], x + w, y + h, 0.0f, 1.0f);
	VectorSet4(quadVerts[3], x,     y + h, 0.0f, 1.0f);

	VectorSet2(texCoords[0], 0.5f / cols,          0.5f / rows);
	VectorSet2(texCoords[1], (cols - 0.5f) / cols, 0.5f / rows);
	VectorSet2(texCoords[2], (cols - 0.5f) / cols, (rows - 0.5f) / rows);
	VectorSet2(texCoords[3], 0.5f / cols,          (rows - 0.5f) / rows);

	GLSL_BindProgram(&tr.textureColorShader);
	
	GLSL_SetUniformMatrix16(&tr.textureColorShader, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
	GLSL_SetUniformVec4(&tr.textureColorShader, UNIFORM_COLOR, colorWhite);

	RB_InstantQuad2(quadVerts, texCoords);
}
Пример #11
0
void R_InitFBOs(void)
{
	int i;
	int width, height;

	Ren_Developer("------- R_InitFBOs -------\n");

	if (!glConfig2.framebufferObjectAvailable)
	{
		return;
	}

	R_CheckDefaultBuffer();

	tr.numFBOs = 0;

	GL_CheckErrors();

	// make sure the render thread is stopped
	R_IssuePendingRenderCommands();

	{
		// forward shading
		if (glConfig2.textureNPOTAvailable)
		{
			width  = glConfig.vidWidth;
			height = glConfig.vidHeight;
		}
		else
		{
			width  = NearestPowerOfTwo(glConfig.vidWidth);
			height = NearestPowerOfTwo(glConfig.vidHeight);
		}

		// deferredRender FBO for the HDR or LDR context
		tr.deferredRenderFBO = R_CreateFBO("_deferredRender", width, height);
		R_BindFBO(tr.deferredRenderFBO);

		if (r_hdrRendering->integer && glConfig2.textureFloatAvailable)
		{
			R_CreateFBOColorBuffer(tr.deferredRenderFBO, GL_RGBA16F_ARB, 0);
		}
		else
		{
			R_CreateFBOColorBuffer(tr.deferredRenderFBO, GL_RGBA, 0);
		}
		R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.deferredRenderFBOImage->texnum, 0);

		R_CreateFBODepthBuffer(tr.deferredRenderFBO, GL_DEPTH_COMPONENT24_ARB);
		R_AttachFBOTextureDepth(tr.depthRenderImage->texnum);

		R_CheckFBO(tr.deferredRenderFBO);
	}

	if (glConfig2.framebufferBlitAvailable)
	{
		if (glConfig2.textureNPOTAvailable)
		{
			width  = glConfig.vidWidth;
			height = glConfig.vidHeight;
		}
		else
		{
			width  = NearestPowerOfTwo(glConfig.vidWidth);
			height = NearestPowerOfTwo(glConfig.vidHeight);
		}

		tr.occlusionRenderFBO = R_CreateFBO("_occlusionRender", width, height);
		R_BindFBO(tr.occlusionRenderFBO);

#if 0
		if (glConfig2.framebufferPackedDepthStencilAvailable)
		{
			//R_CreateFBOColorBuffer(tr.occlusionRenderFBO, GL_ALPHA32F_ARB, 0);
			R_CreateFBOPackedDepthStencilBuffer(tr.occlusionRenderFBO, GL_DEPTH24_STENCIL8);
		}
		else
		{
			//R_CreateFBOColorBuffer(tr.occlusionRenderFBO, GL_RGBA, 0);
			R_CreateFBODepthBuffer(tr.occlusionRenderFBO, GL_DEPTH_COMPONENT24);
		}
#else
		R_CreateFBODepthBuffer(tr.occlusionRenderFBO, GL_DEPTH_COMPONENT24);
#endif

		R_CreateFBOColorBuffer(tr.occlusionRenderFBO, GL_RGBA, 0);
		R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.occlusionRenderFBOImage->texnum, 0);

		R_CheckFBO(tr.occlusionRenderFBO);
	}

	if (r_shadows->integer >= SHADOWING_ESM16 && glConfig2.textureFloatAvailable)
	{
		// shadowMap FBOs for shadow mapping offscreen rendering
		for (i = 0; i < MAX_SHADOWMAPS; i++)
		{
			width = height = shadowMapResolutions[i];

			tr.shadowMapFBO[i] = R_CreateFBO(va("_shadowMap%d", i), width, height);
			R_BindFBO(tr.shadowMapFBO[i]);


			if (r_shadows->integer == SHADOWING_ESM32)
			{
				R_CreateFBOColorBuffer(tr.shadowMapFBO[i], GL_ALPHA32F_ARB, 0);
			}
			else if (r_shadows->integer == SHADOWING_VSM32)
			{
				R_CreateFBOColorBuffer(tr.shadowMapFBO[i], GL_LUMINANCE_ALPHA32F_ARB, 0);
			}
			else if (r_shadows->integer == SHADOWING_EVSM32)
			{
				if (r_evsmPostProcess->integer)
				{
					R_CreateFBOColorBuffer(tr.shadowMapFBO[i], GL_ALPHA32F_ARB, 0);
				}
				else
				{
					R_CreateFBOColorBuffer(tr.shadowMapFBO[i], GL_RGBA32F_ARB, 0);
				}
			}
			else
			{
				R_CreateFBOColorBuffer(tr.shadowMapFBO[i], GL_RGBA16F_ARB, 0);
			}

			R_CreateFBODepthBuffer(tr.shadowMapFBO[i], GL_DEPTH_COMPONENT24_ARB);

			R_CheckFBO(tr.shadowMapFBO[i]);
		}

		// sun requires different resolutions
		for (i = 0; i < MAX_SHADOWMAPS; i++)
		{
			width = height = sunShadowMapResolutions[i];

			tr.sunShadowMapFBO[i] = R_CreateFBO(va("_sunShadowMap%d", i), width, height);
			R_BindFBO(tr.sunShadowMapFBO[i]);

			if (r_shadows->integer == SHADOWING_ESM32)
			{
				R_CreateFBOColorBuffer(tr.sunShadowMapFBO[i], GL_ALPHA32F_ARB, 0);
			}
			else if (r_shadows->integer == SHADOWING_VSM32)
			{
				R_CreateFBOColorBuffer(tr.sunShadowMapFBO[i], GL_LUMINANCE_ALPHA32F_ARB, 0);
			}
			else if (r_shadows->integer == SHADOWING_EVSM32)
			{
				if (!r_evsmPostProcess->integer)
				{
					R_CreateFBOColorBuffer(tr.sunShadowMapFBO[i], GL_RGBA32F_ARB, 0);
				}
			}
			else
			{
				R_CreateFBOColorBuffer(tr.sunShadowMapFBO[i], GL_RGBA16F_ARB, 0);
			}

			R_CreateFBODepthBuffer(tr.sunShadowMapFBO[i], GL_DEPTH_COMPONENT24_ARB);

			if (r_shadows->integer == SHADOWING_EVSM32 && r_evsmPostProcess->integer)
			{
				R_AttachFBOTextureDepth(tr.sunShadowMapFBOImage[i]->texnum);

				/*
				Since we don't have a color attachment the framebuffer will be considered incomplete.
				Consequently, we must inform the driver that we do not wish to render to the color buffer.
				We do this with a call to set the draw-buffer and read-buffer to GL_NONE:
				*/
				glDrawBuffer(GL_NONE);
				glReadBuffer(GL_NONE);
			}

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

	{
		if (glConfig2.textureNPOTAvailable)
		{
			width  = glConfig.vidWidth;
			height = glConfig.vidHeight;
		}
		else
		{
			width  = NearestPowerOfTwo(glConfig.vidWidth);
			height = NearestPowerOfTwo(glConfig.vidHeight);
		}

		// portalRender FBO for portals, mirrors, water, cameras et cetera
		tr.portalRenderFBO = R_CreateFBO("_portalRender", width, height);
		R_BindFBO(tr.portalRenderFBO);

		if (r_hdrRendering->integer && glConfig2.textureFloatAvailable)
		{
			R_CreateFBOColorBuffer(tr.portalRenderFBO, GL_RGBA16F_ARB, 0);
		}
		else
		{
			R_CreateFBOColorBuffer(tr.portalRenderFBO, GL_RGBA, 0);
		}
		R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.portalRenderImage->texnum, 0);

		R_CheckFBO(tr.portalRenderFBO);
	}


	{
		if (glConfig2.textureNPOTAvailable)
		{
			width  = glConfig.vidWidth * 0.25f;
			height = glConfig.vidHeight * 0.25f;
		}
		else
		{
			width  = NearestPowerOfTwo(glConfig.vidWidth * 0.25f);
			height = NearestPowerOfTwo(glConfig.vidHeight * 0.25f);
		}

		tr.downScaleFBO_quarter = R_CreateFBO("_downScale_quarter", width, height);
		R_BindFBO(tr.downScaleFBO_quarter);
		if (r_hdrRendering->integer && glConfig2.textureFloatAvailable)
		{
			R_CreateFBOColorBuffer(tr.downScaleFBO_quarter, GL_RGBA16F_ARB, 0);
		}
		else
		{
			R_CreateFBOColorBuffer(tr.downScaleFBO_quarter, GL_RGBA, 0);
		}
		R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.downScaleFBOImage_quarter->texnum, 0);
		R_CheckFBO(tr.downScaleFBO_quarter);


		tr.downScaleFBO_64x64 = R_CreateFBO("_downScale_64x64", 64, 64);
		R_BindFBO(tr.downScaleFBO_64x64);
		if (r_hdrRendering->integer && glConfig2.textureFloatAvailable)
		{
			R_CreateFBOColorBuffer(tr.downScaleFBO_64x64, GL_RGBA16F_ARB, 0);
		}
		else
		{
			R_CreateFBOColorBuffer(tr.downScaleFBO_64x64, GL_RGBA, 0);
		}
		R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.downScaleFBOImage_64x64->texnum, 0);
		R_CheckFBO(tr.downScaleFBO_64x64);

#if 0
		tr.downScaleFBO_16x16 = R_CreateFBO("_downScale_16x16", 16, 16);
		R_BindFBO(tr.downScaleFBO_16x16);
		if (r_hdrRendering->integer && glConfig2.textureFloatAvailable)
		{
			R_CreateFBOColorBuffer(tr.downScaleFBO_16x16, GL_RGBA16F_ARB, 0);
		}
		else
		{
			R_CreateFBOColorBuffer(tr.downScaleFBO_16x16, GL_RGBA, 0);
		}
		R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.downScaleFBOImage_16x16->texnum, 0);
		R_CheckFBO(tr.downScaleFBO_16x16);


		tr.downScaleFBO_4x4 = R_CreateFBO("_downScale_4x4", 4, 4);
		R_BindFBO(tr.downScaleFBO_4x4);
		if (r_hdrRendering->integer && glConfig2.textureFloatAvailable)
		{
			R_CreateFBOColorBuffer(tr.downScaleFBO_4x4, GL_RGBA16F_ARB, 0);
		}
		else
		{
			R_CreateFBOColorBuffer(tr.downScaleFBO_4x4, GL_RGBA, 0);
		}
		R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.downScaleFBOImage_4x4->texnum, 0);
		R_CheckFBO(tr.downScaleFBO_4x4);


		tr.downScaleFBO_1x1 = R_CreateFBO("_downScale_1x1", 1, 1);
		R_BindFBO(tr.downScaleFBO_1x1);
		if (r_hdrRendering->integer && glConfig2.textureFloatAvailable)
		{
			R_CreateFBOColorBuffer(tr.downScaleFBO_1x1, GL_RGBA16F_ARB, 0);
		}
		else
		{
			R_CreateFBOColorBuffer(tr.downScaleFBO_1x1, GL_RGBA, 0);
		}
		R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.downScaleFBOImage_1x1->texnum, 0);
		R_CheckFBO(tr.downScaleFBO_1x1);
#endif

		if (glConfig2.textureNPOTAvailable)
		{
			width  = glConfig.vidWidth * 0.25f;
			height = glConfig.vidHeight * 0.25f;
		}
		else
		{
			width  = NearestPowerOfTwo(glConfig.vidWidth * 0.25f);
			height = NearestPowerOfTwo(glConfig.vidHeight * 0.25f);
		}

		tr.contrastRenderFBO = R_CreateFBO("_contrastRender", width, height);
		R_BindFBO(tr.contrastRenderFBO);

		if (r_hdrRendering->integer && glConfig2.textureFloatAvailable)
		{
			R_CreateFBOColorBuffer(tr.contrastRenderFBO, GL_RGBA16F_ARB, 0);
		}
		else
		{
			R_CreateFBOColorBuffer(tr.contrastRenderFBO, GL_RGBA, 0);
		}
		R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.contrastRenderFBOImage->texnum, 0);

		R_CheckFBO(tr.contrastRenderFBO);


		for (i = 0; i < 2; i++)
		{
			tr.bloomRenderFBO[i] = R_CreateFBO(va("_bloomRender%d", i), width, height);
			R_BindFBO(tr.bloomRenderFBO[i]);

			if (r_hdrRendering->integer && glConfig2.textureFloatAvailable)
			{
				R_CreateFBOColorBuffer(tr.bloomRenderFBO[i], GL_RGBA16F_ARB, 0);
			}
			else
			{
				R_CreateFBOColorBuffer(tr.bloomRenderFBO[i], GL_RGBA, 0);
			}
			R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.bloomRenderFBOImage[i]->texnum, 0);

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

	GL_CheckErrors();

	R_BindNullFBO();
}
Пример #12
0
void GLSL_InitGPUShaders(void)
{
	int             startTime, endTime;
	int i;
	char extradefines[1024];
	int attribs;
	int numGenShaders = 0, numLightShaders = 0, numEtcShaders = 0;

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

	R_IssuePendingRenderCommands();

	startTime = ri.Milliseconds();

	for (i = 0; i < GENERICDEF_COUNT; i++)
	{	
		attribs = ATTR_POSITION | ATTR_TEXCOORD | ATTR_LIGHTCOORD | ATTR_NORMAL | ATTR_COLOR;
		extradefines[0] = '\0';

		if (i & GENERICDEF_USE_DEFORM_VERTEXES)
			Q_strcat(extradefines, 1024, "#define USE_DEFORM_VERTEXES\n");

		if (i & GENERICDEF_USE_TCGEN_AND_TCMOD)
		{
			Q_strcat(extradefines, 1024, "#define USE_TCGEN\n");
			Q_strcat(extradefines, 1024, "#define USE_TCMOD\n");
		}

		if (i & GENERICDEF_USE_VERTEX_ANIMATION)
		{
			Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n");
			attribs |= ATTR_POSITION2 | ATTR_NORMAL2;
		}

		if (i & GENERICDEF_USE_FOG)
			Q_strcat(extradefines, 1024, "#define USE_FOG\n");

		if (i & GENERICDEF_USE_RGBAGEN)
			Q_strcat(extradefines, 1024, "#define USE_RGBAGEN\n");

		if (i & GENERICDEF_USE_LIGHTMAP)
			Q_strcat(extradefines, 1024, "#define USE_LIGHTMAP\n");

		if (r_hdr->integer && !glRefConfig.floatLightmap)
			Q_strcat(extradefines, 1024, "#define RGBM_LIGHTMAP\n");

		if (!GLSL_InitGPUShader(&tr.genericShader[i], "generic", attribs, qtrue, extradefines, qtrue, fallbackShader_generic_vp, fallbackShader_generic_fp))
		{
			ri.Error(ERR_FATAL, "Could not load generic shader!");
		}

		GLSL_InitUniforms(&tr.genericShader[i]);

		qglUseProgramObjectARB(tr.genericShader[i].program);
		GLSL_SetUniformInt(&tr.genericShader[i], UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP);
		GLSL_SetUniformInt(&tr.genericShader[i], UNIFORM_LIGHTMAP,   TB_LIGHTMAP);
		qglUseProgramObjectARB(0);

		GLSL_FinishGPUShader(&tr.genericShader[i]);

		numGenShaders++;
	}


	attribs = ATTR_POSITION | ATTR_TEXCOORD;

	if (!GLSL_InitGPUShader(&tr.textureColorShader, "texturecolor", attribs, qtrue, NULL, qfalse, fallbackShader_texturecolor_vp, fallbackShader_texturecolor_fp))
	{
		ri.Error(ERR_FATAL, "Could not load texturecolor shader!");
	}
	
	GLSL_InitUniforms(&tr.textureColorShader);

	qglUseProgramObjectARB(tr.textureColorShader.program);
	GLSL_SetUniformInt(&tr.textureColorShader, UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP);
	qglUseProgramObjectARB(0);

	GLSL_FinishGPUShader(&tr.textureColorShader);

	numEtcShaders++;

	for (i = 0; i < FOGDEF_COUNT; i++)
	{
		attribs = ATTR_POSITION | ATTR_POSITION2 | ATTR_NORMAL | ATTR_NORMAL2 | ATTR_TEXCOORD;
		extradefines[0] = '\0';

		if (i & FOGDEF_USE_DEFORM_VERTEXES)
			Q_strcat(extradefines, 1024, "#define USE_DEFORM_VERTEXES\n");

		if (i & FOGDEF_USE_VERTEX_ANIMATION)
			Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n");

		if (!GLSL_InitGPUShader(&tr.fogShader[i], "fogpass", attribs, qtrue, extradefines, qtrue, fallbackShader_fogpass_vp, fallbackShader_fogpass_fp))
		{
			ri.Error(ERR_FATAL, "Could not load fogpass shader!");
		}

		GLSL_InitUniforms(&tr.fogShader[i]);
		GLSL_FinishGPUShader(&tr.fogShader[i]);

		numEtcShaders++;
	}


	for (i = 0; i < DLIGHTDEF_COUNT; i++)
	{
		attribs = ATTR_POSITION | ATTR_NORMAL | ATTR_TEXCOORD;
		extradefines[0] = '\0';

		if (i & DLIGHTDEF_USE_DEFORM_VERTEXES)
		{
			Q_strcat(extradefines, 1024, "#define USE_DEFORM_VERTEXES\n");
		}

		if (!GLSL_InitGPUShader(&tr.dlightShader[i], "dlight", attribs, qtrue, extradefines, qtrue, fallbackShader_dlight_vp, fallbackShader_dlight_fp))
		{
			ri.Error(ERR_FATAL, "Could not load dlight shader!");
		}

		GLSL_InitUniforms(&tr.dlightShader[i]);
		
		qglUseProgramObjectARB(tr.dlightShader[i].program);
		GLSL_SetUniformInt(&tr.dlightShader[i], UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP);
		qglUseProgramObjectARB(0);

		GLSL_FinishGPUShader(&tr.dlightShader[i]);

		numEtcShaders++;
	}


	for (i = 0; i < LIGHTDEF_COUNT; i++)
	{
		int lightType = i & LIGHTDEF_LIGHTTYPE_MASK;
		qboolean fastLight = !(r_normalMapping->integer || r_specularMapping->integer);

		// skip impossible combos
		if ((i & LIGHTDEF_USE_PARALLAXMAP) && !r_parallaxMapping->integer)
			continue;

		if (!lightType && (i & LIGHTDEF_USE_PARALLAXMAP))
			continue;

		if (!lightType && (i & LIGHTDEF_USE_SHADOWMAP))
			continue;

		attribs = ATTR_POSITION | ATTR_TEXCOORD | ATTR_COLOR | ATTR_NORMAL;

		extradefines[0] = '\0';

		if (r_deluxeSpecular->value > 0.000001f)
			Q_strcat(extradefines, 1024, va("#define r_deluxeSpecular %f\n", r_deluxeSpecular->value));

		if (r_specularIsMetallic->value)
			Q_strcat(extradefines, 1024, "#define SPECULAR_IS_METALLIC\n");

		if (r_dlightMode->integer >= 2)
			Q_strcat(extradefines, 1024, "#define USE_SHADOWMAP\n");

		if (1)
			Q_strcat(extradefines, 1024, "#define SWIZZLE_NORMALMAP\n");

		if (r_hdr->integer && !glRefConfig.floatLightmap)
			Q_strcat(extradefines, 1024, "#define RGBM_LIGHTMAP\n");

		if (lightType)
		{
			Q_strcat(extradefines, 1024, "#define USE_LIGHT\n");

			if (fastLight)
				Q_strcat(extradefines, 1024, "#define USE_FAST_LIGHT\n");

			switch (lightType)
			{
				case LIGHTDEF_USE_LIGHTMAP:
					Q_strcat(extradefines, 1024, "#define USE_LIGHTMAP\n");
					if (r_deluxeMapping->integer && !fastLight)
						Q_strcat(extradefines, 1024, "#define USE_DELUXEMAP\n");
					attribs |= ATTR_LIGHTCOORD | ATTR_LIGHTDIRECTION;
					break;
				case LIGHTDEF_USE_LIGHT_VECTOR:
					Q_strcat(extradefines, 1024, "#define USE_LIGHT_VECTOR\n");
					break;
				case LIGHTDEF_USE_LIGHT_VERTEX:
					Q_strcat(extradefines, 1024, "#define USE_LIGHT_VERTEX\n");
					attribs |= ATTR_LIGHTDIRECTION;
					break;
				default:
					break;
			}

			if (r_normalMapping->integer)
			{
				Q_strcat(extradefines, 1024, "#define USE_NORMALMAP\n");

				if (r_normalMapping->integer == 2)
					Q_strcat(extradefines, 1024, "#define USE_OREN_NAYAR\n");

				if (r_normalMapping->integer == 3)
					Q_strcat(extradefines, 1024, "#define USE_TRIACE_OREN_NAYAR\n");

#ifdef USE_VERT_TANGENT_SPACE
				Q_strcat(extradefines, 1024, "#define USE_VERT_TANGENT_SPACE\n");
				attribs |= ATTR_TANGENT;
#endif

				if ((i & LIGHTDEF_USE_PARALLAXMAP) && !(i & LIGHTDEF_ENTITY) && r_parallaxMapping->integer)
					Q_strcat(extradefines, 1024, "#define USE_PARALLAXMAP\n");
			}

			if (r_specularMapping->integer)
			{
				Q_strcat(extradefines, 1024, "#define USE_SPECULARMAP\n");

				switch (r_specularMapping->integer)
				{
					case 1:
					default:
						Q_strcat(extradefines, 1024, "#define USE_BLINN\n");
						break;

					case 2:
						Q_strcat(extradefines, 1024, "#define USE_BLINN_FRESNEL\n");
						break;

					case 3:
						Q_strcat(extradefines, 1024, "#define USE_MCAULEY\n");
						break;

					case 4:
						Q_strcat(extradefines, 1024, "#define USE_GOTANDA\n");
						break;

					case 5:
						Q_strcat(extradefines, 1024, "#define USE_LAZAROV\n");
						break;
				}
			}

			if (r_cubeMapping->integer)
				Q_strcat(extradefines, 1024, "#define USE_CUBEMAP\n");
		}

		if (i & LIGHTDEF_USE_SHADOWMAP)
		{
			Q_strcat(extradefines, 1024, "#define USE_SHADOWMAP\n");

			if (r_sunlightMode->integer == 1)
				Q_strcat(extradefines, 1024, "#define SHADOWMAP_MODULATE\n");
			else if (r_sunlightMode->integer == 2)
				Q_strcat(extradefines, 1024, "#define USE_PRIMARY_LIGHT\n");
		}

		if (i & LIGHTDEF_USE_TCGEN_AND_TCMOD)
		{
			Q_strcat(extradefines, 1024, "#define USE_TCGEN\n");
			Q_strcat(extradefines, 1024, "#define USE_TCMOD\n");
		}

		if (i & LIGHTDEF_ENTITY)
		{
			Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n#define USE_MODELMATRIX\n");
			attribs |= ATTR_POSITION2 | ATTR_NORMAL2;

#ifdef USE_VERT_TANGENT_SPACE
			if (r_normalMapping->integer)
			{
				attribs |= ATTR_TANGENT2;
			}
#endif
		}

		if (!GLSL_InitGPUShader(&tr.lightallShader[i], "lightall", attribs, qtrue, extradefines, qtrue, fallbackShader_lightall_vp, fallbackShader_lightall_fp))
		{
			ri.Error(ERR_FATAL, "Could not load lightall shader!");
		}

		GLSL_InitUniforms(&tr.lightallShader[i]);

		qglUseProgramObjectARB(tr.lightallShader[i].program);
		GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_DIFFUSEMAP,  TB_DIFFUSEMAP);
		GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_LIGHTMAP,    TB_LIGHTMAP);
		GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_NORMALMAP,   TB_NORMALMAP);
		GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_DELUXEMAP,   TB_DELUXEMAP);
		GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_SPECULARMAP, TB_SPECULARMAP);
		GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_SHADOWMAP,   TB_SHADOWMAP);
		GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_CUBEMAP,     TB_CUBEMAP);
		qglUseProgramObjectARB(0);

		GLSL_FinishGPUShader(&tr.lightallShader[i]);

		numLightShaders++;
	}

	attribs = ATTR_POSITION | ATTR_POSITION2 | ATTR_NORMAL | ATTR_NORMAL2 | ATTR_TEXCOORD;

	extradefines[0] = '\0';

	if (!GLSL_InitGPUShader(&tr.shadowmapShader, "shadowfill", attribs, qtrue, extradefines, qtrue, fallbackShader_shadowfill_vp, fallbackShader_shadowfill_fp))
	{
		ri.Error(ERR_FATAL, "Could not load shadowfill shader!");
	}

	GLSL_InitUniforms(&tr.shadowmapShader);
	GLSL_FinishGPUShader(&tr.shadowmapShader);

	numEtcShaders++;

	attribs = ATTR_POSITION | ATTR_NORMAL;
	extradefines[0] = '\0';

	Q_strcat(extradefines, 1024, "#define USE_PCF\n#define USE_DISCARD\n");

	if (!GLSL_InitGPUShader(&tr.pshadowShader, "pshadow", attribs, qtrue, extradefines, qtrue, fallbackShader_pshadow_vp, fallbackShader_pshadow_fp))
	{
		ri.Error(ERR_FATAL, "Could not load pshadow shader!");
	}
	
	GLSL_InitUniforms(&tr.pshadowShader);

	qglUseProgramObjectARB(tr.pshadowShader.program);
	GLSL_SetUniformInt(&tr.pshadowShader, UNIFORM_SHADOWMAP, TB_DIFFUSEMAP);
	qglUseProgramObjectARB(0);

	GLSL_FinishGPUShader(&tr.pshadowShader);

	numEtcShaders++;


	attribs = ATTR_POSITION | ATTR_TEXCOORD;
	extradefines[0] = '\0';

	if (!GLSL_InitGPUShader(&tr.down4xShader, "down4x", attribs, qtrue, extradefines, qtrue, fallbackShader_down4x_vp, fallbackShader_down4x_fp))
	{
		ri.Error(ERR_FATAL, "Could not load down4x shader!");
	}
	
	GLSL_InitUniforms(&tr.down4xShader);

	qglUseProgramObjectARB(tr.down4xShader.program);
	GLSL_SetUniformInt(&tr.down4xShader, UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP);
	qglUseProgramObjectARB(0);

	GLSL_FinishGPUShader(&tr.down4xShader);

	numEtcShaders++;


	attribs = ATTR_POSITION | ATTR_TEXCOORD;
	extradefines[0] = '\0';

	if (!GLSL_InitGPUShader(&tr.bokehShader, "bokeh", attribs, qtrue, extradefines, qtrue, fallbackShader_bokeh_vp, fallbackShader_bokeh_fp))
	{
		ri.Error(ERR_FATAL, "Could not load bokeh shader!");
	}

	GLSL_InitUniforms(&tr.bokehShader);

	qglUseProgramObjectARB(tr.bokehShader.program);
	GLSL_SetUniformInt(&tr.bokehShader, UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP);
	qglUseProgramObjectARB(0);

	GLSL_FinishGPUShader(&tr.bokehShader);

	numEtcShaders++;


	attribs = ATTR_POSITION | ATTR_TEXCOORD;
	extradefines[0] = '\0';

	if (!GLSL_InitGPUShader(&tr.tonemapShader, "tonemap", attribs, qtrue, extradefines, qtrue, fallbackShader_tonemap_vp, fallbackShader_tonemap_fp))
	{
		ri.Error(ERR_FATAL, "Could not load tonemap shader!");
	}

	GLSL_InitUniforms(&tr.tonemapShader);

	qglUseProgramObjectARB(tr.tonemapShader.program);
	GLSL_SetUniformInt(&tr.tonemapShader, UNIFORM_TEXTUREMAP, TB_COLORMAP);
	GLSL_SetUniformInt(&tr.tonemapShader, UNIFORM_LEVELSMAP,  TB_LEVELSMAP);
	qglUseProgramObjectARB(0);

	GLSL_FinishGPUShader(&tr.tonemapShader);

	numEtcShaders++;


	for (i = 0; i < 2; i++)
	{
		attribs = ATTR_POSITION | ATTR_TEXCOORD;
		extradefines[0] = '\0';

		if (!i)
			Q_strcat(extradefines, 1024, "#define FIRST_PASS\n");

		if (!GLSL_InitGPUShader(&tr.calclevels4xShader[i], "calclevels4x", attribs, qtrue, extradefines, qtrue, fallbackShader_calclevels4x_vp, fallbackShader_calclevels4x_fp))
		{
			ri.Error(ERR_FATAL, "Could not load calclevels4x shader!");
		}

		GLSL_InitUniforms(&tr.calclevels4xShader[i]);

		qglUseProgramObjectARB(tr.calclevels4xShader[i].program);
		GLSL_SetUniformInt(&tr.calclevels4xShader[i], UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP);
		qglUseProgramObjectARB(0);

		GLSL_FinishGPUShader(&tr.calclevels4xShader[i]);

		numEtcShaders++;		
	}


	attribs = ATTR_POSITION | ATTR_TEXCOORD;
	extradefines[0] = '\0';

	if (r_shadowFilter->integer >= 1)
		Q_strcat(extradefines, 1024, "#define USE_SHADOW_FILTER\n");

	if (r_shadowFilter->integer >= 2)
		Q_strcat(extradefines, 1024, "#define USE_SHADOW_FILTER2\n");

	if (r_shadowCascadeZFar->integer != 0)
		Q_strcat(extradefines, 1024, "#define USE_SHADOW_CASCADE\n");

	Q_strcat(extradefines, 1024, va("#define r_shadowMapSize %f\n", r_shadowMapSize->value));
	Q_strcat(extradefines, 1024, va("#define r_shadowCascadeZFar %f\n", r_shadowCascadeZFar->value));


	if (!GLSL_InitGPUShader(&tr.shadowmaskShader, "shadowmask", attribs, qtrue, extradefines, qtrue, fallbackShader_shadowmask_vp, fallbackShader_shadowmask_fp))
	{
		ri.Error(ERR_FATAL, "Could not load shadowmask shader!");
	}
	
	GLSL_InitUniforms(&tr.shadowmaskShader);

	qglUseProgramObjectARB(tr.shadowmaskShader.program);
	GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SCREENDEPTHMAP, TB_COLORMAP);
	GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP,  TB_SHADOWMAP);
	GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP2, TB_SHADOWMAP2);
	GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP3, TB_SHADOWMAP3);
	GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP4, TB_SHADOWMAP4);
	qglUseProgramObjectARB(0);

	GLSL_FinishGPUShader(&tr.shadowmaskShader);

	numEtcShaders++;


	attribs = ATTR_POSITION | ATTR_TEXCOORD;
	extradefines[0] = '\0';

	if (!GLSL_InitGPUShader(&tr.ssaoShader, "ssao", attribs, qtrue, extradefines, qtrue, fallbackShader_ssao_vp, fallbackShader_ssao_fp))
	{
		ri.Error(ERR_FATAL, "Could not load ssao shader!");
	}

	GLSL_InitUniforms(&tr.ssaoShader);

	qglUseProgramObjectARB(tr.ssaoShader.program);
	GLSL_SetUniformInt(&tr.ssaoShader, UNIFORM_SCREENDEPTHMAP, TB_COLORMAP);
	qglUseProgramObjectARB(0);

	GLSL_FinishGPUShader(&tr.ssaoShader);

	numEtcShaders++;


	for (i = 0; i < 2; i++)
	{
		attribs = ATTR_POSITION | ATTR_TEXCOORD;
		extradefines[0] = '\0';

		if (i & 1)
			Q_strcat(extradefines, 1024, "#define USE_VERTICAL_BLUR\n");
		else
			Q_strcat(extradefines, 1024, "#define USE_HORIZONTAL_BLUR\n");


		if (!GLSL_InitGPUShader(&tr.depthBlurShader[i], "depthBlur", attribs, qtrue, extradefines, qtrue, fallbackShader_depthblur_vp, fallbackShader_depthblur_fp))
		{
			ri.Error(ERR_FATAL, "Could not load depthBlur shader!");
		}
		
		GLSL_InitUniforms(&tr.depthBlurShader[i]);

		qglUseProgramObjectARB(tr.depthBlurShader[i].program);
		GLSL_SetUniformInt(&tr.depthBlurShader[i], UNIFORM_SCREENIMAGEMAP, TB_COLORMAP);
		GLSL_SetUniformInt(&tr.depthBlurShader[i], UNIFORM_SCREENDEPTHMAP, TB_LIGHTMAP);
		qglUseProgramObjectARB(0);

		GLSL_FinishGPUShader(&tr.depthBlurShader[i]);

		numEtcShaders++;
	}

#if 0
	attribs = ATTR_POSITION | ATTR_TEXCOORD;
	extradefines[0] = '\0';

	if (!GLSL_InitGPUShader(&tr.testcubeShader, "testcube", attribs, qtrue, extradefines, qtrue, NULL, NULL))
	{
		ri.Error(ERR_FATAL, "Could not load testcube shader!");
	}

	GLSL_InitUniforms(&tr.testcubeShader);

	qglUseProgramObjectARB(tr.testcubeShader.program);
	GLSL_SetUniformInt(&tr.testcubeShader, UNIFORM_TEXTUREMAP, TB_COLORMAP);
	qglUseProgramObjectARB(0);

	GLSL_FinishGPUShader(&tr.testcubeShader);

	numEtcShaders++;
#endif


	endTime = ri.Milliseconds();

	ri.Printf(PRINT_ALL, "loaded %i GLSL shaders (%i gen %i light %i etc) in %5.2f seconds\n", 
		numGenShaders + numLightShaders + numEtcShaders, numGenShaders, numLightShaders, 
		numEtcShaders, (endTime - startTime) / 1000.0);
}
Пример #13
0
qhandle_t RE_RegisterSkin(const char *name)
{
	qhandle_t     hSkin;
	skin_t        *skin;
	skinSurface_t *surf;
	skinModel_t   *model;
	char          *text, *text_p;
	char          *token;
	char          surfName[MAX_QPATH];

	if (!name || !name[0])
	{
		Ren_Print("Empty name passed to RE_RegisterSkin\n");
		return 0;
	}

	if (strlen(name) >= MAX_QPATH)
	{
		Ren_Print("Skin name exceeds MAX_QPATH\n");
		return 0;
	}

	// see if the skin is already loaded
	for (hSkin = 1; hSkin < tr.numSkins; hSkin++)
	{
		skin = tr.skins[hSkin];
		if (!Q_stricmp(skin->name, name))
		{
			if (skin->numSurfaces == 0)
			{
				return 0;       // default skin
			}
			return hSkin;
		}
	}

	// allocate a new skin
	if (tr.numSkins == MAX_SKINS)
	{
		Ren_Warning("WARNING: RE_RegisterSkin( '%s' ) MAX_SKINS hit\n", name);
		return 0;
	}

	// - moved things around slightly to fix the problem where you restart
	// a map that has ai characters who had invalid skin names entered
	// in thier "skin" or "head" field

	// make sure the render thread is stopped
	R_IssuePendingRenderCommands();

#if 0
	// If not a .skin file, load as a single shader
	if (strcmp(name + strlen(name) - 5, ".skin"))
	{
		skin->numSurfaces         = 1;
		skin->surfaces[0]         = ri.Hunk_Alloc(sizeof(skin->surfaces[0]), h_low);
		skin->surfaces[0]->shader = R_FindShader(name, SHADER_3D_DYNAMIC, qtrue);
		return hSkin;
	}
#endif

	// load and parse the skin file
	ri.FS_ReadFile(name, (void **)&text);
	if (!text)
	{
		return 0;
	}

	tr.numSkins++;
	skin            = (skin_t *)ri.Hunk_Alloc(sizeof(skin_t), h_low);
	tr.skins[hSkin] = skin;
	Q_strncpyz(skin->name, name, sizeof(skin->name));
	skin->numSurfaces = 0;
	skin->numModels   = 0;

	text_p = text;
	while (text_p && *text_p)
	{
		// get surface name
		token = CommaParse(&text_p);
		Q_strncpyz(surfName, token, sizeof(surfName));

		if (!token[0])
		{
			break;
		}
		// lowercase the surface name so skin compares are faster
		Q_strlwr(surfName);

		if (*text_p == ',')
		{
			text_p++;
		}

		if (!Q_stricmpn(token, "tag_", 4))
		{
			continue;
		}

		if (!Q_stricmpn(token, "md3_", 4))
		{
			if (skin->numModels >= MAX_PART_MODELS)
			{
				Ren_Warning("WARNING: Ignoring models in '%s', the max is %d!\n", name, MAX_PART_MODELS);
				break;
			}

			// this is specifying a model
			model = skin->models[skin->numModels] = (skinModel_t *)ri.Hunk_Alloc(sizeof(*skin->models[0]), h_low);
			Q_strncpyz(model->type, token, sizeof(model->type));
			model->hash = Com_HashKey(model->type, sizeof(model->type));

			// get the model name
			token = CommaParse(&text_p);

			Q_strncpyz(model->model, token, sizeof(model->model));

			skin->numModels++;
			continue;
		}

		// parse the shader name
		token = CommaParse(&text_p);

		if (skin->numSurfaces >= MD3_MAX_SURFACES)
		{
			Ren_Warning("WARNING: Ignoring surfaces in '%s', the max is %d surfaces!\n", name, MD3_MAX_SURFACES);
			break;
		}

		surf = skin->surfaces[skin->numSurfaces] = (skinSurface_t *)ri.Hunk_Alloc(sizeof(*skin->surfaces[0]), h_low);
		Q_strncpyz(surf->name, surfName, sizeof(surf->name));

		// FIXME: bspSurface not not have ::hash yet
		//surf->hash = Com_HashKey(surf->name, sizeof(surf->name));
		surf->shader = R_FindShader(token, SHADER_3D_DYNAMIC, qtrue);
		skin->numSurfaces++;
	}

	ri.FS_FreeFile(text);

	// never let a skin have 0 shaders
	if (skin->numSurfaces == 0)
	{
		return 0;               // use default skin
	}

	return hSkin;
}