Ejemplo n.º 1
0
/*
============
R_CreateVBO2
============
*/
VBO_t *R_CreateVBO2(const char *name, int numVertexes, srfVert_t *verts, unsigned int stateBits, vboUsage_t usage)
{
	VBO_t *vbo;
	int   i, j;

	byte *data;
	int  dataSize;
	int  dataOfs;

	int glUsage;

	switch (usage)
	{
	case VBO_USAGE_STATIC:
		glUsage = GL_STATIC_DRAW;
		break;

	case VBO_USAGE_DYNAMIC:
		glUsage = GL_DYNAMIC_DRAW;
		break;

	default:
		glUsage = 0;
		Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage);
	}

	if (!numVertexes)
	{
		return NULL;
	}

	if (strlen(name) >= MAX_QPATH)
	{
		ri.Error(ERR_DROP, "R_CreateVBO2: \"%s\" is too long\n", name);
	}

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

	vbo = (VBO_t *)ri.Hunk_Alloc(sizeof(*vbo), h_low);
	Com_AddToGrowList(&tr.vbos, vbo);

	Q_strncpyz(vbo->name, name, sizeof(vbo->name));

	vbo->ofsXYZ             = 0;
	vbo->ofsTexCoords       = 0;
	vbo->ofsLightCoords     = 0;
	vbo->ofsBinormals       = 0;
	vbo->ofsTangents        = 0;
	vbo->ofsNormals         = 0;
	vbo->ofsColors          = 0;
	vbo->ofsPaintColors     = 0;
	vbo->ofsLightDirections = 0;
	vbo->ofsBoneIndexes     = 0;
	vbo->ofsBoneWeights     = 0;

	vbo->sizeXYZ       = 0;
	vbo->sizeTangents  = 0;
	vbo->sizeBinormals = 0;
	vbo->sizeNormals   = 0;

	// create VBO
	dataSize = numVertexes * (sizeof(vec4_t) * 9);
	data     = (byte *)ri.Hunk_AllocateTempMemory(dataSize);
	dataOfs  = 0;

	// since this is all float, point tmp directly into data
	// 2-entry -> { memb[0], memb[1], 0, 1 }
	// 3-entry -> { memb[0], memb[1], memb[2], 1 }
#define VERTEXSIZE(memb) (sizeof(verts->memb) / sizeof(verts->memb[0]))
#define VERTEXCOPY(memb) \
	do { \
		vec_t *tmp = (vec_t *) (data + dataOfs); \
		for (i = 0; i < numVertexes; i++) \
		{ \
			for (j = 0; j < VERTEXSIZE(memb); j++) { *tmp++ = verts[i].memb[j]; } \
			if (VERTEXSIZE(memb) < 3) { *tmp++ = 0; } \
			if (VERTEXSIZE(memb) < 4) { *tmp++ = 1; } \
		} \
		dataOfs += i * sizeof(vec4_t); \
	} while (0)

	// set up xyz array
	VERTEXCOPY(xyz);

	// feed vertex texcoords
	if (stateBits & ATTR_TEXCOORD)
	{
		vbo->ofsTexCoords = dataOfs;
		VERTEXCOPY(st);
	}

	// feed vertex lightmap texcoords
	if (stateBits & ATTR_LIGHTCOORD)
	{
		vbo->ofsLightCoords = dataOfs;
		VERTEXCOPY(lightmap);
	}

	// feed vertex tangents
	if (stateBits & ATTR_TANGENT)
	{
		vbo->ofsTangents = dataOfs;
		VERTEXCOPY(tangent);
	}

	// feed vertex binormals
	if (stateBits & ATTR_BINORMAL)
	{
		vbo->ofsBinormals = dataOfs;
		VERTEXCOPY(binormal);
	}

	// feed vertex normals
	if (stateBits & ATTR_NORMAL)
	{
		vbo->ofsNormals = dataOfs;
		VERTEXCOPY(normal);
	}

	// feed vertex colors
	if (stateBits & ATTR_COLOR)
	{
		vbo->ofsColors = dataOfs;
		VERTEXCOPY(lightColor);
	}

	vbo->vertexesSize = dataSize;
	vbo->vertexesNum  = numVertexes;

	glGenBuffers(1, &vbo->vertexesVBO);

	glBindBuffer(GL_ARRAY_BUFFER, vbo->vertexesVBO);
	glBufferData(GL_ARRAY_BUFFER, dataSize, data, glUsage);

	glBindBuffer(GL_ARRAY_BUFFER, 0);

	GL_CheckErrors();

	ri.Hunk_FreeTempMemory(data);

	return vbo;
}
Ejemplo n.º 2
0
/*
============
R_InitFBOs
============
*/
void R_InitFBOs(void)
{
	int             i;
	int             width, height;

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

	if(!glConfig2.framebufferObjectAvailable)
		return;

	tr.numFBOs = 0;

#if !defined(USE_D3D10)
	GL_CheckErrors();
#endif

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

#if defined(USE_D3D10)
	// TODO
#else
	if(DS_STANDARD_ENABLED())
	{
		// geometricRender FBO as G-Buffer for deferred shading
		ri.Printf(PRINT_ALL, "Deferred Shading enabled\n");

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


		tr.geometricRenderFBO = R_CreateFBO("_geometricRender", width, height);
		R_BindFBO(tr.geometricRenderFBO);

		#if 0
		if(glConfig2.framebufferPackedDepthStencilAvailable)
		{
			R_CreateFBOPackedDepthStencilBuffer(tr.geometricRenderFBO, GL_DEPTH24_STENCIL8_EXT);
			R_AttachFBOTexturePackedDepthStencil(tr.depthRenderImage->texnum);
		}
		
		else if(glConfig.hardwareType == GLHW_ATI || glConfig.hardwareType == GLHW_ATI_DX10)// || glConfig.hardwareType == GLHW_NV_DX10)
		{
			R_CreateFBODepthBuffer(tr.geometricRenderFBO, GL_DEPTH_COMPONENT16_ARB);
			R_AttachFBOTextureDepth(tr.depthRenderImage->texnum);
		}
		else
		#endif
		{
			R_CreateFBODepthBuffer(tr.geometricRenderFBO, GL_DEPTH_COMPONENT24_ARB);
			R_AttachFBOTextureDepth(tr.depthRenderImage->texnum);
		}
		
		// enable all attachments as draw buffers
		//glDrawBuffersARB(4, geometricRenderTargets);

		R_CreateFBOColorBuffer(tr.geometricRenderFBO, GL_RGBA, 0);
		R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.deferredRenderFBOImage->texnum, 0);
		
		R_CreateFBOColorBuffer(tr.geometricRenderFBO, GL_RGBA, 1);
		R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.deferredDiffuseFBOImage->texnum, 1);

		R_CreateFBOColorBuffer(tr.geometricRenderFBO, GL_RGBA, 2);
		R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.deferredNormalFBOImage->texnum, 2);

		R_CreateFBOColorBuffer(tr.geometricRenderFBO, GL_RGBA, 3);
		R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.deferredSpecularFBOImage->texnum, 3);

		R_CheckFBO(tr.geometricRenderFBO);
	}
	else
	{
		// 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);

#if 0
		if(glConfig2.framebufferPackedDepthStencilAvailable)
		{
			R_CreateFBOPackedDepthStencilBuffer(tr.deferredRenderFBO, GL_DEPTH24_STENCIL8_EXT);
			R_AttachFBOTexturePackedDepthStencil(tr.depthRenderImage->texnum);
		}
		else if(glConfig.hardwareType == GLHW_ATI || glConfig.hardwareType == GLHW_ATI_DX10)// || glConfig.hardwareType == GLHW_NV_DX10)
		{
			R_CreateFBODepthBuffer(tr.deferredRenderFBO, GL_DEPTH_COMPONENT16_ARB);
			R_AttachFBOTextureDepth(tr.depthRenderImage->texnum);
		}
		else
#endif
		{
			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(glConfig.hardwareType == GLHW_ATI_DX10)
		{
			//R_CreateFBOColorBuffer(tr.occlusionRenderFBO, GL_ALPHA16F_ARB, 0);
			R_CreateFBODepthBuffer(tr.occlusionRenderFBO, GL_DEPTH_COMPONENT16_ARB);
		}
		else if(glConfig.hardwareType == GLHW_NV_DX10)
		{
			//R_CreateFBOColorBuffer(tr.occlusionRenderFBO, GL_ALPHA32F_ARB, 0);
			R_CreateFBODepthBuffer(tr.occlusionRenderFBO, GL_DEPTH_COMPONENT24_ARB);
		}
		else if(glConfig2.framebufferPackedDepthStencilAvailable)
		{
			//R_CreateFBOColorBuffer(tr.occlusionRenderFBO, GL_ALPHA32F_ARB, 0);
			R_CreateFBOPackedDepthStencilBuffer(tr.occlusionRenderFBO, GL_DEPTH24_STENCIL8_EXT);
		}
		else
		{
			//R_CreateFBOColorBuffer(tr.occlusionRenderFBO, GL_RGBA, 0);
			R_CreateFBODepthBuffer(tr.occlusionRenderFBO, GL_DEPTH_COMPONENT24_ARB);
		}

		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((glConfig.driverType == GLDRV_OPENGL3) || (glConfig.hardwareType == GLHW_NV_DX10 || glConfig.hardwareType == GLHW_ATI_DX10))
			{
				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);
				}
			}
			else
			{
				if(r_shadows->integer == SHADOWING_ESM16)
				{
					R_CreateFBOColorBuffer(tr.shadowMapFBO[i], GL_ALPHA16F_ARB, 0);
				}
				else if(r_shadows->integer == SHADOWING_VSM16)
				{
					R_CreateFBOColorBuffer(tr.shadowMapFBO[i], GL_LUMINANCE_ALPHA16F_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((glConfig.driverType == GLDRV_OPENGL3) || (glConfig.hardwareType == GLHW_NV_DX10 || glConfig.hardwareType == GLHW_ATI_DX10))
			{
				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);
				}
			}
			else
			{
				if(r_shadows->integer == SHADOWING_ESM16)
				{
					R_CreateFBOColorBuffer(tr.sunShadowMapFBO[i], GL_ALPHA16F_ARB, 0);
				}
				else if(r_shadows->integer == SHADOWING_VSM16)
				{
					R_CreateFBOColorBuffer(tr.sunShadowMapFBO[i], GL_LUMINANCE_ALPHA16F_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();
#endif // defined(USE_D3D10)

	R_BindNullFBO();
}
Ejemplo n.º 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;

	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_SyncRenderThread();
			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_SyncRenderThread();
			qglDisable( GL_STENCIL_TEST );
		}
		r_measureOverdraw->modified = qfalse;
	}

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

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

		R_SyncRenderThread();
		R_SetColorMappings();
	}

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

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

	//
	// draw buffer stuff
	//
	cmd = R_GetCommandBuffer( sizeof( *cmd ) );
	if ( !cmd ) {
		return;
	}
	cmd->commandId = RC_DRAW_BUFFER;

	if ( glConfig.stereoEnabled ) {
		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 ( stereoFrame != STEREO_CENTER ) {
			ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is disabled, but stereoFrame was %i", stereoFrame );
		}
		if ( !Q_stricmp( r_drawBuffer->string, "GL_FRONT" ) ) {
			cmd->buffer = (int)GL_FRONT;
		} else {
			cmd->buffer = (int)GL_BACK;
		}
	}
}
Ejemplo n.º 4
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;
#ifdef PANDORA
	vec2_t texcoords[4];
	vec2_t verts[4];
	glIndex_t indicies[6] = { 0, 1, 2, 0, 3, 2 };
