예제 #1
0
파일: r_backend.c 프로젝트: DenMSC/qfusion
/*
* RB_AddDynamicMesh
*/
void RB_AddDynamicMesh( const entity_t *entity, const shader_t *shader,
                        const struct mfog_s *fog, const struct portalSurface_s *portalSurface, unsigned int shadowBits,
                        const struct mesh_s *mesh, int primitive, float x_offset, float y_offset )
{
    int numVerts = mesh->numVerts, numElems = mesh->numElems;
    bool trifan = false;
    int scissor[4];
    rbDynamicDraw_t *prev = NULL, *draw;
    bool merge = false;
    vattribmask_t vattribs;
    int streamId = RB_VBO_NONE;
    rbDynamicStream_t *stream;
    int destVertOffset;
    elem_t *destElems;

    // can't (and shouldn't because that would break batching) merge strip draw calls
    // (consider simply disabling merge later in this case if models with tristrips are added in the future, but that's slow)
    assert( ( primitive == GL_TRIANGLES ) || ( primitive == GL_LINES ) );

    if( !numElems ) {
        numElems = ( max( numVerts, 2 ) - 2 ) * 3;
        trifan = true;
    }
    if( !numVerts || !numElems || ( numVerts > MAX_STREAM_VBO_VERTS ) || ( numElems > MAX_STREAM_VBO_ELEMENTS ) ) {
        return;
    }

    RB_GetScissor( &scissor[0], &scissor[1], &scissor[2], &scissor[3] );

    if( rb.numDynamicDraws ) {
        prev = &rb.dynamicDraws[rb.numDynamicDraws - 1];
    }

    if( prev ) {
        int prevRenderFX = 0, renderFX = 0;
        if( prev->entity ) {
            prevRenderFX = prev->entity->renderfx;
        }
        if( entity ) {
            renderFX = entity->renderfx;
        }
        if( ( ( shader->flags & SHADER_ENTITY_MERGABLE ) || ( prev->entity == entity ) ) && ( prevRenderFX == renderFX ) &&
                ( prev->shader == shader ) && ( prev->fog == fog ) && ( prev->portalSurface == portalSurface ) &&
                ( ( prev->shadowBits && shadowBits ) || ( !prev->shadowBits && !shadowBits ) ) ) {
            // don't rebind the shader to get the VBO in this case
            streamId = prev->streamId;
            if( ( prev->shadowBits == shadowBits ) && ( prev->primitive == primitive ) &&
                    ( prev->offset[0] == x_offset ) && ( prev->offset[1] == y_offset ) &&
                    !memcmp( prev->scissor, scissor, sizeof( scissor ) ) ) {
                merge = true;
            }
        }
    }

    if( streamId == RB_VBO_NONE ) {
        RB_BindShader( entity, shader, fog );
        vattribs = rb.currentVAttribs;
        streamId = ( ( vattribs & ~COMPACT_STREAM_VATTRIBS ) ? RB_VBO_STREAM : RB_VBO_STREAM_COMPACT );
    }
    else {
        vattribs = prev->vattribs;
    }

    stream = &rb.dynamicStreams[-streamId - 1];

    if( ( !merge && ( ( rb.numDynamicDraws + 1 ) > MAX_DYNAMIC_DRAWS ) ) ||
            ( ( stream->drawElements.firstVert + stream->drawElements.numVerts + numVerts ) > MAX_STREAM_VBO_VERTS ) ||
            ( ( stream->drawElements.firstElem + stream->drawElements.numElems + numElems ) > MAX_STREAM_VBO_ELEMENTS ) ) {
        // wrap if overflows
        RB_FlushDynamicMeshes();

        stream->drawElements.firstVert = 0;
        stream->drawElements.numVerts = 0;
        stream->drawElements.firstElem = 0;
        stream->drawElements.numElems = 0;

        merge = false;
    }

    if( merge ) {
        // merge continuous draw calls
        draw = prev;
        draw->drawElements.numVerts += numVerts;
        draw->drawElements.numElems += numElems;
    }
    else {
        draw = &rb.dynamicDraws[rb.numDynamicDraws++];
        draw->entity = entity;
        draw->shader = shader;
        draw->fog = fog;
        draw->portalSurface = portalSurface;
        draw->shadowBits = shadowBits;
        draw->vattribs = vattribs;
        draw->streamId = streamId;
        draw->primitive = primitive;
        draw->offset[0] = x_offset;
        draw->offset[1] = y_offset;
        memcpy( draw->scissor, scissor, sizeof( scissor ) );
        draw->drawElements.firstVert = stream->drawElements.firstVert + stream->drawElements.numVerts;
        draw->drawElements.numVerts = numVerts;
        draw->drawElements.firstElem = stream->drawElements.firstElem + stream->drawElements.numElems;
        draw->drawElements.numElems = numElems;
        draw->drawElements.numInstances = 0;
    }

    destVertOffset = stream->drawElements.firstVert + stream->drawElements.numVerts;
    R_FillVBOVertexDataBuffer( stream->vbo, vattribs, mesh,
                               stream->vertexData + destVertOffset * stream->vbo->vertexSize );

    destElems = dynamicStreamElems[-streamId - 1] + stream->drawElements.firstElem + stream->drawElements.numElems;
    if( trifan ) {
        R_BuildTrifanElements( destVertOffset, numElems, destElems );
    }
    else {
        if( primitive == GL_TRIANGLES ) {
            R_CopyOffsetTriangles( mesh->elems, numElems, destVertOffset, destElems );
        }
        else {
            R_CopyOffsetElements( mesh->elems, numElems, destVertOffset, destElems );
        }
    }

    stream->drawElements.numVerts += numVerts;
    stream->drawElements.numElems += numElems;
}
예제 #2
0
/*
* RB_BatchMesh
*/
void RB_BatchMesh( const mesh_t *mesh )
{
	int stream;
	vboSlice_t *batch;
	int numVerts = mesh->numVerts, numElems = mesh->numElems;

	if( rb.currentVBOId == RB_VBO_STREAM_QUAD ) {
		numElems = numVerts/4*6;
	} else if( !numElems && rb.currentVBOId == RB_VBO_STREAM ) {
		numElems = (max(numVerts, 2) - 2) * 3;
	}

	if( !numVerts || !numElems ) {
		return;
	}

	assert( rb.currentVBOId < RB_VBO_NONE );
	if( rb.currentVBOId >= RB_VBO_NONE ) {
		return;
	}

	stream = -rb.currentVBOId - 1;
	batch = &rb.batches[stream];

	if( numVerts+batch->numVerts > MAX_BATCH_VERTS || 
		numElems+batch->numElems > MAX_BATCH_ELEMENTS ) {
		RB_UploadBatchMesh( batch );
	}

	if( numVerts > MAX_BATCH_VERTS || 
		numElems > MAX_BATCH_ELEMENTS ) {
		RB_UploadMesh( mesh );
	}
	else {
		int i;
		vattribmask_t vattribs = rb.currentVAttribs;

		memcpy( rb.batchMesh.xyzArray + batch->numVerts, mesh->xyzArray, numVerts * sizeof( vec3_t ) );
		if( rb.currentVBOId == RB_VBO_STREAM_QUAD ) {
			// quad indices are stored in a static vbo
		} else if( mesh->elems ) {
			if( rb.primitive == GL_TRIANGLES ) {
				R_CopyOffsetTriangles( mesh->elems, numElems, batch->numVerts, rb.batchMesh.elems + batch->numElems );
			}
			else {
				R_CopyOffsetElements( mesh->elems, numElems, batch->numVerts, rb.batchMesh.elems + batch->numElems );
			}
		} else if( rb.currentVBOId == RB_VBO_STREAM ) {
			R_BuildTrifanElements( batch->numVerts, numElems, rb.batchMesh.elems + batch->numElems );
		} else {
			assert( 0 );
		}
		if( mesh->normalsArray && (vattribs & VATTRIB_NORMAL_BIT) ) {
			memcpy( rb.batchMesh.normalsArray + batch->numVerts, mesh->normalsArray, numVerts * sizeof( vec3_t ) );
		}
		if( mesh->sVectorsArray && (vattribs & VATTRIB_SVECTOR_BIT) ) {
			memcpy( rb.batchMesh.sVectorsArray + batch->numVerts, mesh->sVectorsArray, numVerts * sizeof( vec4_t ) );
		}
		if( mesh->stArray && (vattribs & VATTRIB_TEXCOORDS_BIT) ) {
			memcpy( rb.batchMesh.stArray + batch->numVerts, mesh->stArray, numVerts * sizeof( vec2_t ) );
		}
		
		if( mesh->lmstArray[0] && (vattribs & VATTRIB_LMCOORDS_BIT) ) {
			memcpy( rb.batchMesh.lmstArray[0] + batch->numVerts, mesh->lmstArray[0], numVerts * sizeof( vec2_t ) );

			for( i = 1; i < MAX_LIGHTMAPS; i++ ) {
				if( !mesh->lmstArray[i] || !(vattribs & (VATTRIB_LMCOORDS1_BIT<<(i-1))) ) {
					break;
				}
				memcpy( rb.batchMesh.lmstArray[i] + batch->numVerts, mesh->lmstArray[i], numVerts * sizeof( vec2_t ) );
			}
		}

		if( mesh->colorsArray[0] && (vattribs & VATTRIB_COLOR_BIT) ) {
			memcpy( rb.batchMesh.colorsArray[0] + batch->numVerts, mesh->colorsArray[0], numVerts * sizeof( byte_vec4_t ) );

			for( i = 1; i < MAX_LIGHTMAPS; i++ ) {
				if( !mesh->colorsArray[i] || !(vattribs & (VATTRIB_COLOR1_BIT<<(i-1))) ) {
					break;
				}
				memcpy( rb.batchMesh.colorsArray[i] + batch->numVerts, mesh->colorsArray[i], numVerts * sizeof( byte_vec4_t ) );
			}
		}

		batch->numVerts += numVerts;
		batch->numElems += numElems;
	}
}