Beispiel #1
0
/*
==============
Tess_CheckVBOAndIBO
==============
*/
static void Tess_CheckVBOAndIBO( VBO_t *vbo, IBO_t *ibo )
{
	if ( glState.currentVBO != vbo || glState.currentIBO != ibo || tess.multiDrawPrimitives >= MAX_MULTIDRAW_PRIMITIVES )
	{
		Tess_EndBegin();

		R_BindVBO( vbo );
		R_BindIBO( ibo );
	}
}
Beispiel #2
0
/*
============
R_CreateVBO
============
*/
VBO_t *R_CreateStaticVBO( const char *name, vboData_t data, vboLayout_t layout )
{
	VBO_t *vbo;
	byte *outData;

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

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

	vbo = (VBO_t*) ri.Hunk_Alloc( sizeof( *vbo ), h_low );
	memset( vbo, 0, sizeof( *vbo ) );

	Com_AddToGrowList( &tr.vbos, vbo );

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

	vbo->layout = layout;
	vbo->vertexesNum = data.numVerts;
	vbo->framesNum = data.numFrames;
	vbo->attribBits = R_DeriveAttrBits( data );
	vbo->usage = GL_STATIC_DRAW;

	R_SetVBOAttributeLayouts( vbo );

	glGenBuffers( 1, &vbo->vertexesVBO );
	R_BindVBO( vbo );

#ifdef GLEW_ARB_buffer_storage
	if( glConfig2.bufferStorageAvailable ) {
		outData = (byte *)ri.Hunk_AllocateTempMemory( vbo->vertexesSize );
		R_CopyVertexData( vbo, outData, data );
		glBufferStorage( GL_ARRAY_BUFFER, vbo->vertexesSize,
				 outData, 0 );
		ri.Hunk_FreeTempMemory( outData );
	} else
#endif
	{
		glBufferData( GL_ARRAY_BUFFER, vbo->vertexesSize, nullptr, vbo->usage );
		outData = (byte *)glMapBuffer( GL_ARRAY_BUFFER, GL_WRITE_ONLY );
		R_CopyVertexData( vbo, outData, data );
		glUnmapBuffer( GL_ARRAY_BUFFER );
	}

	R_BindNullVBO();

	GL_CheckErrors();

	return vbo;
}
Beispiel #3
0
VBO_t *R_CreateDynamicVBO( const char *name, int numVertexes, uint32_t stateBits, vboLayout_t layout )
{
	VBO_t *vbo;

	if ( !numVertexes )
	{
		return nullptr;
	}

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

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

	vbo = (VBO_t*) ri.Hunk_Alloc( sizeof( *vbo ), h_low );
	memset( vbo, 0, sizeof( *vbo ) );

	Com_AddToGrowList( &tr.vbos, vbo );

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

	vbo->layout = layout;
	vbo->framesNum = 0;
	vbo->vertexesNum = numVertexes;
	vbo->attribBits = stateBits;
	vbo->usage = GL_DYNAMIC_DRAW;

	R_SetVBOAttributeLayouts( vbo );

	glGenBuffers( 1, &vbo->vertexesVBO );

	R_BindVBO( vbo );

#if defined( GLEW_ARB_buffer_storage ) && defined( GLEW_ARB_sync )
	if( glConfig2.bufferStorageAvailable &&
	    glConfig2.syncAvailable ) {
		R_InitRingbuffer( GL_ARRAY_BUFFER, sizeof( shaderVertex_t ),
				  numVertexes, &tess.vertexRB );
	} else
#endif
	{
		glBufferData( GL_ARRAY_BUFFER, vbo->vertexesSize, nullptr, vbo->usage );
	}
	R_BindNullVBO();

	GL_CheckErrors();

	return vbo;
}
Beispiel #4
0
/*
============
R_CreateVBO2
============
*/
VBO_t *R_CreateStaticVBO2( const char *name, int numVertexes, shaderVertex_t *verts, unsigned int stateBits )
{
	VBO_t  *vbo;

	if ( !numVertexes )
	{
		return nullptr;
	}

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

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

	vbo = ( VBO_t * ) ri.Hunk_Alloc( sizeof( *vbo ), h_low );
	memset( vbo, 0, sizeof( *vbo ) );

	Com_AddToGrowList( &tr.vbos, vbo );

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

	vbo->layout = VBO_LAYOUT_STATIC;
	vbo->framesNum = 0;
	vbo->vertexesNum = numVertexes;
	vbo->attribBits = stateBits;
	vbo->usage = GL_STATIC_DRAW;

	R_SetVBOAttributeLayouts( vbo );
	
	glGenBuffers( 1, &vbo->vertexesVBO );
	R_BindVBO( vbo );

#ifdef GLEW_ARB_buffer_storage
	if( glConfig2.bufferStorageAvailable ) {
		glBufferStorage( GL_ARRAY_BUFFER, vbo->vertexesSize,
				 verts, 0 );
	} else
#endif
	{
		glBufferData( GL_ARRAY_BUFFER, vbo->vertexesSize,
			      verts, vbo->usage );
	}

	R_BindNullVBO();
	GL_CheckErrors();

	return vbo;
}
Beispiel #5
0
/*
==============
Tess_SurfaceVBOMD5Mesh
==============
*/
static void Tess_SurfaceVBOMD5Mesh( srfVBOMD5Mesh_t *srf )
{
	int        i;
	md5Model_t *model;

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

	if ( !srf->vbo || !srf->ibo )
	{
		return;
	}

	Tess_EndBegin();

	R_BindVBO( srf->vbo );
	R_BindIBO( srf->ibo );

	tess.numIndexes = srf->numIndexes;
	tess.numVertexes = srf->numVerts;

	model = srf->md5Model;

	tess.vboVertexSkinning = true;
	tess.numBones = srf->numBoneRemap;

	for ( i = 0; i < srf->numBoneRemap; i++ )
	{
		refBone_t *bone = &backEnd.currentEntity->e.skeleton.bones[ srf->boneRemapInverse[ i ] ];

		if ( backEnd.currentEntity->e.skeleton.type == SK_ABSOLUTE )
		{
			TransInitRotationQuat( model->bones[ srf->boneRemapInverse[ i ] ].rotation, &tess.bones[ i ] );
			TransAddTranslation( model->bones[ srf->boneRemapInverse[ i ] ].origin, &tess.bones[ i ] );
			TransInverse( &tess.bones[ i ], &tess.bones[ i ] );
			TransCombine( &tess.bones[ i ], &bone->t, &tess.bones[ i ] );
		} else {
			TransInit( &tess.bones[ i ] );
		}
		TransAddScale( backEnd.currentEntity->e.skeleton.scale, &tess.bones[ i ] );
		TransInsScale( model->internalScale, &tess.bones[ i ] );
	}

	Tess_End();
}
Beispiel #6
0
/*
==============
Tess_SurfaceVBOMDVMesh
==============
*/
void Tess_SurfaceVBOMDVMesh( srfVBOMDVMesh_t *surface )
{
	refEntity_t *refEnt;

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

	if ( !surface->vbo || !surface->ibo )
	{
		return;
	}

	Tess_EndBegin();

	R_BindVBO( surface->vbo );
	R_BindIBO( surface->ibo );

	tess.numIndexes = surface->numIndexes;
	tess.numVertexes = surface->numVerts;
	tess.vboVertexAnimation = true;

	refEnt = &backEnd.currentEntity->e;

	if ( refEnt->oldframe == refEnt->frame )
	{
		glState.vertexAttribsInterpolation = 0;
	}
	else
	{
		glState.vertexAttribsInterpolation = ( 1.0 - refEnt->backlerp );
	}

	glState.vertexAttribsOldFrame = refEnt->oldframe;
	glState.vertexAttribsNewFrame = refEnt->frame;

	Tess_End();
}
Beispiel #7
0
/*
================
Tess_StageIteratorSky

All of the visible sky triangles are in tess

Other things could be stuck in here, like birds in the sky, etc
================
*/
void Tess_StageIteratorSky( void )
{
	// log this call
	if ( r_logFile->integer )
	{
		// don't just call LogComment, or we will get
		// a call to va() every frame!
		GLimp_LogComment( va
		                  ( "--- Tess_StageIteratorSky( %s, %i vertices, %i triangles ) ---\n", tess.surfaceShader->name,
		                    tess.numVertexes, tess.numIndexes / 3 ) );
	}

	if ( r_fastsky->integer )
	{
		return;
	}

	// trebor: HACK why does this happen with cg_draw2D 0 ?
	if ( tess.stageIteratorFunc2 == NULL )
	{
		//tess.stageIteratorFunc2 = Tess_StageIteratorGeneric;
		ri.Error( ERR_FATAL, "tess.stageIteratorFunc == NULL" );
	}

	GL_Cull(CT_TWO_SIDED);

	if ( tess.stageIteratorFunc2 == &Tess_StageIteratorDepthFill )
	{
		// go through all the polygons and project them onto
		// the sky box to see which blocks on each side need
		// to be drawn
		Tess_ClipSkyPolygons();

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

		if ( tess.numVertexes || tess.multiDrawPrimitives )
		{
			tess.stageIteratorFunc2();
		}
	}
	else
	{
		if ( tess.stageIteratorFunc2 == &Tess_StageIteratorGBuffer )
		{
			R_BindFBO( tr.geometricRenderFBO );
		}

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

		// r_showSky will let all the sky blocks be drawn in
		// front of everything to allow developers to see how
		// much sky is getting sucked in

		if ( r_showSky->integer )
		{
			glDepthRange( 0.0, 0.0 );
		}
		else
		{
			glDepthRange( 1.0, 1.0 );
		}

		// draw the outer skybox
		if ( tess.surfaceShader->sky.outerbox && tess.surfaceShader->sky.outerbox != tr.blackCubeImage )
		{
#if 1
			R_BindVBO( tess.vbo );
			R_BindIBO( tess.ibo );

			gl_skyboxShader->BindProgram();

			gl_skyboxShader->SetUniform_ViewOrigin( backEnd.viewParms.orientation.origin );  // in world space

			gl_skyboxShader->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix );
			gl_skyboxShader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] );

			gl_skyboxShader->SetRequiredVertexPointers();

			// bind u_ColorMap
			GL_SelectTexture( 0 );
			GL_Bind( tess.surfaceShader->sky.outerbox );

			DrawSkyBox( tess.surfaceShader );
