Beispiel #1
0
/*
* R_UploadVBOVertexData
*
* Uploads required vertex data to the buffer.
*
* Vertex attributes masked by halfFloatVattribs will use half-precision floats
* to save memory, if GL_ARB_half_float_vertex is available. Note that if
* VATTRIB_POSITION_BIT is not set, it will also reset bits for other positional 
* attributes such as autosprite pos and instance pos.
*/
vattribmask_t R_UploadVBOVertexData( mesh_vbo_t *vbo, int vertsOffset, 
	vattribmask_t vattribs, const mesh_t *mesh, vbo_hint_t hint )
{
	int i, j;
	unsigned numVerts;
	size_t vertSize;
	vattribmask_t errMask;
	vattribmask_t hfa;
	qbyte *data;

	assert( vbo != NULL );
	assert( mesh != NULL );

	if( !vbo || !vbo->vertexId ) {
		return 0;
	}

	errMask = 0;
	numVerts = mesh->numVerts;
	vertSize = vbo->vertexSize;

	hfa = vbo->halfFloatAttribs;
	data = R_VBOVertBuffer( numVerts, vertSize );

	RB_BindArrayBuffer( vbo->vertexId );

	// upload vertex xyz data
	if( vattribs & VATTRIB_POSITION_BIT ) {
		if( !mesh->xyzArray ) {
			errMask |= VATTRIB_POSITION_BIT;
		}
		else {
			R_FillVertexBuffer_float_or_half( FLOAT_VATTRIB_GL_TYPE( VATTRIB_POSITION_BIT, hfa ), 
				mesh->xyzArray[0],
				4, vertSize, numVerts, data + 0 );
		}
	}

	// upload normals data
	if( vbo->normalsOffset && (vattribs & VATTRIB_NORMAL_BIT) ) {
		if( !mesh->normalsArray ) {
			errMask |= VATTRIB_NORMAL_BIT;
		} else {
			R_FillVertexBuffer_float_or_half( FLOAT_VATTRIB_GL_TYPE( VATTRIB_NORMAL_BIT, hfa ), 
				mesh->normalsArray[0],
				4, vertSize, numVerts, data + vbo->normalsOffset );
		}
	}
	 
	// upload tangent vectors
	if( vbo->sVectorsOffset && ( ( vattribs & (VATTRIB_SVECTOR_BIT|VATTRIB_AUTOSPRITE2_BIT) ) == VATTRIB_SVECTOR_BIT ) ) {
		if( !mesh->sVectorsArray ) {
			errMask |= VATTRIB_SVECTOR_BIT;
		} else {
			R_FillVertexBuffer_float_or_half( FLOAT_VATTRIB_GL_TYPE( VATTRIB_SVECTOR_BIT, hfa ), 
				mesh->sVectorsArray[0],
				4, vertSize, numVerts, data + vbo->sVectorsOffset );
		}
	}

	// upload texture coordinates
	if( vbo->stOffset && (vattribs & VATTRIB_TEXCOORDS_BIT) ) {
		if( !mesh->stArray ) {
			errMask |= VATTRIB_TEXCOORDS_BIT;
		} else {
			R_FillVertexBuffer_float_or_half( FLOAT_VATTRIB_GL_TYPE( VATTRIB_TEXCOORDS_BIT, hfa ), 
				mesh->stArray[0],
				2, vertSize, numVerts, data + vbo->stOffset );
		}
	}

	// upload lightmap texture coordinates
	if( vbo->lmstOffset[0] && ( vattribs & VATTRIB_LMCOORDS0_BIT ) ) {
		int i;
		vattribbit_t lmattrbit;

		lmattrbit = VATTRIB_LMCOORDS0_BIT;

		for( i = 0; i < MAX_LIGHTMAPS/2; i++ ) {
			if( !(vattribs & lmattrbit) ) {
				break;
			}
			if( !mesh->lmstArray[i*2+0] ) {
				errMask |= lmattrbit;
				break;
			}

			R_FillVertexBuffer_float_or_half( FLOAT_VATTRIB_GL_TYPE( VATTRIB_LMCOORDS0_BIT, hfa ), 
				mesh->lmstArray[i*2+0][0],
				2, vertSize, numVerts, data + vbo->lmstOffset[i] );

			if( vattribs & (lmattrbit<<1) ) {
				if( !mesh->lmstArray[i*2+1] ) {
					errMask |= lmattrbit<<1;
					break;
				}
				R_FillVertexBuffer_float_or_half( FLOAT_VATTRIB_GL_TYPE( VATTRIB_LMCOORDS0_BIT, hfa ), 
					mesh->lmstArray[i*2+1][0],
					2, vertSize, numVerts, data + vbo->lmstOffset[i] + 2 * sizeof( float ) );
			}

			lmattrbit <<= 2;
		}
	}

	// upload vertex colors (although indices > 0 are never used)
	if( vbo->colorsOffset[0] && (vattribs & VATTRIB_COLOR0_BIT) ) {
		if( !mesh->colorsArray[0] ) {
			errMask |= VATTRIB_COLOR0_BIT;
		}
		else {
			R_FillVertexBuffer( int, int, 
				(int *)&mesh->colorsArray[0][0],
				1, vertSize, numVerts, data + vbo->colorsOffset[0] );
		}
	}

	// upload centre and radius for autosprites
	// this code assumes that the mesh has been properly pretransformed
	if( vbo->spritePointsOffset && ( (vattribs & VATTRIB_AUTOSPRITE2_BIT) == VATTRIB_AUTOSPRITE2_BIT ) ) {
		// for autosprite2 also upload vertices that form the longest axis
		// the remaining vertex can be trivially computed in vertex shader
		vec3_t vd[3];
		float d[3];
		int longest_edge = -1, longer_edge = -1, short_edge;
		float longest_dist = 0, longer_dist = 0;
		const int edges[3][2] = { { 1, 0 }, { 2, 0 }, { 2, 1 } };
		vec4_t centre[4];
		vec4_t axes[4];
		vec4_t *verts = mesh->xyzArray;
		elem_t *elems, temp_elems[6];
		int numQuads;
		size_t bufferOffset0 = vbo->spritePointsOffset;
		size_t bufferOffset1 = vbo->sVectorsOffset;

		if( hint == VBO_HINT_ELEMS_QUAD ) {
			numQuads = numVerts / 4;
		}
		else {
			assert( mesh->elems != NULL );
			if( !mesh->elems ) {
				numQuads = 0;
			} else {
				numQuads = mesh->numElems / 6;
			}
		}

		for( i = 0, elems = mesh->elems; i < numQuads; i++, elems += 6 ) {
			if( hint == VBO_HINT_ELEMS_QUAD ) {
				elem_t firstV = i * 4;

				temp_elems[0] = firstV;
				temp_elems[1] = firstV + 2 - 1;
				temp_elems[2] = firstV + 2;

				temp_elems[3] = firstV;
				temp_elems[4] = firstV + 3 - 1;
				temp_elems[5] = firstV + 3;

				elems = temp_elems;
			}

			// find the longest edge, the long edge and the short edge
			longest_edge = longer_edge = -1;
			longest_dist = longer_dist = 0;
			for( j = 0; j < 3; j++ ) {
				float len;

				VectorSubtract( verts[elems[edges[j][0]]], verts[elems[edges[j][1]]], vd[j] );
				len = VectorLength( vd[j] );
				if( !len ) {
					len = 1;
				}
				d[j] = len;

				if( longest_edge == -1 || longest_dist < len ) {
					longer_dist = longest_dist;
					longer_edge = longest_edge;
					longest_dist = len;
					longest_edge = j;
				} else if( longer_dist < len ) {
					longer_dist = len;
					longer_edge = j;
				}
			}

			short_edge = 3 - (longest_edge + longer_edge);
			if( short_edge > 2 ) {
				continue;
			}

			// centre
			VectorAdd( verts[elems[edges[longest_edge][0]]], verts[elems[edges[longest_edge][1]]], centre[0] );
			VectorScale( centre[0], 0.5, centre[0] );
			// radius
			centre[0][3] = d[longest_edge] * 0.5; // unused
			// right axis, normalized
			VectorScale( vd[short_edge], 1.0 / d[short_edge], vd[short_edge] );
			// up axis, normalized
			VectorScale( vd[longer_edge], 1.0 / d[longer_edge], vd[longer_edge] );

			NormToLatLong( vd[short_edge], &axes[0][0] );
			NormToLatLong( vd[longer_edge], &axes[0][2] );

			for( j = 1; j < 4; j++ ) {
				Vector4Copy( centre[0], centre[j] );
				Vector4Copy( axes[0], axes[j] );
			}

			R_FillVertexBuffer_float_or_half( FLOAT_VATTRIB_GL_TYPE( VATTRIB_AUTOSPRITE_BIT, hfa ), 
				centre[0],
				4, vertSize, 4, data + bufferOffset0 );
			R_FillVertexBuffer_float_or_half( FLOAT_VATTRIB_GL_TYPE( VATTRIB_SVECTOR_BIT, hfa ), 
				axes[0],
				4, vertSize, 4, data + bufferOffset1 );

			bufferOffset0 += 4 * vertSize;
			bufferOffset1 += 4 * vertSize;
		}
	}
	else if( vbo->spritePointsOffset && ( (vattribs & VATTRIB_AUTOSPRITE_BIT) == VATTRIB_AUTOSPRITE_BIT ) ) {
		vec4_t *verts;
		vec4_t centre[4];
		int numQuads = numVerts / 4;
		size_t bufferOffset = vbo->spritePointsOffset;

		for( i = 0, verts = mesh->xyzArray; i < numQuads; i++, verts += 4 ) {
			// centre
			for( j = 0; j < 3; j++ ) {
				centre[0][j] = (verts[0][j] + verts[1][j] + verts[2][j] + verts[3][j]) * 0.25;
			}
			// radius
			centre[0][3] = Distance( verts[0], centre[0] ) * 0.707106f;		// 1.0f / sqrt(2)

			for( j = 1; j < 4; j++ ) {
				Vector4Copy( centre[0], centre[j] );
			}

			R_FillVertexBuffer_float_or_half( FLOAT_VATTRIB_GL_TYPE( VATTRIB_AUTOSPRITE_BIT, hfa ), 
				centre[0],
				4, vertSize, 4, data + bufferOffset );

			bufferOffset += 4 * vertSize;
		}
	}

	if( vattribs & VATTRIB_BONES_BITS ) {
		if( vbo->bonesIndicesOffset ) {
			if( !mesh->blendIndices ) {
				errMask |= VATTRIB_BONESINDICES_BIT;
			}
			else {
				R_FillVertexBuffer( int, int, 
					(int *)&mesh->blendIndices[0],
					1, vertSize, numVerts, data + vbo->bonesIndicesOffset );
			}
		}
		if( vbo->bonesWeightsOffset ) {
			if( !mesh->blendWeights ) {
				errMask |= VATTRIB_BONESWEIGHTS_BIT;
			}
			else {
				R_FillVertexBuffer( int, int, 
					(int *)&mesh->blendWeights[0],
					1, vertSize, numVerts, data + vbo->bonesWeightsOffset );
			}
		}
	}

	qglBufferSubDataARB( GL_ARRAY_BUFFER_ARB, vertsOffset * vertSize, numVerts * vertSize, data );

	return errMask;
}
Beispiel #2
0
/*
* RB_EnableVertexAttribs
*/
static void RB_EnableVertexAttribs( void )
{
    vattribmask_t vattribs = rb.currentVAttribs;
    mesh_vbo_t *vbo = rb.currentVBO;
    vattribmask_t hfa = vbo->halfFloatAttribs;

    assert( vattribs & VATTRIB_POSITION_BIT );

    if( ( vattribs == rb.gl.lastVAttribs ) && ( hfa == rb.gl.lastHalfFloatVAttribs ) ) {
        return;
    }

    rb.gl.lastVAttribs = vattribs;
    rb.gl.lastHalfFloatVAttribs = hfa;

    // xyz position
    RB_EnableVertexAttrib( VATTRIB_POSITION, true );
    qglVertexAttribPointerARB( VATTRIB_POSITION, 4, FLOAT_VATTRIB_GL_TYPE( VATTRIB_POSITION_BIT, hfa ),
                               GL_FALSE, vbo->vertexSize, ( const GLvoid * )0 );

    // normal
    if( vattribs & VATTRIB_NORMAL_BIT ) {
        RB_EnableVertexAttrib( VATTRIB_NORMAL, true );
        qglVertexAttribPointerARB( VATTRIB_NORMAL, 4, FLOAT_VATTRIB_GL_TYPE( VATTRIB_NORMAL_BIT, hfa ),
                                   GL_FALSE, vbo->vertexSize, ( const GLvoid * )vbo->normalsOffset );
    }
    else {
        RB_EnableVertexAttrib( VATTRIB_NORMAL, false );
    }

    // s-vector
    if( vattribs & VATTRIB_SVECTOR_BIT ) {
        RB_EnableVertexAttrib( VATTRIB_SVECTOR, true );
        qglVertexAttribPointerARB( VATTRIB_SVECTOR, 4, FLOAT_VATTRIB_GL_TYPE( VATTRIB_SVECTOR_BIT, hfa ),
                                   GL_FALSE, vbo->vertexSize, ( const GLvoid * )vbo->sVectorsOffset );
    }
    else {
        RB_EnableVertexAttrib( VATTRIB_SVECTOR, false );
    }

    // color
    if( vattribs & VATTRIB_COLOR0_BIT ) {
        RB_EnableVertexAttrib( VATTRIB_COLOR0, true );
        qglVertexAttribPointerARB( VATTRIB_COLOR0, 4, GL_UNSIGNED_BYTE,
                                   GL_TRUE, vbo->vertexSize, (const GLvoid * )vbo->colorsOffset[0] );
    }
    else {
        RB_EnableVertexAttrib( VATTRIB_COLOR0, false );
    }

    // texture coordinates
    if( vattribs & VATTRIB_TEXCOORDS_BIT ) {
        RB_EnableVertexAttrib( VATTRIB_TEXCOORDS, true );
        qglVertexAttribPointerARB( VATTRIB_TEXCOORDS, 2, FLOAT_VATTRIB_GL_TYPE( VATTRIB_TEXCOORDS_BIT, hfa ),
                                   GL_FALSE, vbo->vertexSize, ( const GLvoid * )vbo->stOffset );
    }
    else {
        RB_EnableVertexAttrib( VATTRIB_TEXCOORDS, false );
    }

    if( (vattribs & VATTRIB_AUTOSPRITE_BIT) == VATTRIB_AUTOSPRITE_BIT ) {
        // submit sprite point
        RB_EnableVertexAttrib( VATTRIB_SPRITEPOINT, true );
        qglVertexAttribPointerARB( VATTRIB_SPRITEPOINT, 4, FLOAT_VATTRIB_GL_TYPE( VATTRIB_AUTOSPRITE_BIT, hfa ),
                                   GL_FALSE, vbo->vertexSize, ( const GLvoid * )vbo->spritePointsOffset );
    }
    else {
        RB_EnableVertexAttrib( VATTRIB_SPRITEPOINT, false );
    }

    // bones (skeletal models)
    if( (vattribs & VATTRIB_BONES_BITS) == VATTRIB_BONES_BITS ) {
        // submit indices
        RB_EnableVertexAttrib( VATTRIB_BONESINDICES, true );
        qglVertexAttribPointerARB( VATTRIB_BONESINDICES, 4, GL_UNSIGNED_BYTE,
                                   GL_FALSE, vbo->vertexSize, ( const GLvoid * )vbo->bonesIndicesOffset );

        // submit weights
        RB_EnableVertexAttrib( VATTRIB_BONESWEIGHTS, true );
        qglVertexAttribPointerARB( VATTRIB_BONESWEIGHTS, 4, GL_UNSIGNED_BYTE,
                                   GL_TRUE, vbo->vertexSize, ( const GLvoid * )vbo->bonesWeightsOffset );
    }
    else {
        int i;
        vattrib_t lmattr;
        vattribbit_t lmattrbit;

        // lightmap texture coordinates - aliasing bones, so not disabling bones
        lmattr = VATTRIB_LMCOORDS01;
        lmattrbit = VATTRIB_LMCOORDS0_BIT;

        for( i = 0; i < ( MAX_LIGHTMAPS + 1 ) / 2; i++ ) {
            if( vattribs & lmattrbit ) {
                RB_EnableVertexAttrib( lmattr, true );
                qglVertexAttribPointerARB( lmattr, vbo->lmstSize[i],
                                           FLOAT_VATTRIB_GL_TYPE( VATTRIB_LMCOORDS0_BIT, hfa ),
                                           GL_FALSE, vbo->vertexSize, ( const GLvoid * )vbo->lmstOffset[i] );
            }
            else {
                RB_EnableVertexAttrib( lmattr, false );
            }

            lmattr++;
            lmattrbit <<= 2;
        }

        // lightmap array texture layers
        lmattr = VATTRIB_LMLAYERS0123;

        for( i = 0; i < ( MAX_LIGHTMAPS + 3 ) / 4; i++ ) {
            if( vattribs & ( VATTRIB_LMLAYERS0123_BIT << i ) ) {
                RB_EnableVertexAttrib( lmattr, true );
                qglVertexAttribPointerARB( lmattr, 4, GL_UNSIGNED_BYTE,
                                           GL_FALSE, vbo->vertexSize, ( const GLvoid * )vbo->lmlayersOffset[i] );
            }
            else {
                RB_EnableVertexAttrib( lmattr, false );
            }

            lmattr++;
        }
    }

    if( (vattribs & VATTRIB_INSTANCES_BITS) == VATTRIB_INSTANCES_BITS ) {
        RB_EnableVertexAttrib( VATTRIB_INSTANCE_QUAT, true );
        qglVertexAttribPointerARB( VATTRIB_INSTANCE_QUAT, 4, GL_FLOAT, GL_FALSE, 8 * sizeof( vec_t ),
                                   ( const GLvoid * )vbo->instancesOffset );
        qglVertexAttribDivisorARB( VATTRIB_INSTANCE_QUAT, 1 );

        RB_EnableVertexAttrib( VATTRIB_INSTANCE_XYZS, true );
        qglVertexAttribPointerARB( VATTRIB_INSTANCE_XYZS, 4, GL_FLOAT, GL_FALSE, 8 * sizeof( vec_t ),
                                   ( const GLvoid * )( vbo->instancesOffset + sizeof( vec_t ) * 4 ) );
        qglVertexAttribDivisorARB( VATTRIB_INSTANCE_XYZS, 1 );
    } else {
        RB_EnableVertexAttrib( VATTRIB_INSTANCE_QUAT, false );
        RB_EnableVertexAttrib( VATTRIB_INSTANCE_XYZS, false );
    }
}
Beispiel #3
0
/*
* R_FillVBOVertexDataBuffer
*
* Generates required vertex data to be uploaded to the buffer.
*
* Vertex attributes masked by halfFloatVattribs will use half-precision floats
* to save memory, if GL_ARB_half_float_vertex is available. Note that if
* VATTRIB_POSITION_BIT is not set, it will also reset bits for other positional 
* attributes such as autosprite pos and instance pos.
*/
vattribmask_t R_FillVBOVertexDataBuffer( mesh_vbo_t *vbo, vattribmask_t vattribs, const mesh_t *mesh, void *outData )
{
	int i, j;
	unsigned numVerts;
	size_t vertSize;
	vattribmask_t errMask;
	vattribmask_t hfa;
	uint8_t *data = outData;

	assert( vbo != NULL );
	assert( mesh != NULL );

	if( !vbo ) {
		return 0;
	}

	errMask = 0;
	numVerts = mesh->numVerts;
	vertSize = vbo->vertexSize;

	hfa = vbo->halfFloatAttribs;

	// upload vertex xyz data
	if( vattribs & VATTRIB_POSITION_BIT ) {
		if( !mesh->xyzArray ) {
			errMask |= VATTRIB_POSITION_BIT;
		}
		else {
			R_FillVertexBuffer_float_or_half( FLOAT_VATTRIB_GL_TYPE( VATTRIB_POSITION_BIT, hfa ), 
				mesh->xyzArray[0],
				4, vertSize, numVerts, data + 0 );
		}
	}

	// upload normals data
	if( vbo->normalsOffset && (vattribs & VATTRIB_NORMAL_BIT) ) {
		if( !mesh->normalsArray ) {
			errMask |= VATTRIB_NORMAL_BIT;
		} else {
			R_FillVertexBuffer_float_or_half( FLOAT_VATTRIB_GL_TYPE( VATTRIB_NORMAL_BIT, hfa ), 
				mesh->normalsArray[0],
				4, vertSize, numVerts, data + vbo->normalsOffset );
		}
	}
	 
	// upload tangent vectors
	if( vbo->sVectorsOffset && ( ( vattribs & (VATTRIB_SVECTOR_BIT|VATTRIB_AUTOSPRITE2_BIT) ) == VATTRIB_SVECTOR_BIT ) ) {
		if( !mesh->sVectorsArray ) {
			errMask |= VATTRIB_SVECTOR_BIT;
		} else {
			R_FillVertexBuffer_float_or_half( FLOAT_VATTRIB_GL_TYPE( VATTRIB_SVECTOR_BIT, hfa ), 
				mesh->sVectorsArray[0],
				4, vertSize, numVerts, data + vbo->sVectorsOffset );
		}
	}

	// upload texture coordinates
	if( vbo->stOffset && (vattribs & VATTRIB_TEXCOORDS_BIT) ) {
		if( !mesh->stArray ) {
			errMask |= VATTRIB_TEXCOORDS_BIT;
		} else {
			R_FillVertexBuffer_float_or_half( FLOAT_VATTRIB_GL_TYPE( VATTRIB_TEXCOORDS_BIT, hfa ), 
				mesh->stArray[0],
				2, vertSize, numVerts, data + vbo->stOffset );
		}
	}

	// upload lightmap texture coordinates
	if( vbo->lmstOffset[0] && ( vattribs & VATTRIB_LMCOORDS0_BIT ) ) {
		vattribbit_t lmattrbit;
		int type = FLOAT_VATTRIB_GL_TYPE( VATTRIB_LMCOORDS0_BIT, hfa );
		int lmstSize = ( ( type == GL_HALF_FLOAT ) ? 2 * sizeof( GLhalfARB ) : 2 * sizeof( float ) );

		lmattrbit = VATTRIB_LMCOORDS0_BIT;

		for( i = 0; i < ( MAX_LIGHTMAPS + 1 ) / 2; i++ ) {
			if( !(vattribs & lmattrbit) ) {
				break;
			}
			if( !mesh->lmstArray[i*2+0] ) {
				errMask |= lmattrbit;
				break;
			}

			R_FillVertexBuffer_float_or_half( type, 
				mesh->lmstArray[i*2+0][0],
				2, vertSize, numVerts, data + vbo->lmstOffset[i] );

			if( vattribs & (lmattrbit<<1) ) {
				if( !mesh->lmstArray[i*2+1] ) {
					errMask |= lmattrbit<<1;
					break;
				}
				R_FillVertexBuffer_float_or_half( type,
					mesh->lmstArray[i*2+1][0],
					2, vertSize, numVerts, data + vbo->lmstOffset[i] + lmstSize );
			}

			lmattrbit <<= 2;
		}
	}

	// upload lightmap array texture layers
	if( vbo->lmlayersOffset[0] && ( vattribs & VATTRIB_LMLAYERS0123_BIT ) ) {
		vattribbit_t lmattrbit;

		lmattrbit = VATTRIB_LMLAYERS0123_BIT;

		for( i = 0; i < ( MAX_LIGHTMAPS + 3 ) / 4; i++ ) {
			if( !( vattribs & lmattrbit ) ) {
				break;
			}
			if( !mesh->lmlayersArray[i] ) {
				errMask |= lmattrbit;
				break;
			}

			R_FillVertexBuffer( int, int, 
				( int * )&mesh->lmlayersArray[i][0],
				1, vertSize, numVerts, data + vbo->lmlayersOffset[i] );

			lmattrbit <<= 1;
		}
	}