#endif
	if ( !tr.registered ) {
		return;
	}
	R_SyncRenderThread();

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

	start = end = 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 PANDORA
		qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
#else
		qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, 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();

#ifdef PANDORA
	glColor4f( tr.identityLight, tr.identityLight, tr.identityLight, 1.0f );

	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;

	texcoords[0][0] = 0.5f/cols;      texcoords[0][1] = 0.5f/rows;
	texcoords[1][0] = (cols-0.5f)/cols;   texcoords[1][1] = 0.5f/rows;
	texcoords[2][0] = (cols-0.5f)/cols;   texcoords[2][1] = (rows-0.5f)/rows;
	texcoords[3][0] = 0.5f/cols;      texcoords[3][1] = (rows-0.5f)/rows;

	qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
	qglTexCoordPointer( 2, GL_FLOAT, 0, texcoords );
	qglVertexPointer  ( 2, GL_FLOAT, 0, verts );
	qglDrawElements( GL_TRIANGLE_STRIP, 6, GL_INDEX_TYPE, indicies );
	qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
#else
	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 ();
#endif
}
Ejemplo n.º 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;
	unsigned  *buffer;
	int       bufferLen = 0;
	int       lod;
	int       ident;
	qboolean  loaded;
	qhandle_t hModel;
	int       numLoaded;

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

	if ( strlen( name ) >= MAX_QPATH )
	{
		Com_Printf( "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 ) );

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

	mod->numLods = 0;

	// load the files
	numLoaded = 0;

#if defined( COMPAT_ET )

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

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

		if ( buffer )
		{
			loadmodel = mod;

			ident = LittleLong( * ( unsigned * ) buffer );
#if defined( COMPAT_ET )
#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 );
				}

#endif

#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 ];

		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 ] = '3';  // try MD3 first
		ri.FS_ReadFile( filename, ( void ** ) &buffer );

		if ( !buffer )
		{
			filename[ strlen( filename ) - 1 ] = 'c';  // try MDC second
			ri.FS_ReadFile( filename, ( void ** ) &buffer );

			if ( !buffer )
			{
				continue;
			}
		}

		loadmodel = mod;

		ident = LittleLong( * ( unsigned * ) buffer );

		if ( ident == MD3_IDENT )
		{
			loaded = R_LoadMD3( mod, lod, buffer, bufferLen, name );
			ri.FS_FreeFile( buffer );
		}

#if defined( COMPAT_ET )
		else if ( ident == MDC_IDENT )
		{
			loaded = R_LoadMDC( mod, lod, buffer, bufferLen, name );
			ri.FS_FreeFile( buffer );
		}

#endif
		else
		{
			ri.FS_FreeFile( buffer );

			ri.Printf( PRINT_WARNING, "RE_RegisterModel: unknown fileid for %s\n", name );
			goto fail;
		}

		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;
	}