#endif
		}

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

		if ( tess.numVertexes || tess.multiDrawPrimitives )
		{
			tess.stageIteratorFunc2();
		}

		// Tr3B: TODO draw the inner skybox?

		if ( tess.stageIteratorFunc2 == Tess_StageIteratorGBuffer )
		{
			R_BindNullFBO();
		}

		if ( tess.stageIteratorFunc2 != Tess_StageIteratorDepthFill )
		{
			// back to standard depth range
			glDepthRange( 0.0, 1.0 );

			// note that sky was drawn so we will draw a sun later
			backEnd.skyRenderedThisView = qtrue;
		}
	}
}
Beispiel #8
0
/*
==============
RB_UpdateVBOs

Adapted from Tess_UpdateVBOs from xreal

Update the default VBO to replace the client side vertex arrays
==============
*/
void RB_UpdateVBOs(unsigned int attribBits)
{
	GLimp_LogComment("--- RB_UpdateVBOs ---\n");

	backEnd.pc.c_dynamicVboDraws++;

	// update the default VBO
	if(tess.numVertexes > 0 && tess.numVertexes <= SHADER_MAX_VERTEXES)
	{
		R_BindVBO(tess.vbo);

		// orphan old buffer so we don't stall on it
		qglBufferDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->vertexesSize, NULL, GL_DYNAMIC_DRAW_ARB);

		if(attribBits & ATTR_BITS)
		{
			if(attribBits & ATTR_POSITION)
			{
				//ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_xyz, tess.numVertexes * sizeof(tess.xyz[0]));
				qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_xyz,         tess.numVertexes * sizeof(tess.xyz[0]),              tess.xyz);
			}

			if(attribBits & ATTR_TEXCOORD || attribBits & ATTR_LIGHTCOORD)
			{
				// these are interleaved, so we update both if either need it
				//ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_st, tess.numVertexes * sizeof(tess.texCoords[0][0]) * 2);
				qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_st,          tess.numVertexes * sizeof(tess.texCoords[0][0]) * 2, tess.texCoords);
			}

			if(attribBits & ATTR_NORMAL)
			{
				//ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_normal, tess.numVertexes * sizeof(tess.normal[0]));
				qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_normal,      tess.numVertexes * sizeof(tess.normal[0]),           tess.normal);
			}

