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