#ifndef NDEBUG
	else
	{
		ri.Printf( PRINT_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;
}
Ejemplo n.º 6
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;
	unsigned	*buf;
	int			lod;
	int			ident;
	qboolean	loaded = qfalse;
	qhandle_t	hModel;
	int			numLoaded;
	char		*fext, defex[] = "md3", filename[MAX_QPATH], namebuf[MAX_QPATH+20];

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

	if ( strlen( name ) >= MAX_QPATH ) {
		Com_Printf( "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 ) );


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

	mod->numLods = 0;

	//
	// load the files
	//
	numLoaded = 0;

	strcpy(filename, name);

	fext = strchr(filename, '.');
	if(!fext)
		fext = defex;
	else
	{
		*fext = '\0';
		fext++;
	}

#ifdef RAVENMD4
	if(!Q_stricmp(fext, "mdr"))
	{
		int filesize;
		
		filesize = ri.FS_ReadFile(name, (void **) &buf);
		if(!buf)
		{
			ri.Printf (PRINT_WARNING,"RE_RegisterModel: couldn't load %s\n", name);
			mod->type = MOD_BAD;
			return 0;
		}
		
		ident = LittleLong(*(unsigned *)buf);
		if(ident == MDR_IDENT)
			loaded = R_LoadMDR(mod, buf, filesize, name);

		ri.FS_FreeFile (buf);
		
		if(!loaded)
		{
			ri.Printf(PRINT_WARNING,"RE_RegisterModel: couldn't load mdr file %s\n", name);
			mod->type = MOD_BAD;
			return 0;
		}
		
		return mod->index;
	}
#endif

	fext = defex;

	for ( lod = MD3_MAX_LODS - 1 ; lod >= 0 ; lod-- ) {
		if ( lod )
			Com_sprintf(namebuf, sizeof(namebuf), "%s_%d.%s", filename, lod, fext);
		else
			Com_sprintf(namebuf, sizeof(namebuf), "%s.%s", filename, fext);

		ri.FS_ReadFile( namebuf, (void **)&buf );
		if ( !buf ) {
			continue;
		}
		
		loadmodel = mod;
		
		ident = LittleLong(*(unsigned *)buf);
		if ( ident == MD4_IDENT ) {
			loaded = R_LoadMD4( mod, buf, name );
		} else {
			if ( ident != MD3_IDENT ) {
				ri.Printf (PRINT_WARNING,"RE_RegisterModel: unknown fileid for %s\n", name);
				goto fail;
			}

			loaded = R_LoadMD3( mod, lod, buf, name );
		}
		
		ri.FS_FreeFile (buf);

		if ( !loaded ) {
			if ( lod == 0 ) {
				goto fail;
			} else {
				break;
			}
		} else {
			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;
//			}
		}
	}

	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->md3[lod] = mod->md3[lod+1];
		}

		return mod->index;
	}
#ifdef _DEBUG
	else {
		ri.Printf (PRINT_WARNING,"RE_RegisterModel: 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;
	return 0;
}
Ejemplo n.º 7
0
/*
=============
RE_EndRegistration

Touch all images to make sure they are resident
=============
*/
void RE_EndRegistration(void) {
    R_SyncRenderThread();
    if (!ri.Sys_LowPhysicalMemory()) {
        RB_ShowImages();
    }
}
Ejemplo n.º 8
0
/*
===============
RE_Shutdown
===============
*/
void RE_Shutdown( qboolean destroyWindow ) {

	ri.Printf( PRINT_ALL, "RE_Shutdown( %i )\n", destroyWindow );

	ri.Cmd_RemoveCommand( "modellist" );
	ri.Cmd_RemoveCommand( "screenshotJPEG" );
	ri.Cmd_RemoveCommand( "screenshot" );
	ri.Cmd_RemoveCommand( "imagelist" );
	ri.Cmd_RemoveCommand( "shaderlist" );
	ri.Cmd_RemoveCommand( "skinlist" );
	ri.Cmd_RemoveCommand( "gfxinfo" );
	ri.Cmd_RemoveCommand( "modelist" );
	ri.Cmd_RemoveCommand( "shaderstate" );
	ri.Cmd_RemoveCommand( "taginfo" );

	// Ridah
	ri.Cmd_RemoveCommand( "cropimages" );
	// done.

	R_ShutdownCommandBuffers();

	// Ridah, keep a backup of the current images if possible
	// clean out any remaining unused media from the last backup
	R_PurgeShaders( 9999999 );
	R_PurgeBackupImages( 9999999 );
	R_PurgeModels( 9999999 );

	if ( r_cache->integer ) {
		if ( tr.registered ) {
			if ( destroyWindow ) {
				R_SyncRenderThread();
				R_ShutdownCommandBuffers();
				R_DeleteTextures();
			} else {
				// backup the current media
				R_ShutdownCommandBuffers();

				R_BackupModels();
				R_BackupShaders();
				R_BackupImages();
			}
		}
	} else if ( tr.registered ) {
		R_SyncRenderThread();
		R_ShutdownCommandBuffers();
		R_DeleteTextures();
	}

	R_DoneFreeType();

	// shut down platform specific OpenGL stuff
	if ( destroyWindow ) {
		GLimp_Shutdown();

		// Ridah, release the virtual memory
		R_Hunk_End();
		R_FreeImageBuffer();
		//ri.Tag_Free();	// wipe all render alloc'd zone memory
	}

	tr.registered = qfalse;
}
Ejemplo n.º 9
0
/*
============
R_InitFBOs
============
*/
void R_InitFBOs()
{
	int i;
	int width, height;

	ri.Printf( PRINT_DEVELOPER, "------- R_InitFBOs -------\n" );

	if ( !glConfig2.framebufferObjectAvailable )
	{
		return;
	}

	tr.numFBOs = 0;

	GL_CheckErrors();

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

	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 ( glConfig.hardwareType == GLHW_ATI_DX10 )
	{
		R_CreateFBODepthBuffer( tr.occlusionRenderFBO, GL_DEPTH_COMPONENT16 );
	}
	else if ( glConfig.hardwareType == GLHW_NV_DX10 )
	{
		R_CreateFBODepthBuffer( tr.occlusionRenderFBO, GL_DEPTH_COMPONENT24 );
	}
	else if ( glConfig2.framebufferPackedDepthStencilAvailable )
	{
		R_CreateFBOPackedDepthStencilBuffer( tr.occlusionRenderFBO, GL_DEPTH24_STENCIL8_EXT );
	}
	else
	{
		R_CreateFBODepthBuffer( tr.occlusionRenderFBO, GL_DEPTH_COMPONENT24 );
	}

	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 ] );
			R_AttachFBOTexture2D( GL_TEXTURE_2D,
					      tr.shadowMapFBOImage[ i ]->texnum,
					      0 );

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

			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 ] );
			R_AttachFBOTexture2D( GL_TEXTURE_2D,
					      tr.sunShadowMapFBOImage[ i ]->texnum,
					      0 );

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

			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 );

		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 );

		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 );

		R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.downScaleFBOImage_64x64->texnum, 0 );
		R_CheckFBO( tr.downScaleFBO_64x64 );

		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 );

		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 ] );

			R_AttachFBOTexture2D( GL_TEXTURE_2D, tr.bloomRenderFBOImage[ i ]->texnum, 0 );

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

	GL_CheckErrors();

	R_BindNullFBO();
}
Ejemplo n.º 10
0
/*
===============
RE_Shutdown
===============
*/
void RE_Shutdown( qboolean destroyWindow ) {

//	Com_Printf ("RE_Shutdown( %i )\n", destroyWindow );

    Cmd_RemoveCommand ("imagelist");
    Cmd_RemoveCommand ("shaderlist");
    Cmd_RemoveCommand ("skinlist");
    Cmd_RemoveCommand ("screenshot");
    Cmd_RemoveCommand ("screenshot_tga");
    Cmd_RemoveCommand ("gfxinfo");
    Cmd_RemoveCommand ("r_we");
    Cmd_RemoveCommand ("imagecacheinfo");
    Cmd_RemoveCommand ("modellist");
    Cmd_RemoveCommand ("modelist");
    Cmd_RemoveCommand ("modelcacheinfo");
#ifndef DEDICATED

#ifndef _XBOX	// GLOWXXX
    if ( r_DynamicGlow && r_DynamicGlow->integer )
    {
        // Release the Glow Vertex Shader.
        if ( tr.glowVShader )
        {
            qglDeleteProgramsARB( 1, &tr.glowVShader );
        }

        // Release Pixel Shader.
        if ( tr.glowPShader )
        {
            if ( qglCombinerParameteriNV  )
            {
                // Release the Glow Regcom call list.
                qglDeleteLists( tr.glowPShader, 1 );
            }
            else if ( qglGenProgramsARB )
            {
                // Release the Glow Fragment Shader.
                qglDeleteProgramsARB( 1, &tr.glowPShader );
            }
        }

        // Release the scene glow texture.
        qglDeleteTextures( 1, &tr.screenGlow );

        // Release the scene texture.
        qglDeleteTextures( 1, &tr.sceneImage );

        // Release the blur texture.
        qglDeleteTextures( 1, &tr.blurImage );
    }
#endif

    /*
    	R_TerrainShutdown(); //rwwRMG - added
    */

    R_ShutdownFonts();
    if ( tr.registered ) {
        R_SyncRenderThread();
        R_ShutdownCommandBuffers();
//#ifndef _XBOX
        if (destroyWindow)
//#endif
        {
            R_DeleteTextures();		// only do this for vid_restart now, not during things like map load
        }
    }

    // shut down platform specific OpenGL stuff
    if ( destroyWindow ) {
        GLimp_Shutdown();
    }
#endif //!DEDICATED

    tr.registered = qfalse;
}
Ejemplo n.º 11
0
/*
===============
RE_RegisterSkin

===============
*/
qhandle_t RE_RegisterSkin( const char *name )
{
	qhandle_t     hSkin;
	skin_t        *skin;
	skinSurface_t *surf;
	skinModel_t   *model; //----(SA) added
	char          *text, *text_p;
	char          *token;
	char          surfName[ MAX_QPATH ];

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

	if ( strlen( name ) >= MAX_QPATH )
	{
		Com_Printf( "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_WARNING, "WARNING: RE_RegisterSkin( '%s' ) MAX_SKINS hit\n", name );
		return 0;
	}

//----(SA)  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_SyncRenderThread();

#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 = 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; //----(SA) added

//----(SA)  end

	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 ) )
		{
			// this is specifying a model
			model = skin->models[ skin->numModels ] = 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 );

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

		// RB: bspSurface_t does 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;
}
Ejemplo n.º 12
0
//	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 R_RegisterModel( const char* name, idSkinTranslation* skinTranslation ) {
	if ( !name || !name[ 0 ] ) {
		common->Printf( "R_RegisterModel: NULL name\n" );
		return 0;
	}

	if ( String::Length( name ) >= MAX_QPATH ) {
		common->Printf( "Model name exceeds MAX_QPATH\n" );
		return 0;
	}

	// Ridah, caching
	if ( r_cacheGathering->integer ) {
		Cbuf_ExecuteText( EXEC_NOW, va( "cache_usedfile model %s\n", name ) );
	}

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

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

	idList<byte> buf;
	int modfilelen = FS_ReadFile( name, buf );
	if ( modfilelen < 0 && ( GGameType & ( GAME_WolfSP | GAME_WolfMP | GAME_ET ) ) ) {
		char filename[ 1024 ];
		String::Cpy( filename, name );

		//	try MDC first
		filename[ String::Length( filename ) - 1 ] = 'c';
		modfilelen = FS_ReadFile( filename, buf );

		if ( modfilelen < 0 ) {
			// try MD3 second
			filename[ String::Length( filename ) - 1 ] = '3';
			modfilelen = FS_ReadFile( filename, buf );
		}
	}
	if ( modfilelen < 0 ) {
		common->Printf( S_COLOR_YELLOW "R_RegisterModel: couldn't load %s\n", name );
		// we still keep the idRenderModel around, so if the model name is asked for
		// again, we won't bother scanning the filesystem
		idRenderModel* mod = new idRenderModelBad();
		R_AddModel( mod );
		mod->type = MOD_BAD;
		String::NCpyZ( mod->name, name, sizeof ( mod->name ) );
		return 0;
	}

	// allocate a new idRenderModel
	idRenderModel* mod;
	switch ( LittleLong( *( qint32* )buf.Ptr() ) ) {
	case BSP29_VERSION:
		mod = new idRenderModelBSP29NonMap();
		break;

	case IDSPRITE1HEADER:
		mod = new idRenderModelSPR();
		break;

	case IDSPRITE2HEADER:
		mod = new idRenderModelSP2();
		break;

	case IDPOLYHEADER:
		mod = new idRenderModelMDL();
		break;

	case RAPOLYHEADER:
		mod = new idRenderModelMDLNew();
		break;

	case IDMESH2HEADER:
		mod = new idRenderModelMD2();
		break;

	case MD3_IDENT:
		mod = new idRenderModelMD3();
		break;

	case MD4_IDENT:
		mod = new idRenderModelMD4();
		break;

	case MDC_IDENT:
		mod = new idRenderModelMDC();
		break;

	case MDS_IDENT:
		mod = new idRenderModelMDS();
		break;

	case MDM_IDENT:
		mod = new idRenderModelMDM();
		break;

	case MDX_IDENT:
		mod = new idRenderModelMDX();
		break;

	default:
		common->Printf( S_COLOR_YELLOW "R_RegisterModel: unknown fileid for %s\n", name );
		mod = new idRenderModelBad;
		break;
	}
	R_AddModel( mod );

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

	loadmodel = mod;

	//	call the apropriate loader
	bool loaded = mod->Load( buf, skinTranslation );

	R_LoadModelShadow( mod );

	// GR - by default models are not tessellated
	mod->q3_ATI_tess = false;
	// GR - check if can be tessellated...
	//		make sure to tessellate model heads
	if ( GGameType & GAME_WolfSP && strstr( name, "head" ) ) {
		mod->q3_ATI_tess = true;
	}

	if ( !loaded ) {
		common->Printf( S_COLOR_YELLOW "R_RegisterModel: couldn't load %s\n", name );
		// we still keep the idRenderModel around, so if the model name is asked for
		// again, we won't bother scanning the filesystem
		delete mod;
		mod = new idRenderModelBad();
		R_AddModel( mod );
		mod->type = MOD_BAD;
		String::NCpyZ( mod->name, name, sizeof ( mod->name ) );
		return 0;
	}

	return mod->index;
}
Ejemplo n.º 13
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 ) {
		Com_Printf( "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 ) );


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

	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;
}
Ejemplo n.º 14
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;

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

	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 = false;
		}
		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 = false;
		}
		else
		{
			R_SyncRenderThread();
			glEnable(GL_STENCIL_TEST);
			glStencilMask(~0U);
			glClearStencil(0U);
			glStencilFunc(GL_ALWAYS, 0U, ~0U);
			glStencilOp(GL_KEEP, GL_INCR, GL_INCR);
		}
		r_measureOverdraw->modified = false;
	}
	else
	{
		// this is only reached if it was on and is now off
		if(r_measureOverdraw->modified)
		{
			R_SyncRenderThread();
			glDisable(GL_STENCIL_TEST);
		}
		r_measureOverdraw->modified = false;
	}

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

	//
	// anisotropic filtering stuff
	//
	if(r_textureAnisotropy->modified)
	{
		R_SyncRenderThread();
		GL_TextureAnisotropy(r_textureAnisotropy->value);
		r_textureAnisotropy->modified = false;
	}

	//
	// NVidia stuff
	//

	// fog control
	if(glConfig.NVFogAvailable && r_nv_fogdist_mode->modified)
	{
		r_nv_fogdist_mode->modified = false;
		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 = false;

		if( !glConfig.deviceSupportsGamma ) {
			Com_Printf( "r_gamma will be changed upon restarting.\n" );
		} else {
			R_SyncRenderThread();
			R_SetColorMappings();
		}
	}

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

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

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

	if(glConfig.stereoEnabled)
	{
		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(stereoFrame != STEREO_CENTER)
		{
			ri.Error(ERR_FATAL, "RE_BeginFrame: Stereo is disabled, but stereoFrame was %i", stereoFrame);
		}
		if(!Q_stricmp(r_drawBuffer->string, "GL_FRONT"))
		{
			cmd->buffer = (int)GL_FRONT;
		}
		else
		{
			cmd->buffer = (int)GL_BACK;
		}
	}
}
Ejemplo n.º 15
0
/*
============
R_CreateIBO2
============
*/
IBO_t *R_CreateIBO2(const char *name, int numTriangles, srfTriangle_t *triangles, vboUsage_t usage)
{
	IBO_t *ibo;
	int   i, j;

	byte *indexes;
	int  indexesSize;
	int  indexesOfs;

	srfTriangle_t *tri;
	glIndex_t     index;
	int           glUsage;

	switch (usage)
	{
	case VBO_USAGE_STATIC:
		glUsage = GL_STATIC_DRAW;
		break;

	case VBO_USAGE_DYNAMIC:
		glUsage = GL_DYNAMIC_DRAW;
		break;

	default:
		glUsage = 0;
		Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage);
	}

	if (!numTriangles)
	{
		return NULL;
	}

	if (strlen(name) >= MAX_QPATH)
	{
		ri.Error(ERR_DROP, "R_CreateIBO2: \"%s\" is too long\n", name);
	}

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

	ibo = (IBO_t *)ri.Hunk_Alloc(sizeof(*ibo), h_low);
	Com_AddToGrowList(&tr.ibos, ibo);

	Q_strncpyz(ibo->name, name, sizeof(ibo->name));

	indexesSize = numTriangles * 3 * sizeof(glIndex_t);
	indexes     = (byte *)ri.Hunk_AllocateTempMemory(indexesSize);
	indexesOfs  = 0;

	//ri.Printf(PRINT_ALL, "sizeof(glIndex_t) = %i\n", sizeof(glIndex_t));

	for (i = 0, tri = triangles; i < numTriangles; i++, tri++)
	{
		for (j = 0; j < 3; j++)
		{
			index = tri->indexes[j];
			memcpy(indexes + indexesOfs, &index, sizeof(glIndex_t));
			indexesOfs += sizeof(glIndex_t);
		}
	}

	ibo->indexesSize = indexesSize;
	ibo->indexesNum  = numTriangles * 3;

	glGenBuffers(1, &ibo->indexesVBO);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo->indexesVBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexesSize, indexes, glUsage);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

	GL_CheckErrors();

	ri.Hunk_FreeTempMemory(indexes);

	return ibo;
}
Ejemplo n.º 16
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_SyncRenderThread();

	// 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;
		qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, 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 ) {
		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 );

	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 ();
}
Ejemplo n.º 17
0
/*
============
R_CreateVBO
============
*/
VBO_t *R_CreateVBO(const char *name, byte *vertexes, int vertexesSize, vboUsage_t usage)
{
	VBO_t *vbo;
	int   glUsage;

	switch (usage)
	{
	case VBO_USAGE_STATIC:
		glUsage = GL_STATIC_DRAW;
		break;

	case VBO_USAGE_DYNAMIC:
		glUsage = GL_DYNAMIC_DRAW;
		break;

	default:
		glUsage = 0; //Prevents warning
		Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage);
	}

	if (strlen(name) >= MAX_QPATH)
	{
		ri.Error(ERR_DROP, "R_CreateVBO: \"%s\" is too long\n", name);
	}

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

	vbo = (VBO_t *)ri.Hunk_Alloc(sizeof(*vbo), h_low);
	Com_AddToGrowList(&tr.vbos, vbo);

	Q_strncpyz(vbo->name, name, sizeof(vbo->name));

	vbo->ofsXYZ             = 0;
	vbo->ofsTexCoords       = 0;
	vbo->ofsLightCoords     = 0;
	vbo->ofsBinormals       = 0;
	vbo->ofsTangents        = 0;
	vbo->ofsNormals         = 0;
	vbo->ofsColors          = 0;
	vbo->ofsPaintColors     = 0;
	vbo->ofsLightDirections = 0;
	vbo->ofsBoneIndexes     = 0;
	vbo->ofsBoneWeights     = 0;

	vbo->sizeXYZ       = 0;
	vbo->sizeTangents  = 0;
	vbo->sizeBinormals = 0;
	vbo->sizeNormals   = 0;

	vbo->vertexesSize = vertexesSize;

	glGenBuffers(1, &vbo->vertexesVBO);

	glBindBuffer(GL_ARRAY_BUFFER, vbo->vertexesVBO);
	glBufferData(GL_ARRAY_BUFFER, vertexesSize, vertexes, glUsage);

	glBindBuffer(GL_ARRAY_BUFFER, 0);

	GL_CheckErrors();

	return vbo;
}
Ejemplo n.º 18
0
/*
============
R_CreateVBO2

RB: OPTIMIZE rewrite to not use memcpy
============
*/
VBO_t          *R_CreateVBO2(const char *name, int numVertexes, srfVert_t * verts, unsigned int stateBits, vboUsage_t usage)
{
	VBO_t          *vbo;
	int             i, j;

	byte           *data;
	int             dataSize;
	int             dataOfs;

	vec4_t          tmp;
	int				glUsage;

	switch (usage)
	{
		case VBO_USAGE_STATIC:
			glUsage = GL_STATIC_DRAW_ARB;
			break;

		case VBO_USAGE_DYNAMIC:
			glUsage = GL_DYNAMIC_DRAW_ARB;
			break;

		default:
			Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage);
	}

	if(!numVertexes)
		return NULL;

	if(strlen(name) >= MAX_QPATH)
	{
		ri.Error(ERR_DROP, "R_CreateVBO2: \"%s\" is too long\n", name);
	}

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

	vbo = ri.Hunk_Alloc(sizeof(*vbo), h_low);
	Com_AddToGrowList(&tr.vbos, vbo);

	Q_strncpyz(vbo->name, name, sizeof(vbo->name));

	vbo->ofsXYZ = 0;
	vbo->ofsTexCoords = 0;
	vbo->ofsLightCoords = 0;
	vbo->ofsBinormals = 0;
	vbo->ofsTangents = 0;
	vbo->ofsNormals = 0;
	vbo->ofsColors = 0;
	vbo->ofsPaintColors = 0;
	vbo->ofsLightDirections = 0;
	vbo->ofsBoneIndexes = 0;
	vbo->ofsBoneWeights = 0;

	vbo->sizeXYZ = 0;
	vbo->sizeTangents = 0;
	vbo->sizeBinormals = 0;
	vbo->sizeNormals = 0;

	// create VBO
	dataSize = numVertexes * (sizeof(vec4_t) * 9);
	data = ri.Hunk_AllocateTempMemory(dataSize);
	dataOfs = 0;

	// set up xyz array
	for(i = 0; i < numVertexes; i++)
	{
		for(j = 0; j < 3; j++)
		{
			tmp[j] = verts[i].xyz[j];
		}
		tmp[3] = 1;

		memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
		dataOfs += sizeof(vec4_t);
	}

	// feed vertex texcoords
	if(stateBits & ATTR_TEXCOORD)
	{
		vbo->ofsTexCoords = dataOfs;
		for(i = 0; i < numVertexes; i++)
		{
			for(j = 0; j < 2; j++)
			{
				tmp[j] = verts[i].st[j];
			}
			tmp[2] = 0;
			tmp[3] = 1;

			memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
			dataOfs += sizeof(vec4_t);
		}
	}

	// feed vertex lightmap texcoords
	if(stateBits & ATTR_LIGHTCOORD)
	{
		vbo->ofsLightCoords = dataOfs;
		for(i = 0; i < numVertexes; i++)
		{
			for(j = 0; j < 2; j++)
			{
				tmp[j] = verts[i].lightmap[j];
			}
			tmp[2] = 0;
			tmp[3] = 1;

			memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
			dataOfs += sizeof(vec4_t);
		}
	}

	// feed vertex tangents
	if(stateBits & ATTR_TANGENT)
	{
		vbo->ofsTangents = dataOfs;
		for(i = 0; i < numVertexes; i++)
		{
			for(j = 0; j < 3; j++)
			{
				tmp[j] = verts[i].tangent[j];
			}
			tmp[3] = 1;

			memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
			dataOfs += sizeof(vec4_t);
		}
	}

	// feed vertex binormals
	if(stateBits & ATTR_BINORMAL)
	{
		vbo->ofsBinormals = dataOfs;
		for(i = 0; i < numVertexes; i++)
		{
			for(j = 0; j < 3; j++)
			{
				tmp[j] = verts[i].binormal[j];
			}
			tmp[3] = 1;

			memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
			dataOfs += sizeof(vec4_t);
		}
	}

	// feed vertex normals
	if(stateBits & ATTR_NORMAL)
	{
		vbo->ofsNormals = dataOfs;
		for(i = 0; i < numVertexes; i++)
		{
			for(j = 0; j < 3; j++)
			{
				tmp[j] = verts[i].normal[j];
			}
			tmp[3] = 1;

			memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
			dataOfs += sizeof(vec4_t);
		}
	}

	// feed vertex colors
	if(stateBits & ATTR_COLOR)
	{
		vbo->ofsColors = dataOfs;
		for(i = 0; i < numVertexes; i++)
		{
			for(j = 0; j < 4; j++)
			{
				tmp[j] = verts[i].lightColor[j];
			}

			memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
			dataOfs += sizeof(vec4_t);
		}
	}