#ifdef USE_VERT_TANGENT_SPACE
			if(attribBits & ATTR_TANGENT)
			{
				//ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_tangent, tess.numVertexes * sizeof(tess.tangent[0]));
				qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_tangent,     tess.numVertexes * sizeof(tess.tangent[0]),          tess.tangent);
			}
#endif

			if(attribBits & ATTR_COLOR)
			{
				//ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_vertexcolor, tess.numVertexes * sizeof(tess.vertexColors[0]));
				qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_vertexcolor, tess.numVertexes * sizeof(tess.vertexColors[0]),     tess.vertexColors);
			}

			if(attribBits & ATTR_LIGHTDIRECTION)
			{
				//ri.Printf(PRINT_ALL, "offset %d, size %d\n", tess.vbo->ofs_lightdir, tess.numVertexes * sizeof(tess.lightdir[0]));
				qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_lightdir,    tess.numVertexes * sizeof(tess.lightdir[0]),         tess.lightdir);
			}
		}
		else
		{
			qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_xyz,         tess.numVertexes * sizeof(tess.xyz[0]),              tess.xyz);
			qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_st,          tess.numVertexes * sizeof(tess.texCoords[0][0]) * 2, tess.texCoords);
			qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_normal,      tess.numVertexes * sizeof(tess.normal[0]),           tess.normal);
