コード例 #1
0
ファイル: r_backend.c プロジェクト: DenMSC/qfusion
/*
* RB_BindVBO
*/
void RB_BindVBO( int id, int primitive )
{
    mesh_vbo_t *vbo;

    rb.primitive = primitive;

    if( id < RB_VBO_NONE ) {
        vbo = rb.dynamicStreams[-id - 1].vbo;
    }
    else if( id == RB_VBO_NONE ) {
        vbo = NULL;
    }
    else {
        vbo = R_GetVBOByIndex( id );
    }

    rb.currentVBOId = id;
    rb.currentVBO = vbo;
    if( !vbo ) {
        RB_BindArrayBuffer( 0 );
        RB_BindElementArrayBuffer( 0 );
        return;
    }

    RB_BindArrayBuffer( vbo->vertexId );
    RB_BindElementArrayBuffer( vbo->elemId );
}
コード例 #2
0
/*
* RB_BindVBO
*/
void RB_BindVBO( int id, int primitive )
{
	mesh_vbo_t *vbo;
	vboSlice_t *batch;

	if( rb.currentVBOId == id ) {
		return;
	}

	if( id < RB_VBO_NONE ) {
		vbo = rb.streamVBOs[-id - 1];
		batch = &rb.batches[-id - 1];
	} else if( id == RB_VBO_NONE ) {
		vbo = NULL;
		batch = NULL;
	}
	else {
		vbo = R_GetVBOByIndex( id );
		batch = NULL;
	}

	rb.primitive = primitive;
	rb.currentVBOId = id;
	rb.currentVBO = vbo;
	rb.currentBatch = batch;
	if( !vbo ) {
		RB_BindArrayBuffer( 0 );
		RB_BindElementArrayBuffer( 0 );
		return;
	}

	RB_BindArrayBuffer( vbo->vertexId );
	RB_BindElementArrayBuffer( vbo->elemId );
}
コード例 #3
0
ファイル: r_vbo.c プロジェクト: ewirch/qfusion
/*
* R_UploadVBOElemData
*
* Upload elements into the buffer, properly offsetting them (batching)
*/
void R_UploadVBOElemData( mesh_vbo_t *vbo, int vertsOffset, int elemsOffset, 
	const mesh_t *mesh, vbo_hint_t hint )
{
	int i;
	elem_t *ielems;

	assert( vbo != NULL );

	if( !vbo->elemId )
		return;

	if( hint == VBO_HINT_ELEMS_QUAD ) {
		R_UploadVBOElemQuadData( vbo, vertsOffset, elemsOffset, mesh->numVerts );
		return;
	}
	if( hint == VBO_HINT_ELEMS_TRIFAN ) {
		R_UploadVBOElemTrifanData( vbo, vertsOffset, elemsOffset, mesh->numVerts );
		return;
	}


	ielems = R_VBOElemBuffer( mesh->numElems );
	for( i = 0; i < mesh->numElems; i++ ) {
		ielems[i] = vertsOffset + mesh->elems[i];
	}

	RB_BindElementArrayBuffer( vbo->elemId );
	qglBufferSubDataARB( GL_ELEMENT_ARRAY_BUFFER_ARB, elemsOffset * sizeof( elem_t ), 
		mesh->numElems * sizeof( elem_t ), ielems );
}
コード例 #4
0
ファイル: r_vbo.c プロジェクト: ewirch/qfusion
/*
* R_DiscardVBOElemData
*/
void R_DiscardVBOElemData( mesh_vbo_t *vbo )
{
	GLenum elem_usage = VBO_ELEM_USAGE_FOR_TAG(vbo->tag);

	if( vbo->elemId ) {
		RB_BindElementArrayBuffer( vbo->elemId );
		qglBufferDataARB( GL_ELEMENT_ARRAY_BUFFER_ARB, vbo->elemBufferSize, NULL, elem_usage );
	}
}
コード例 #5
0
ファイル: r_vbo.c プロジェクト: ewirch/qfusion
/*
* R_UploadVBOElemTrifanData
*
* Builds and uploads indexes in trifan order, properly offsetting them for batching
*/
static int R_UploadVBOElemTrifanData( mesh_vbo_t *vbo, int vertsOffset, int elemsOffset, int numVerts )
{
	int numElems;
	elem_t *ielems;

	assert( vbo != NULL );

	if( !vbo->elemId )
		return 0;

	numElems = (numVerts - 2) * 3;
	ielems = R_VBOElemBuffer( numElems );

	R_BuildTrifanElements( vertsOffset, numVerts, ielems );

	RB_BindElementArrayBuffer( vbo->elemId );
	qglBufferSubDataARB( GL_ELEMENT_ARRAY_BUFFER_ARB, elemsOffset * sizeof( elem_t ), 
		numElems * sizeof( elem_t ), ielems );

	return numElems;
}
コード例 #6
0
ファイル: r_vbo.c プロジェクト: ewirch/qfusion
/*
* R_CreateMeshVBO
*
* Create two static buffer objects: vertex buffer and elements buffer, the real
* data is uploaded by calling R_UploadVBOVertexData and R_UploadVBOElemData.
*
* Tag allows vertex buffer objects to be grouped and released simultaneously.
*/
mesh_vbo_t *R_CreateMeshVBO( void *owner, int numVerts, int numElems, int numInstances,
	vattribmask_t vattribs, vbo_tag_t tag, vattribmask_t halfFloatVattribs )
{
	int i;
	size_t size;
	GLuint vbo_id;
	vbohandle_t *vboh = NULL;
	mesh_vbo_t *vbo = NULL;
	GLenum array_usage = VBO_ARRAY_USAGE_FOR_TAG(tag);
	GLenum elem_usage = VBO_ELEM_USAGE_FOR_TAG(tag);
	size_t vertexSize;
	vattribbit_t lmattrbit;

	if( !glConfig.ext.vertex_buffer_object )
		return NULL;

	if( !r_free_vbohandles )
		return NULL;

	if( !glConfig.ext.half_float_vertex ) {
		halfFloatVattribs = 0;
	}
	else {
		if( !(halfFloatVattribs & VATTRIB_POSITION_BIT) ) {
			halfFloatVattribs &= ~(VATTRIB_AUTOSPRITE_BIT);
		}

		halfFloatVattribs &= ~VATTRIB_COLORS_BITS;
		halfFloatVattribs &= ~VATTRIB_BONES_BITS;

		// TODO: convert quaternion component of instance_t to half-float
		// when uploading instances data
		halfFloatVattribs &= ~VATTRIB_INSTANCES_BITS;
	}

	vboh = r_free_vbohandles;
	vbo = &r_mesh_vbo[vboh->index];
	memset( vbo, 0, sizeof( *vbo ) );

	// vertex data
	vertexSize = 0;

	vertexSize += FLOAT_VATTRIB_SIZE(VATTRIB_POSITION_BIT, halfFloatVattribs) * 4;

	// normals data
	if( vattribs & VATTRIB_NORMAL_BIT )
	{
		assert( !(vertexSize & 3) );
		vbo->normalsOffset = vertexSize;
		vertexSize += FLOAT_VATTRIB_SIZE(VATTRIB_NORMAL_BIT, halfFloatVattribs) * 4;
	}

	// s-vectors (tangent vectors)
	if( vattribs & VATTRIB_SVECTOR_BIT )
	{
		assert( !(vertexSize & 3) );
		vbo->sVectorsOffset = vertexSize;
		vertexSize += FLOAT_VATTRIB_SIZE(VATTRIB_SVECTOR_BIT, halfFloatVattribs) * 4;
	}

	// texture coordinates
	if( vattribs & VATTRIB_TEXCOORDS_BIT )
	{
		assert( !(vertexSize & 3) );
		vbo->stOffset = vertexSize;
		vertexSize += FLOAT_VATTRIB_SIZE(VATTRIB_TEXCOORDS_BIT, halfFloatVattribs) * 2;
	}

	// lightmap texture coordinates
	lmattrbit = VATTRIB_LMCOORDS0_BIT;
	for( i = 0; i < MAX_LIGHTMAPS/2; i++ ) {
		if( !(vattribs & lmattrbit) ) {
			break;
		}
		assert( !(vertexSize & 3) );
		vbo->lmstOffset[i] = vertexSize;
		vbo->lmstSize[i] = vattribs & VATTRIB_LMCOORDS0_BIT<<1 ? 4 : 2;
		vertexSize += FLOAT_VATTRIB_SIZE(VATTRIB_LMCOORDS0_BIT, halfFloatVattribs) * vbo->lmstSize[i];
		lmattrbit = ( vattribbit_t )( ( vattribmask_t )lmattrbit << 2 );
	}

	// vertex colors
	if( vattribs & VATTRIB_COLOR0_BIT )
	{
		assert( !(vertexSize & 3) );
		vbo->colorsOffset[0] = vertexSize;
		vertexSize += sizeof( int );
	}

	// bones data for skeletal animation
	if( (vattribs & VATTRIB_BONES_BITS) == VATTRIB_BONES_BITS ) {
		assert( SKM_MAX_WEIGHTS == 4 );

		assert( !(vertexSize & 3) );
		vbo->bonesIndicesOffset = vertexSize;
		vertexSize += sizeof( int );

		assert( !(vertexSize & 3) );
		vbo->bonesWeightsOffset = vertexSize;
		vertexSize += sizeof( int );
	}

	// autosprites
	// FIXME: autosprite2 requires waaaay too much data for such a trivial
	// transformation..
	if( (vattribs & VATTRIB_AUTOSPRITE_BIT) == VATTRIB_AUTOSPRITE_BIT ) {
		assert( !(vertexSize & 3) );
		vbo->spritePointsOffset = vertexSize;
		vertexSize += FLOAT_VATTRIB_SIZE(VATTRIB_AUTOSPRITE_BIT, halfFloatVattribs) * 4;
	}

	size = vertexSize * numVerts;


	// instances data
	if( ( (vattribs & VATTRIB_INSTANCES_BITS) == VATTRIB_INSTANCES_BITS ) && 
		numInstances && glConfig.ext.instanced_arrays ) {
		assert( !(vertexSize & 3) );
		vbo->instancesOffset = size;
		size += numInstances * sizeof( GLfloat ) * 8;
	}

	// pre-allocate vertex buffer
	vbo_id = 0;
	qglGenBuffersARB( 1, &vbo_id );
	if( !vbo_id )
		goto error;
	vbo->vertexId = vbo_id;

	RB_BindArrayBuffer( vbo->vertexId );
	qglBufferDataARB( GL_ARRAY_BUFFER_ARB, size, NULL, array_usage );
	if( qglGetError () == GL_OUT_OF_MEMORY )
		goto error;

	vbo->arrayBufferSize = size;

	// pre-allocate elements buffer
	vbo_id = 0;
	qglGenBuffersARB( 1, &vbo_id );
	if( !vbo_id )
		goto error;
	vbo->elemId = vbo_id;

	size = numElems * sizeof( elem_t );
	RB_BindElementArrayBuffer( vbo->elemId );
	qglBufferDataARB( GL_ELEMENT_ARRAY_BUFFER_ARB, size, NULL, elem_usage );
	if( qglGetError () == GL_OUT_OF_MEMORY )
		goto error;

	vbo->elemBufferSize = size;

	r_free_vbohandles = vboh->next;

	// link to the list of active vbo handles
	vboh->prev = &r_vbohandles_headnode;
	vboh->next = r_vbohandles_headnode.next;
	vboh->next->prev = vboh;
	vboh->prev->next = vboh;

	r_num_active_vbos++;

	vbo->registrationSequence = rsh.registrationSequence;
	vbo->vertexSize = vertexSize;
	vbo->numVerts = numVerts;
	vbo->numElems = numElems;
	vbo->owner = owner;
	vbo->index = vboh->index + 1;
	vbo->tag = tag;
	vbo->halfFloatAttribs = halfFloatVattribs;

	return vbo;

error:
	if( vbo )
		R_ReleaseMeshVBO( vbo );

	RB_BindArrayBuffer( 0 );
	RB_BindElementArrayBuffer( 0 );

	return NULL;
}