#if !defined(COMPAT_Q3A) && !defined(COMPAT_ET)
	// feed vertex paint colors
	if(stateBits & ATTR_PAINTCOLOR)
	{
		vbo->ofsPaintColors = dataOfs;
		for(i = 0; i < numVertexes; i++)
		{
			for(j = 0; j < 4; j++)
			{
				tmp[j] = verts[i].paintColor[j];
			}

			memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
			dataOfs += sizeof(vec4_t);
		}
	}

	// feed vertex light directions
	if(stateBits & ATTR_LIGHTDIRECTION)
	{
		vbo->ofsLightDirections = dataOfs;
		for(i = 0; i < numVertexes; i++)
		{
			for(j = 0; j < 3; j++)
			{
				tmp[j] = verts[i].lightDirection[j];
			}
			tmp[3] = 1;

			memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
			dataOfs += sizeof(vec4_t);
		}
	}
#endif

	vbo->vertexesSize = dataSize;
	vbo->vertexesNum = numVertexes;

	glGenBuffersARB(1, &vbo->vertexesVBO);

	glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vertexesVBO);
	glBufferDataARB(GL_ARRAY_BUFFER_ARB, dataSize, data, glUsage);

	glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);

	GL_CheckErrors();

	ri.Hunk_FreeTempMemory(data);

	return vbo;
}
Ejemplo n.º 19
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_SyncRenderThread();
			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_SyncRenderThread();
			qglDisable( GL_STENCIL_TEST );
		}
		r_measureOverdraw->modified = qfalse;
	}
	#endif

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

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

		R_SyncRenderThread();
		R_SetColorMappings();
	}

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

		R_SyncRenderThread();
		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;
}
Ejemplo n.º 20
0
/*
============
R_CreateIBO2
============
*/
IBO_t          *R_CreateIBO2(const char *name, int numTriangles, srfTriangle_t * triangles, vboUsage_t usage)
{
	IBO_t          *ibo;
	int             i, j;

	byte           *indexes;
	int             indexesSize;
	int             indexesOfs;

	srfTriangle_t  *tri;
	glIndex_t       index;
	int				glUsage;

	switch (usage)
	{
		case VBO_USAGE_STATIC:
			glUsage = GL_STATIC_DRAW_ARB;
			break;

		case VBO_USAGE_DYNAMIC:
			glUsage = GL_DYNAMIC_DRAW_ARB;
			break;

		default:
			Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage);
			return NULL;
	}

	if(!numTriangles)
		return NULL;

	if(strlen(name) >= MAX_QPATH)
	{
		ri.Error(ERR_DROP, "R_CreateIBO2: \"%s\" is too long\n", name);
	}

	if ( tr.numIBOs == MAX_IBOS ) {
		ri.Error( ERR_DROP, "R_CreateIBO2: MAX_IBOS hit\n");
	}

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

	ibo = tr.ibos[tr.numIBOs] = ri.Hunk_Alloc(sizeof(*ibo), h_low);
	tr.numIBOs++;

	Q_strncpyz(ibo->name, name, sizeof(ibo->name));

	indexesSize = numTriangles * 3 * sizeof(int);
	indexes = ri.Hunk_AllocateTempMemory(indexesSize);
	indexesOfs = 0;

	for(i = 0, tri = triangles; i < numTriangles; i++, tri++)
	{
		for(j = 0; j < 3; j++)
		{
			index = tri->indexes[j];
			memcpy(indexes + indexesOfs, &index, sizeof(glIndex_t));
			indexesOfs += sizeof(glIndex_t);
		}
	}

	ibo->indexesSize = indexesSize;

	qglGenBuffersARB(1, &ibo->indexesVBO);

	qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ibo->indexesVBO);
	qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexesSize, indexes, glUsage);

	qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);

	glState.currentIBO = NULL;

	GL_CheckErrors();

	ri.Hunk_FreeTempMemory(indexes);

	return ibo;
}
Ejemplo n.º 21
0
/*
===============
RE_RegisterAnimation
===============
*/
qhandle_t RE_RegisterAnimation( const char *name )
{
	qhandle_t       hAnim;
	skelAnimation_t *anim;
	char            *buffer;
	int             bufferLen;
	qboolean        loaded = qfalse;

	if ( !name || !name[ 0 ] )
	{
		ri.Printf( PRINT_WARNING, "Empty name passed to RE_RegisterAnimation\n" );
		return 0;
	}

	//ri.Printf(PRINT_ALL, "RE_RegisterAnimation(%s)\n", name);

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

	// search the currently loaded animations
	for ( hAnim = 1; hAnim < tr.numAnimations; hAnim++ )
	{
		anim = tr.animations[ hAnim ];

		if ( !Q_stricmp( anim->name, name ) )
		{
			if ( anim->type == AT_BAD )
			{
				return 0;
			}

			return hAnim;
		}
	}

	// allocate a new model_t
	if ( ( anim = R_AllocAnimation() ) == NULL )
	{
		ri.Printf( PRINT_WARNING, "RE_RegisterAnimation: R_AllocAnimation() failed for '%s'\n", name );
		return 0;
	}

	// only set the name after the animation has been successfully allocated
	Q_strncpyz( anim->name, name, sizeof( anim->name ) );

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

	// load and parse the .md5anim file
	bufferLen = ri.FS_ReadFile( name, ( void ** ) &buffer );

	if ( !buffer )
	{
		return 0;
	}

	if ( !Q_stricmpn( ( const char * ) buffer, "MD5Version", 10 ) )
	{
		loaded = R_LoadMD5Anim( anim, buffer, bufferLen, name );
	}
	else
	{
		ri.Printf( PRINT_WARNING, "RE_RegisterAnimation: unknown fileid for '%s'\n", name );
	}

	ri.FS_FreeFile( buffer );

	if ( !loaded )
	{
		ri.Printf( PRINT_WARNING, "couldn't load '%s'\n", name );

		// we still keep the model_t around, so if the model name is asked for
		// again, we won't bother scanning the filesystem
		anim->type = AT_BAD;
	}

	return anim->index;
}
Ejemplo n.º 22
0
/*
============
R_CreateVBO2
============
*/
VBO_t          *R_CreateVBO2(const char *name, int numVertexes, srfVert_t * verts, unsigned int stateBits, vboUsage_t usage)
{
	VBO_t          *vbo;
	int             i;

	byte           *data;
	int             dataSize;
	int             dataOfs;

	int				glUsage;

	switch (usage)
	{
		case VBO_USAGE_STATIC:
			glUsage = GL_STATIC_DRAW_ARB;
			break;

		case VBO_USAGE_DYNAMIC:
			glUsage = GL_DYNAMIC_DRAW_ARB;
			break;

		default:
			Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage);
			return NULL;
	}

	if(!numVertexes)
		return NULL;

	if(strlen(name) >= MAX_QPATH)
	{
		ri.Error(ERR_DROP, "R_CreateVBO2: \"%s\" is too long\n", name);
	}

	if ( tr.numVBOs == MAX_VBOS ) {
		ri.Error( ERR_DROP, "R_CreateVBO2: MAX_VBOS hit\n");
	}

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

	vbo = tr.vbos[tr.numVBOs] = ri.Hunk_Alloc(sizeof(*vbo), h_low);
	tr.numVBOs++;

	memset(vbo, 0, sizeof(*vbo));

	Q_strncpyz(vbo->name, name, sizeof(vbo->name));

	if (usage == VBO_USAGE_STATIC)
	{
		// since these vertex attributes are never altered, interleave them
		vbo->ofs_xyz = 0;
		dataSize = sizeof(verts[0].xyz);

		if(stateBits & ATTR_NORMAL)
		{
			vbo->ofs_normal = dataSize;
			dataSize += sizeof(verts[0].normal);
		}

#ifdef USE_VERT_TANGENT_SPACE
		if(stateBits & ATTR_TANGENT)
		{
			vbo->ofs_tangent = dataSize;
			dataSize += sizeof(verts[0].tangent);
		}

		if(stateBits & ATTR_BITANGENT)
		{
			vbo->ofs_bitangent = dataSize;
			dataSize += sizeof(verts[0].bitangent);
		}
#endif

		if(stateBits & ATTR_TEXCOORD)
		{
			vbo->ofs_st = dataSize;
			dataSize += sizeof(verts[0].st);
		}

		if(stateBits & ATTR_LIGHTCOORD)
		{
			vbo->ofs_lightmap = dataSize;
			dataSize += sizeof(verts[0].lightmap);
		}

		if(stateBits & ATTR_COLOR)
		{
			vbo->ofs_vertexcolor = dataSize;
			dataSize += sizeof(verts[0].vertexColors);
		}

		if(stateBits & ATTR_LIGHTDIRECTION)
		{
			vbo->ofs_lightdir = dataSize;
			dataSize += sizeof(verts[0].lightdir);
		}

		vbo->stride_xyz         = dataSize;
		vbo->stride_normal      = dataSize;
#ifdef USE_VERT_TANGENT_SPACE
		vbo->stride_tangent     = dataSize;
		vbo->stride_bitangent   = dataSize;
#endif
		vbo->stride_st          = dataSize;
		vbo->stride_lightmap    = dataSize;
		vbo->stride_vertexcolor = dataSize;
		vbo->stride_lightdir    = dataSize;

		// create VBO
		dataSize *= numVertexes;
		data = ri.Hunk_AllocateTempMemory(dataSize);
		dataOfs = 0;

		//ri.Printf(PRINT_ALL, "CreateVBO: %d, %d %d %d %d %d, %d %d %d %d %d\n", dataSize, vbo->ofs_xyz, vbo->ofs_normal, vbo->ofs_st, vbo->ofs_lightmap, vbo->ofs_vertexcolor,
			//vbo->stride_xyz, vbo->stride_normal, vbo->stride_st, vbo->stride_lightmap, vbo->stride_vertexcolor);

		for (i = 0; i < numVertexes; i++)
		{
			// xyz
			memcpy(data + dataOfs, &verts[i].xyz, sizeof(verts[i].xyz));
			dataOfs += sizeof(verts[i].xyz);

			// normal
			if(stateBits & ATTR_NORMAL)
			{
				memcpy(data + dataOfs, &verts[i].normal, sizeof(verts[i].normal));
				dataOfs += sizeof(verts[i].normal);
			}

#ifdef USE_VERT_TANGENT_SPACE
			// tangent
			if(stateBits & ATTR_TANGENT)
			{
				memcpy(data + dataOfs, &verts[i].tangent, sizeof(verts[i].tangent));
				dataOfs += sizeof(verts[i].tangent);
			}

			// bitangent
			if(stateBits & ATTR_BITANGENT)
			{
				memcpy(data + dataOfs, &verts[i].bitangent, sizeof(verts[i].bitangent));
				dataOfs += sizeof(verts[i].bitangent);
			}
#endif

			// vertex texcoords
			if(stateBits & ATTR_TEXCOORD)
			{
				memcpy(data + dataOfs, &verts[i].st, sizeof(verts[i].st));
				dataOfs += sizeof(verts[i].st);
			}

			// feed vertex lightmap texcoords
			if(stateBits & ATTR_LIGHTCOORD)
			{
				memcpy(data + dataOfs, &verts[i].lightmap, sizeof(verts[i].lightmap));
				dataOfs += sizeof(verts[i].lightmap);
			}

			// feed vertex colors
			if(stateBits & ATTR_COLOR)
			{
				memcpy(data + dataOfs, &verts[i].vertexColors, sizeof(verts[i].vertexColors));
				dataOfs += sizeof(verts[i].vertexColors);
			}

			// feed vertex light directions
			if(stateBits & ATTR_LIGHTDIRECTION)
			{
				memcpy(data + dataOfs, &verts[i].lightdir, sizeof(verts[i].lightdir));
				dataOfs += sizeof(verts[i].lightdir);
			}
		}
	}
	else
	{
		// since these vertex attributes may be changed, put them in flat arrays
		dataSize = sizeof(verts[0].xyz);

		if(stateBits & ATTR_NORMAL)
		{
			dataSize += sizeof(verts[0].normal);
		}

#ifdef USE_VERT_TANGENT_SPACE
		if(stateBits & ATTR_TANGENT)
		{
			dataSize += sizeof(verts[0].tangent);
		}

		if(stateBits & ATTR_BITANGENT)
		{
			dataSize += sizeof(verts[0].bitangent);
		}
#endif

		if(stateBits & ATTR_TEXCOORD)
		{
			dataSize += sizeof(verts[0].st);
		}

		if(stateBits & ATTR_LIGHTCOORD)
		{
			dataSize += sizeof(verts[0].lightmap);
		}

		if(stateBits & ATTR_COLOR)
		{
			dataSize += sizeof(verts[0].vertexColors);
		}

		if(stateBits & ATTR_LIGHTDIRECTION)
		{
			dataSize += sizeof(verts[0].lightdir);
		}

		// create VBO
		dataSize *= numVertexes;
		data = ri.Hunk_AllocateTempMemory(dataSize);
		dataOfs = 0;

		vbo->ofs_xyz            = 0;
		vbo->ofs_normal         = 0;
#ifdef USE_VERT_TANGENT_SPACE
		vbo->ofs_tangent        = 0;
		vbo->ofs_bitangent      = 0;
#endif
		vbo->ofs_st             = 0;
		vbo->ofs_lightmap       = 0;
		vbo->ofs_vertexcolor    = 0;
		vbo->ofs_lightdir       = 0;

		vbo->stride_xyz         = sizeof(verts[0].xyz);
		vbo->stride_normal      = sizeof(verts[0].normal);
#ifdef USE_VERT_TANGENT_SPACE
		vbo->stride_tangent     = sizeof(verts[0].tangent);
		vbo->stride_bitangent   = sizeof(verts[0].bitangent);
#endif
		vbo->stride_vertexcolor = sizeof(verts[0].vertexColors);
		vbo->stride_st          = sizeof(verts[0].st);
		vbo->stride_lightmap    = sizeof(verts[0].lightmap);
		vbo->stride_lightdir    = sizeof(verts[0].lightdir);

		//ri.Printf(PRINT_ALL, "2CreateVBO: %d, %d %d %d %d %d, %d %d %d %d %d\n", dataSize, vbo->ofs_xyz, vbo->ofs_normal, vbo->ofs_st, vbo->ofs_lightmap, vbo->ofs_vertexcolor,
			//vbo->stride_xyz, vbo->stride_normal, vbo->stride_st, vbo->stride_lightmap, vbo->stride_vertexcolor);

		// xyz
		for (i = 0; i < numVertexes; i++)
		{
			memcpy(data + dataOfs, &verts[i].xyz, sizeof(verts[i].xyz));
			dataOfs += sizeof(verts[i].xyz);
		}

		// normal
		if(stateBits & ATTR_NORMAL)
		{
			vbo->ofs_normal = dataOfs;
			for (i = 0; i < numVertexes; i++)
			{
				memcpy(data + dataOfs, &verts[i].normal, sizeof(verts[i].normal));
				dataOfs += sizeof(verts[i].normal);
			}
		}

#ifdef USE_VERT_TANGENT_SPACE
		// tangent
		if(stateBits & ATTR_TANGENT)
		{
			vbo->ofs_tangent = dataOfs;
			for (i = 0; i < numVertexes; i++)
			{
				memcpy(data + dataOfs, &verts[i].tangent, sizeof(verts[i].tangent));
				dataOfs += sizeof(verts[i].tangent);
			}
		}

		// bitangent
		if(stateBits & ATTR_BITANGENT)
		{
			vbo->ofs_bitangent = dataOfs;
			for (i = 0; i < numVertexes; i++)
			{
				memcpy(data + dataOfs, &verts[i].bitangent, sizeof(verts[i].bitangent));
				dataOfs += sizeof(verts[i].bitangent);
			}
		}
#endif

		// vertex texcoords
		if(stateBits & ATTR_TEXCOORD)
		{
			vbo->ofs_st = dataOfs;
			for (i = 0; i < numVertexes; i++)
			{
				memcpy(data + dataOfs, &verts[i].st, sizeof(verts[i].st));
				dataOfs += sizeof(verts[i].st);
			}
		}

		// feed vertex lightmap texcoords
		if(stateBits & ATTR_LIGHTCOORD)
		{
			vbo->ofs_lightmap = dataOfs;
			for (i = 0; i < numVertexes; i++)
			{
				memcpy(data + dataOfs, &verts[i].lightmap, sizeof(verts[i].lightmap));
				dataOfs += sizeof(verts[i].lightmap);
			}
		}

		// feed vertex colors
		if(stateBits & ATTR_COLOR)
		{
			vbo->ofs_vertexcolor = dataOfs;
			for (i = 0; i < numVertexes; i++)
			{
				memcpy(data + dataOfs, &verts[i].vertexColors, sizeof(verts[i].vertexColors));
				dataOfs += sizeof(verts[i].vertexColors);
			}
		}

		// feed vertex lightdirs
		if(stateBits & ATTR_LIGHTDIRECTION)
		{
			vbo->ofs_lightdir = dataOfs;
			for (i = 0; i < numVertexes; i++)
			{
				memcpy(data + dataOfs, &verts[i].lightdir, sizeof(verts[i].lightdir));
				dataOfs += sizeof(verts[i].lightdir);
			}
		}
	}


	vbo->vertexesSize = dataSize;

	qglGenBuffersARB(1, &vbo->vertexesVBO);

	qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vertexesVBO);
	qglBufferDataARB(GL_ARRAY_BUFFER_ARB, dataSize, data, glUsage);

	qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);

	glState.currentVBO = NULL;

	GL_CheckErrors();

	ri.Hunk_FreeTempMemory(data);

	return vbo;
}
Ejemplo n.º 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;

	if(!tr.registered)
	{
		return;
	}

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

