//----------------------------------------------------------------------- void BillboardChain::updateIndexBuffer(void) { setupBuffers(); if (mIndexContentDirty) { HardwareBufferLockGuard indexLock(mIndexData->indexBuffer, HardwareBuffer::HBL_DISCARD); uint16* pShort = static_cast<uint16*>(indexLock.pData); mIndexData->indexCount = 0; // indexes for (ChainSegmentList::iterator segi = mChainSegmentList.begin(); segi != mChainSegmentList.end(); ++segi) { ChainSegment& seg = *segi; // Skip 0 or 1 element segment counts if (seg.head != SEGMENT_EMPTY && seg.head != seg.tail) { // Start from head + 1 since it's only useful in pairs size_t laste = seg.head; while(1) // until break { size_t e = laste + 1; // Wrap forwards if (e == mMaxElementsPerChain) e = 0; // indexes of this element are (e * 2) and (e * 2) + 1 // indexes of the last element are the same, -2 assert (((e + seg.start) * 2) < 65536 && "Too many elements!"); uint16 baseIdx = static_cast<uint16>((e + seg.start) * 2); uint16 lastBaseIdx = static_cast<uint16>((laste + seg.start) * 2); *pShort++ = lastBaseIdx; *pShort++ = lastBaseIdx + 1; *pShort++ = baseIdx; *pShort++ = lastBaseIdx + 1; *pShort++ = baseIdx + 1; *pShort++ = baseIdx; mIndexData->indexCount += 6; if (e == seg.tail) break; // last one laste = e; } } } mIndexContentDirty = false; } }
void csSprite2DMeshObject::PreGetBuffer (csRenderBufferHolder* holder, csRenderBufferName buffer) { if (!holder) return; csColoredVertices* vertices = GetCsVertices (); if (buffer == CS_BUFFER_INDEX) { size_t indexSize = vertices->GetSize (); if (!index_buffer.IsValid() || (indicesSize != indexSize)) { index_buffer = csRenderBuffer::CreateIndexRenderBuffer ( indexSize, CS_BUF_DYNAMIC, CS_BUFCOMP_UNSIGNED_INT, 0, vertices->GetSize () - 1); holder->SetRenderBuffer (CS_BUFFER_INDEX, index_buffer); csRenderBufferLock<uint> indexLock (index_buffer); uint* ptr = indexLock; for (size_t i = 0; i < vertices->GetSize (); i++) { *ptr++ = (uint)i; } indicesSize = indexSize; } } else if (buffer == CS_BUFFER_TEXCOORD0) { if (texels_dirty) { int texels_count; const csVector2 *uvani_uv = 0; if (!uvani) texels_count = (int)vertices->GetSize (); else uvani_uv = uvani->GetVertices (texels_count); size_t texelSize = texels_count; if (!texel_buffer.IsValid() || (texel_buffer->GetSize() != texelSize * sizeof(float) * 2)) { texel_buffer = csRenderBuffer::CreateRenderBuffer ( texelSize, CS_BUF_STATIC, CS_BUFCOMP_FLOAT, 2); holder->SetRenderBuffer (CS_BUFFER_TEXCOORD0, texel_buffer); } csRenderBufferLock<csVector2> texelLock (texel_buffer); for (size_t i = 0; i < (size_t)texels_count; i++) { csVector2& v = texelLock[i]; if (!uvani) { v.x = (*vertices)[i].u; v.y = (*vertices)[i].v; } else { v.x = uvani_uv[i].x; v.y = uvani_uv[i].y; } } texels_dirty = false; } } else if (buffer == CS_BUFFER_COLOR) { if (colors_dirty) { size_t color_size = vertices->GetSize (); if (!color_buffer.IsValid() || (color_buffer->GetSize() != color_size * sizeof(float) * 2)) { color_buffer = csRenderBuffer::CreateRenderBuffer ( color_size, CS_BUF_STATIC, CS_BUFCOMP_FLOAT, 3); holder->SetRenderBuffer (CS_BUFFER_COLOR, color_buffer); } csRenderBufferLock<csColor> colorLock (color_buffer); for (size_t i = 0; i < vertices->GetSize (); i++) { colorLock[i] = (*vertices)[i].color; } colors_dirty = false; } } else if (buffer == CS_BUFFER_POSITION) { if (vertices_dirty) { size_t vertices_size = vertices->GetSize (); if (!vertex_buffer.IsValid() || (vertex_buffer->GetSize() != vertices_size * sizeof(float) * 3)) { vertex_buffer = csRenderBuffer::CreateRenderBuffer ( vertices_size, CS_BUF_STATIC, CS_BUFCOMP_FLOAT, 3); holder->SetRenderBuffer (CS_BUFFER_POSITION, vertex_buffer); } csRenderBufferLock<csVector3> vertexLock (vertex_buffer); for (size_t i = 0; i < vertices->GetSize (); i++) { vertexLock[i].Set ((*vertices)[i].pos.x, (*vertices)[i].pos.y, 0.0f); } vertices_dirty = false; } } }
// ------------------------------------------------------------------------ void ShadowCaster::generateShadowVolume(EdgeData* edgeData, const HardwareIndexBufferSharedPtr& indexBuffer, size_t& indexBufferUsedSize, const Light* light, ShadowRenderableList& shadowRenderables, unsigned long flags) { // Edge groups should be 1:1 with shadow renderables assert(edgeData->edgeGroups.size() == shadowRenderables.size()); Light::LightTypes lightType = light->getType(); // Whether to use the McGuire method, a triangle fan covering all silhouette // This won't work properly with multiple separate edge groups (should be one fan per group, not implemented) // or when light position is too close to light cap bound. bool useMcGuire = edgeData->edgeGroups.size() <= 1 && (lightType == Light::LT_DIRECTIONAL || isBoundOkForMcGuire(getLightCapBounds(), light->getDerivedPosition())); EdgeData::EdgeGroupList::const_iterator egi, egiend; ShadowRenderableList::const_iterator si; // pre-count the size of index data we need since it makes a big perf difference // to GL in particular if we lock a smaller area of the index buffer size_t preCountIndexes = 0; si = shadowRenderables.begin(); egiend = edgeData->edgeGroups.end(); for (egi = edgeData->edgeGroups.begin(); egi != egiend; ++egi, ++si) { const EdgeData::EdgeGroup& eg = *egi; bool firstDarkCapTri = true; EdgeData::EdgeList::const_iterator i, iend; iend = eg.edges.end(); for (i = eg.edges.begin(); i != iend; ++i) { const EdgeData::Edge& edge = *i; // Silhouette edge, when two tris has opposite light facing, or // degenerate edge where only tri 1 is valid and the tri light facing char lightFacing = edgeData->triangleLightFacings[edge.triIndex[0]]; if ((edge.degenerate && lightFacing) || (!edge.degenerate && (lightFacing != edgeData->triangleLightFacings[edge.triIndex[1]]))) { preCountIndexes += 3; // Are we extruding to infinity? if (!(lightType == Light::LT_DIRECTIONAL && flags & SRF_EXTRUDE_TO_INFINITY)) { preCountIndexes += 3; } if(useMcGuire) { // Do dark cap tri // Use McGuire et al method, a triangle fan covering all silhouette // edges and one point (taken from the initial tri) if (flags & SRF_INCLUDE_DARK_CAP) { if (firstDarkCapTri) { firstDarkCapTri = false; } else { preCountIndexes += 3; } } } } } if(useMcGuire) { // Do light cap if (flags & SRF_INCLUDE_LIGHT_CAP) { // Iterate over the triangles which are using this vertex set EdgeData::TriangleList::const_iterator ti, tiend; EdgeData::TriangleLightFacingList::const_iterator lfi; ti = edgeData->triangles.begin() + eg.triStart; tiend = ti + eg.triCount; lfi = edgeData->triangleLightFacings.begin() + eg.triStart; for ( ; ti != tiend; ++ti, ++lfi) { assert(ti->vertexSet == eg.vertexSet); // Check it's light facing if (*lfi) { preCountIndexes += 3; } } } } else { // Do both caps int increment = ((flags & SRF_INCLUDE_DARK_CAP) ? 3 : 0) + ((flags & SRF_INCLUDE_LIGHT_CAP) ? 3 : 0); if(increment != 0) { // Iterate over the triangles which are using this vertex set EdgeData::TriangleList::const_iterator ti, tiend; EdgeData::TriangleLightFacingList::const_iterator lfi; ti = edgeData->triangles.begin() + eg.triStart; tiend = ti + eg.triCount; lfi = edgeData->triangleLightFacings.begin() + eg.triStart; for ( ; ti != tiend; ++ti, ++lfi) { assert(ti->vertexSet == eg.vertexSet); // Check it's light facing if (*lfi) preCountIndexes += increment; } } } } // End pre-count //Check if index buffer is to small if (preCountIndexes > indexBuffer->getNumIndexes()) { LogManager::getSingleton().logWarning( "shadow index buffer size to small. Auto increasing buffer size to" + StringConverter::toString(sizeof(unsigned short) * preCountIndexes)); SceneManager* pManager = Root::getSingleton()._getCurrentSceneManager(); if (pManager) { pManager->setShadowIndexBufferSize(preCountIndexes); } //Check that the index buffer size has actually increased if (preCountIndexes > indexBuffer->getNumIndexes()) { //increasing index buffer size has failed OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Lock request out of bounds.", "ShadowCaster::generateShadowVolume"); } } else if(indexBufferUsedSize + preCountIndexes > indexBuffer->getNumIndexes()) { indexBufferUsedSize = 0; } // Lock index buffer for writing, just enough length as we need HardwareBufferLockGuard indexLock(indexBuffer, sizeof(unsigned short) * indexBufferUsedSize, sizeof(unsigned short) * preCountIndexes, indexBufferUsedSize == 0 ? HardwareBuffer::HBL_DISCARD : HardwareBuffer::HBL_NO_OVERWRITE); unsigned short* pIdx = static_cast<unsigned short*>(indexLock.pData); size_t numIndices = indexBufferUsedSize; // Iterate over the groups and form renderables for each based on their // lightFacing si = shadowRenderables.begin(); egiend = edgeData->edgeGroups.end(); for (egi = edgeData->edgeGroups.begin(); egi != egiend; ++egi, ++si) { const EdgeData::EdgeGroup& eg = *egi; // Initialise the index start for this shadow renderable IndexData* indexData = (*si)->getRenderOperationForUpdate()->indexData; if (indexData->indexBuffer != indexBuffer) { (*si)->rebindIndexBuffer(indexBuffer); indexData = (*si)->getRenderOperationForUpdate()->indexData; } indexData->indexStart = numIndices; // original number of verts (without extruded copy) size_t originalVertexCount = eg.vertexData->vertexCount; bool firstDarkCapTri = true; unsigned short darkCapStart = 0; EdgeData::EdgeList::const_iterator i, iend; iend = eg.edges.end(); for (i = eg.edges.begin(); i != iend; ++i) { const EdgeData::Edge& edge = *i; // Silhouette edge, when two tris has opposite light facing, or // degenerate edge where only tri 1 is valid and the tri light facing char lightFacing = edgeData->triangleLightFacings[edge.triIndex[0]]; if ((edge.degenerate && lightFacing) || (!edge.degenerate && (lightFacing != edgeData->triangleLightFacings[edge.triIndex[1]]))) { size_t v0 = edge.vertIndex[0]; size_t v1 = edge.vertIndex[1]; if (!lightFacing) { // Inverse edge indexes when t1 is light away std::swap(v0, v1); } /* Note edge(v0, v1) run anticlockwise along the edge from the light facing tri so to point shadow volume tris outward, light cap indexes have to be backwards We emit 2 tris if light is a point light, 1 if light is directional, because directional lights cause all points to converge to a single point at infinity. First side tri = near1, near0, far0 Second tri = far0, far1, near1 'far' indexes are 'near' index + originalVertexCount because 'far' verts are in the second half of the buffer */ assert(v1 < 65536 && v0 < 65536 && (v0 + originalVertexCount) < 65536 && "Vertex count exceeds 16-bit index limit!"); *pIdx++ = static_cast<unsigned short>(v1); *pIdx++ = static_cast<unsigned short>(v0); *pIdx++ = static_cast<unsigned short>(v0 + originalVertexCount); numIndices += 3; // Are we extruding to infinity? if (!(lightType == Light::LT_DIRECTIONAL && flags & SRF_EXTRUDE_TO_INFINITY)) { // additional tri to make quad *pIdx++ = static_cast<unsigned short>(v0 + originalVertexCount); *pIdx++ = static_cast<unsigned short>(v1 + originalVertexCount); *pIdx++ = static_cast<unsigned short>(v1); numIndices += 3; } if(useMcGuire) { // Do dark cap tri // Use McGuire et al method, a triangle fan covering all silhouette // edges and one point (taken from the initial tri) if (flags & SRF_INCLUDE_DARK_CAP) { if (firstDarkCapTri) { darkCapStart = static_cast<unsigned short>(v0 + originalVertexCount); firstDarkCapTri = false; } else { *pIdx++ = darkCapStart; *pIdx++ = static_cast<unsigned short>(v1 + originalVertexCount); *pIdx++ = static_cast<unsigned short>(v0 + originalVertexCount); numIndices += 3; } } } } } if(!useMcGuire) { // Do dark cap if (flags & SRF_INCLUDE_DARK_CAP) { // Iterate over the triangles which are using this vertex set EdgeData::TriangleList::const_iterator ti, tiend; EdgeData::TriangleLightFacingList::const_iterator lfi; ti = edgeData->triangles.begin() + eg.triStart; tiend = ti + eg.triCount; lfi = edgeData->triangleLightFacings.begin() + eg.triStart; for ( ; ti != tiend; ++ti, ++lfi) { const EdgeData::Triangle& t = *ti; assert(t.vertexSet == eg.vertexSet); // Check it's light facing if (*lfi) { assert(t.vertIndex[0] < 65536 && t.vertIndex[1] < 65536 && t.vertIndex[2] < 65536 && "16-bit index limit exceeded!"); *pIdx++ = static_cast<unsigned short>(t.vertIndex[1] + originalVertexCount); *pIdx++ = static_cast<unsigned short>(t.vertIndex[0] + originalVertexCount); *pIdx++ = static_cast<unsigned short>(t.vertIndex[2] + originalVertexCount); numIndices += 3; } } } } // Do light cap if (flags & SRF_INCLUDE_LIGHT_CAP) { // separate light cap? if ((*si)->isLightCapSeparate()) { // update index count for this shadow renderable indexData->indexCount = numIndices - indexData->indexStart; // get light cap index data for update indexData = (*si)->getLightCapRenderable()->getRenderOperationForUpdate()->indexData; // start indexes after the current total indexData->indexStart = numIndices; } // Iterate over the triangles which are using this vertex set EdgeData::TriangleList::const_iterator ti, tiend; EdgeData::TriangleLightFacingList::const_iterator lfi; ti = edgeData->triangles.begin() + eg.triStart; tiend = ti + eg.triCount; lfi = edgeData->triangleLightFacings.begin() + eg.triStart; for ( ; ti != tiend; ++ti, ++lfi) { const EdgeData::Triangle& t = *ti; assert(t.vertexSet == eg.vertexSet); // Check it's light facing if (*lfi) { assert(t.vertIndex[0] < 65536 && t.vertIndex[1] < 65536 && t.vertIndex[2] < 65536 && "16-bit index limit exceeded!"); *pIdx++ = static_cast<unsigned short>(t.vertIndex[0]); *pIdx++ = static_cast<unsigned short>(t.vertIndex[1]); *pIdx++ = static_cast<unsigned short>(t.vertIndex[2]); numIndices += 3; } } } // update index count for current index data (either this shadow renderable or its light cap) indexData->indexCount = numIndices - indexData->indexStart; } // In debug mode, check we didn't overrun the index buffer assert(numIndices == indexBufferUsedSize + preCountIndexes); assert(numIndices <= indexBuffer->getNumIndexes() && "Index buffer overrun while generating shadow volume!! " "You must increase the size of the shadow index buffer."); indexBufferUsedSize = numIndices; }