#ifdef USE_VERT_TANGENT_SPACE
			qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_tangent,     tess.numVertexes * sizeof(tess.tangent[0]),          tess.tangent);
#endif
			qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_vertexcolor, tess.numVertexes * sizeof(tess.vertexColors[0]),     tess.vertexColors);
			qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_lightdir,    tess.numVertexes * sizeof(tess.lightdir[0]),         tess.lightdir);
		}

	}

	// update the default IBO
	if(tess.numIndexes > 0 && tess.numIndexes <= SHADER_MAX_INDEXES)
	{
		R_BindIBO(tess.ibo);

		// orphan old buffer so we don't stall on it
		qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, tess.ibo->indexesSize, NULL, GL_DYNAMIC_DRAW_ARB);

		qglBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, tess.numIndexes * sizeof(tess.indexes[0]), tess.indexes);
	}
}
Beispiel #9
0
/*
=================
Tess_SurfaceIQM

Compute vertices for this model surface
=================
*/
void Tess_SurfaceIQM( srfIQModel_t *surf ) {
	IQModel_t       *model = surf->data;
	int             i, j;
	int             offset = tess.numVertexes - surf->first_vertex;

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

	Tess_CheckOverflow( surf->num_vertexes, surf->num_triangles * 3 );

	// compute bones
	for ( i = 0; i < model->num_joints; i++ )
	{

		if ( backEnd.currentEntity->e.skeleton.type == SK_ABSOLUTE )
		{
			refBone_t *bone = &backEnd.currentEntity->e.skeleton.bones[ i ];

			TransInverse( &model->joints[ i ], &bones[ i ] );
			TransCombine( &bones[ i ], &bone->t, &bones[ i ] );
		}
		else
		{
			TransInit( &bones[ i ] );
		}
		TransAddScale( backEnd.currentEntity->e.skeleton.scale, &bones[ i ] );
		TransInsScale( model->internalScale, &bones[ i ] );
	}

	if( surf->vbo && surf->ibo ) {
		if( model->num_joints > 0 ) {
			Com_Memcpy( tess.bones, bones, model->num_joints * sizeof(transform_t) );
			tess.numBones = model->num_joints;
		} else {
			TransInitScale( model->internalScale * backEnd.currentEntity->e.skeleton.scale, &tess.bones[ 0 ] );
			tess.numBones = 1;
		}
		R_BindVBO( surf->vbo );
		R_BindIBO( surf->ibo );
		tess.vboVertexSkinning = true;

		tess.multiDrawIndexes[ tess.multiDrawPrimitives ] = ((glIndex_t *)nullptr) + surf->first_triangle * 3;
		tess.multiDrawCounts[ tess.multiDrawPrimitives ] = surf->num_triangles * 3;
		tess.multiDrawPrimitives++;

		Tess_End();
		return;
	}

	for ( i = 0; i < surf->num_triangles; i++ )
	{
		tess.indexes[ tess.numIndexes + i * 3 + 0 ] = offset + model->triangles[ 3 * ( surf->first_triangle + i ) + 0 ];
		tess.indexes[ tess.numIndexes + i * 3 + 1 ] = offset + model->triangles[ 3 * ( surf->first_triangle + i ) + 1 ];
		tess.indexes[ tess.numIndexes + i * 3 + 2 ] = offset + model->triangles[ 3 * ( surf->first_triangle + i ) + 2 ];
	}

	tess.attribsSet |= ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT;

	if( model->num_joints > 0 && model->blendWeights && model->blendIndexes ) {
		// deform the vertices by the lerped bones
		for ( i = 0; i < surf->num_vertexes; i++ )
		{
			int    idxIn = surf->first_vertex + i;
			int    idxOut = tess.numVertexes + i;
			const float weightFactor = 1.0f / 255.0f;
			vec3_t tangent, binormal, normal, tmp;

			if( model->blendWeights[ 4 * idxIn + 0 ] == 0 &&
			    model->blendWeights[ 4 * idxIn + 1 ] == 0 &&
			    model->blendWeights[ 4 * idxIn + 2 ] == 0 &&
			    model->blendWeights[ 4 * idxIn + 3 ] == 0 )
				model->blendWeights[ 4 * idxIn + 0 ] = 255;

			VectorClear( tess.verts[ idxOut ].xyz );
			VectorClear( normal );
			VectorClear( tangent );
			VectorClear( binormal );
			for ( j = 0; j < 4; j++ ) {
				int bone = model->blendIndexes[ 4 * idxIn + j ];
				float weight = weightFactor * model->blendWeights[ 4 * idxIn + j ];

				TransformPoint( &bones[ bone ],
						&model->positions[ 3 * idxIn ], tmp );
				VectorMA( tess.verts[ idxOut ].xyz, weight, tmp,
					  tess.verts[ idxOut ].xyz );

				TransformNormalVector( &bones[ bone ],
						       &model->normals[ 3 * idxIn ], tmp );
				VectorMA( normal, weight, tmp, normal );
				TransformNormalVector( &bones[ bone ],
						       &model->tangents[ 3 * idxIn ], tmp );
				VectorMA( tangent, weight, tmp, tangent );
				TransformNormalVector( &bones[ bone ],
						       &model->bitangents[ 3 * idxIn ], tmp );
				VectorMA( binormal, weight, tmp, binormal );
			}
			VectorNormalize( normal );
			VectorNormalize( tangent );
			VectorNormalize( binormal );

			R_TBNtoQtangents( tangent, binormal, normal, tess.verts[ idxOut ].qtangents );

			tess.verts[ idxOut ].texCoords[ 0 ] = model->texcoords[ 2 * idxIn + 0 ];
			tess.verts[ idxOut ].texCoords[ 1 ] = model->texcoords[ 2 * idxIn + 1 ];
		}
	} else {
		for ( i = 0; i < surf->num_vertexes; i++ )
		{
			int    idxIn = surf->first_vertex + i;
			int    idxOut = tess.numVertexes + i;
			float  scale = model->internalScale * backEnd.currentEntity->e.skeleton.scale;

			VectorScale( &model->positions[ 3 * idxIn ], scale, tess.verts[ idxOut ].xyz );
			R_TBNtoQtangents( &model->tangents[ 3 * idxIn ],
					  &model->bitangents[ 3 * idxIn ],
					  &model->normals[ 3 * idxIn ],
					  tess.verts[ idxOut ].qtangents );

			tess.verts[ idxOut ].texCoords[ 0 ] = model->texcoords[ 2 * idxIn + 0 ];
			tess.verts[ idxOut ].texCoords[ 1 ] = model->texcoords[ 2 * idxIn + 1 ];
		}
	}

	tess.numIndexes  += 3 * surf->num_triangles;
	tess.numVertexes += surf->num_vertexes;
}
Beispiel #10
0
/*
============
R_ShutdownVBOs
============
*/
void R_ShutdownVBOs()
{
	int   i;
	VBO_t *vbo;
	IBO_t *ibo;

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

	if( !glConfig2.mapBufferRangeAvailable ) {
		// nothing
	}
#if defined( GLEW_ARB_buffer_storage ) && defined( GLEW_ARB_sync )
	else if( glConfig2.bufferStorageAvailable &&
		 glConfig2.syncAvailable ) {
		R_BindVBO( tess.vbo );
		R_ShutdownRingbuffer( GL_ARRAY_BUFFER, &tess.vertexRB );
		R_BindIBO( tess.ibo );
		R_ShutdownRingbuffer( GL_ELEMENT_ARRAY_BUFFER, &tess.indexRB );
	}
#endif
	else {
		if( tess.verts != nullptr && tess.verts != tess.vertsBuffer ) {
			R_BindVBO( tess.vbo );
			glUnmapBuffer( GL_ARRAY_BUFFER );
		}

		if( tess.indexes != nullptr && tess.indexes != tess.indexesBuffer ) {
			R_BindIBO( tess.ibo );
			glUnmapBuffer( GL_ELEMENT_ARRAY_BUFFER );
		}
	}

	R_BindNullVBO();
	R_BindNullIBO();

	glDeleteBuffers( 1, &tr.colorGradePBO );

	for ( i = 0; i < tr.vbos.currentElements; i++ )
	{
		vbo = ( VBO_t * ) Com_GrowListElement( &tr.vbos, i );

		if ( vbo->vertexesVBO )
		{
			glDeleteBuffers( 1, &vbo->vertexesVBO );
		}
	}

	for ( i = 0; i < tr.ibos.currentElements; i++ )
	{
		ibo = ( IBO_t * ) Com_GrowListElement( &tr.ibos, i );

		if ( ibo->indexesVBO )
		{
			glDeleteBuffers( 1, &ibo->indexesVBO );
		}
	}

	Com_DestroyGrowList( &tr.vbos );
	Com_DestroyGrowList( &tr.ibos );

	Com_Free_Aligned( tess.vertsBuffer );
	Com_Free_Aligned( tess.indexesBuffer );

	tess.verts = tess.vertsBuffer = nullptr;
	tess.indexes = tess.indexesBuffer = nullptr;
}
Beispiel #11
0
/*
==============
Tess_UpdateVBOs

Tr3B: update the default VBO to replace the client side vertex arrays
==============
*/
void Tess_UpdateVBOs()
{
	GLimp_LogComment( "--- Tess_UpdateVBOs( ) ---\n" );

	GL_CheckErrors();

	// update the default VBO
	if ( tess.numVertexes > 0 && tess.numVertexes <= SHADER_MAX_VERTEXES )
	{
		GLsizei size = tess.numVertexes * sizeof( shaderVertex_t );

		GL_CheckErrors();

		if ( r_logFile->integer )
		{
			GLimp_LogComment( va( "glBufferSubData( vbo = '%s', numVertexes = %i )\n", tess.vbo->name, tess.numVertexes ) );
		}

		if( !glConfig2.mapBufferRangeAvailable ) {
			R_BindVBO( tess.vbo );
			glBufferSubData( GL_ARRAY_BUFFER, 0, size, tess.verts );
		} else {
			R_BindVBO( tess.vbo );
			if( glConfig2.bufferStorageAvailable &&
			    glConfig2.syncAvailable ) {
				GLsizei offset = tess.vertexBase * sizeof( shaderVertex_t );

				glFlushMappedBufferRange( GL_ARRAY_BUFFER,
							  offset, size );
			} else {
				glFlushMappedBufferRange( GL_ARRAY_BUFFER,
							  0, size );
				glUnmapBuffer( GL_ARRAY_BUFFER );
			}
			tess.vertexBase = tess.vertsWritten;
			tess.vertsWritten += tess.numVertexes;

			tess.verts = nullptr;
		}
	}

	GL_CheckErrors();

	// update the default IBO
	if ( tess.numIndexes > 0 && tess.numIndexes <= SHADER_MAX_INDEXES )
	{
		GLsizei size = tess.numIndexes * sizeof( glIndex_t );

		if( !glConfig2.mapBufferRangeAvailable ) {
			R_BindIBO( tess.ibo );
			glBufferSubData( GL_ELEMENT_ARRAY_BUFFER, 0, size,
					 tess.indexes );
		} else {
			R_BindIBO( tess.ibo );

			if( glConfig2.bufferStorageAvailable &&
			    glConfig2.syncAvailable ) {
				GLsizei offset = tess.indexBase * sizeof( glIndex_t );

				glFlushMappedBufferRange( GL_ELEMENT_ARRAY_BUFFER,
							  offset, size );
			} else {
				glFlushMappedBufferRange( GL_ELEMENT_ARRAY_BUFFER,
							  0, size );
				glUnmapBuffer( GL_ELEMENT_ARRAY_BUFFER );
			}
			tess.indexBase = tess.indexesWritten;
			tess.indexesWritten += tess.numIndexes;

			tess.indexes = nullptr;
		}
	}

	GL_CheckErrors();
}
Beispiel #12
0
/*
==============
Tess_MapVBOs

Map the default VBOs
==============
*/
void Tess_MapVBOs( bool forceCPU ) {
	if( forceCPU || !glConfig2.mapBufferRangeAvailable ) {
		// use host buffers
		tess.verts = tess.vertsBuffer;
		tess.indexes = tess.indexesBuffer;

		return;
	}

	if( tess.verts == nullptr ) {
		R_BindVBO( tess.vbo );

#if defined( GLEW_ARB_buffer_storage ) && defined( GL_ARB_sync )
		if( glConfig2.bufferStorageAvailable &&
		    glConfig2.syncAvailable ) {
			GLsizei segmentEnd = (tess.vertexRB.activeSegment + 1) * tess.vertexRB.segmentElements;
			if( tess.vertsWritten + SHADER_MAX_VERTEXES > (unsigned) segmentEnd ) {
				tess.vertsWritten = R_RotateRingbuffer( &tess.vertexRB );
			}
			tess.verts = ( shaderVertex_t * )tess.vertexRB.baseAddr + tess.vertsWritten;
		} else
#endif
		{
			if( vertexCapacity - tess.vertsWritten < SHADER_MAX_VERTEXES ) {
				// buffer is full, allocate a new one
				glBufferData( GL_ARRAY_BUFFER, vertexCapacity * sizeof( shaderVertex_t ), nullptr, GL_DYNAMIC_DRAW );
				tess.vertsWritten = 0;
			}
			tess.verts = ( shaderVertex_t *) glMapBufferRange( 
				GL_ARRAY_BUFFER, tess.vertsWritten * sizeof( shaderVertex_t ),
				SHADER_MAX_VERTEXES * sizeof( shaderVertex_t ),
				GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
				GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_FLUSH_EXPLICIT_BIT );
		}
	}

	if( tess.indexes == nullptr ) {
		R_BindIBO( tess.ibo );

#if defined( GLEW_ARB_buffer_storage ) && defined( GL_ARB_sync )
		if( glConfig2.bufferStorageAvailable &&
		    glConfig2.syncAvailable ) {
			GLsizei segmentEnd = (tess.indexRB.activeSegment + 1) * tess.indexRB.segmentElements;
			if( tess.indexesWritten + SHADER_MAX_INDEXES > (unsigned) segmentEnd ) {
				tess.indexesWritten = R_RotateRingbuffer( &tess.indexRB );
			}
			tess.indexes = ( glIndex_t * )tess.indexRB.baseAddr + tess.indexesWritten;
		} else
#endif
		{
			if( indexCapacity - tess.indexesWritten < SHADER_MAX_INDEXES ) {
				// buffer is full, allocate a new one
				glBufferData( GL_ELEMENT_ARRAY_BUFFER, indexCapacity * sizeof( glIndex_t ), nullptr, GL_DYNAMIC_DRAW );
				tess.indexesWritten = 0;
			}
			tess.indexes = ( glIndex_t *) glMapBufferRange( 
				GL_ELEMENT_ARRAY_BUFFER, tess.indexesWritten * sizeof( glIndex_t ),
				SHADER_MAX_INDEXES * sizeof( glIndex_t ),
				GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
				GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_FLUSH_EXPLICIT_BIT );
		}
	}
}