#if defined(USE_D3D10)
	// TODO
#else
	glState.finishCalled = qfalse;
#endif

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

#if defined(USE_D3D10)
	// draw buffer stuff
	cmd = (drawBufferCommand_t*)R_GetCommandBuffer(sizeof(*cmd));
	if(!cmd)
	{
		return;
	}
	cmd->commandId = RC_DRAW_BUFFER;
	cmd->buffer = 0;
#else
	// 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
		{
			R_SyncRenderThread();
			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_SyncRenderThread();
			glDisable(GL_STENCIL_TEST);
		}
		r_measureOverdraw->modified = qfalse;
	}

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

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

		if( !glConfig.deviceSupportsGamma ) {
			Com_Printf( "r_gamma will be changed upon restarting.\n" );
		} else {
			R_SyncRenderThread();
			R_SetColorMappings();
		}
	}

	// check for errors
	if(!r_ignoreGLErrors->integer)
	{
		int             err;
		char            s[128];

		R_SyncRenderThread();

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

			//ri.Error(ERR_FATAL, "caught OpenGL error: %s in file %s line %i", s, filename, line);
			ri.Error(ERR_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(glConfig.stereoEnabled)
	{
		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(stereoFrame != STEREO_CENTER)
		{
			ri.Error(ERR_FATAL, "RE_BeginFrame: Stereo is disabled, but stereoFrame was %i", stereoFrame);
		}
		if(!Q_stricmp(r_drawBuffer->string, "GL_FRONT"))
		{
			cmd->buffer = (int)GL_FRONT;
		}
		else
		{
			cmd->buffer = (int)GL_BACK;
		}
	}
#endif
}
Ejemplo n.º 24
0
/*
====================
RE_BeginFrame
====================
*/
void RE_BeginFrame()
{
	drawBufferCommand_t *cmd;

	if ( !tr.registered )
	{
		return;
	}

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

	tr.frameCount++;
	tr.frameSceneNum = 0;
	tr.viewCount = 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 = false;
		}
		else
		{
			R_SyncRenderThread();
			glEnable( GL_STENCIL_TEST );
			glStencilMask( ~0U );
			GL_ClearStencil( 0U );
			glStencilFunc( GL_ALWAYS, 0U, ~0U );
			glStencilOp( GL_KEEP, GL_INCR, GL_INCR );
		}

		r_measureOverdraw->modified = false;
	}
	else
	{
		// this is only reached if it was on and is now off
		if ( r_measureOverdraw->modified )
		{
			R_SyncRenderThread();
			glDisable( GL_STENCIL_TEST );
		}

		r_measureOverdraw->modified = false;
	}

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

	// check for errors
	if ( !r_ignoreGLErrors->integer )
	{
		int  err;
		char s[ 128 ];

		R_SyncRenderThread();

		if ( ( err = glGetError() ) != GL_NO_ERROR )
		{
			switch ( err )
			{
				case GL_INVALID_ENUM:
					strcpy( s, "GL_INVALID_ENUM" );
					break;

				case GL_INVALID_VALUE:
					strcpy( s, "GL_INVALID_VALUE" );
					break;

				case GL_INVALID_OPERATION:
					strcpy( s, "GL_INVALID_OPERATION" );
					break;

				case GL_STACK_OVERFLOW:
					strcpy( s, "GL_STACK_OVERFLOW" );
					break;

				case GL_STACK_UNDERFLOW:
					strcpy( s, "GL_STACK_UNDERFLOW" );
					break;

				case GL_OUT_OF_MEMORY:
					strcpy( s, "GL_OUT_OF_MEMORY" );
					break;

				case GL_TABLE_TOO_LARGE:
					strcpy( s, "GL_TABLE_TOO_LARGE" );
					break;

				case GL_INVALID_FRAMEBUFFER_OPERATION:
					strcpy( s, "GL_INVALID_FRAMEBUFFER_OPERATION" );
					break;

				default:
					Com_sprintf( s, sizeof( s ), "0x%X", err );
					break;
			}

			//ri.Error(ERR_FATAL, "caught OpenGL error: %s in file %s line %i", s, filename, line);
			ri.Error( ERR_FATAL, "RE_BeginFrame() - glGetError() failed (%s)!", 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;
	}
}