public void Build(bool stencilShadows, bool logDetails) { // Ok, here's where we transfer the vertices and indexes to the shared buffers VertexDeclaration dcl = vertexData.vertexDeclaration; VertexBufferBinding binds = vertexData.vertexBufferBinding; // create index buffer, and lock if (logDetails) { log.InfoFormat("GeometryBucket.Build: Creating index buffer indexType {0} indexData.indexCount {1}", indexType, indexData.indexCount); } indexData.indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer(indexType, indexData.indexCount, BufferUsage.StaticWriteOnly); IntPtr indexBufferIntPtr = indexData.indexBuffer.Lock(BufferLocking.Discard); // create all vertex buffers, and lock ushort b; ushort posBufferIdx = dcl.FindElementBySemantic(VertexElementSemantic.Position).Source; List <List <VertexElement> > bufferElements = new List <List <VertexElement> >(); unsafe { byte *[] destBufferPtrs = new byte *[binds.BindingCount]; for (b = 0; b < binds.BindingCount; ++b) { int vertexCount = vertexData.vertexCount; if (logDetails) { log.InfoFormat("GeometryBucket.Build b {0}, binds.BindingCount {1}, vertexCount {2}, dcl.GetVertexSize(b) {3}", b, binds.BindingCount, vertexCount, dcl.GetVertexSize(b)); } // Need to double the vertex count for the position buffer // if we're doing stencil shadows if (stencilShadows && b == posBufferIdx) { vertexCount = vertexCount * 2; if (vertexCount > maxVertexIndex) { throw new Exception("Index range exceeded when using stencil shadows, consider " + "reducing your region size or reducing poly count"); } } HardwareVertexBuffer vbuf = HardwareBufferManager.Instance.CreateVertexBuffer(dcl.GetVertexSize(b), vertexCount, BufferUsage.StaticWriteOnly); binds.SetBinding(b, vbuf); IntPtr pLock = vbuf.Lock(BufferLocking.Discard); destBufferPtrs[b] = (byte *)pLock.ToPointer(); // Pre-cache vertex elements per buffer bufferElements.Add(dcl.FindElementBySource(b)); } // iterate over the geometry items int indexOffset = 0; IEnumerator iter = queuedGeometry.GetEnumerator(); Vector3 regionCenter = parent.Parent.Parent.Center; int * pDestInt = (int *)indexBufferIntPtr.ToPointer(); ushort * pDestUShort = (ushort *)indexBufferIntPtr.ToPointer(); foreach (QueuedGeometry geom in queuedGeometry) { // copy indexes across with offset IndexData srcIdxData = geom.geometry.indexData; IntPtr srcIntPtr = srcIdxData.indexBuffer.Lock(BufferLocking.ReadOnly); if (indexType == IndexType.Size32) { int *pSrcInt = (int *)srcIntPtr.ToPointer(); for (int i = 0; i < srcIdxData.indexCount; i++) { *pDestInt++ = (*pSrcInt++) + indexOffset; } } else { ushort *pSrcUShort = (ushort *)(srcIntPtr.ToPointer()); for (int i = 0; i < srcIdxData.indexCount; i++) { *pDestUShort++ = (ushort)((*pSrcUShort++) + indexOffset); } } srcIdxData.indexBuffer.Unlock(); // Now deal with vertex buffers // we can rely on buffer counts / formats being the same VertexData srcVData = geom.geometry.vertexData; VertexBufferBinding srcBinds = srcVData.vertexBufferBinding; for (b = 0; b < binds.BindingCount; ++b) { // Iterate over vertices destBufferPtrs[b] = CopyVertices(srcBinds.GetBuffer(b), destBufferPtrs[b], bufferElements[b], geom, regionCenter); } indexOffset += geom.geometry.vertexData.vertexCount; } } // unlock everything indexData.indexBuffer.Unlock(); for (b = 0; b < binds.BindingCount; ++b) { binds.GetBuffer(b).Unlock(); } // If we're dealing with stencil shadows, copy the position data from // the early half of the buffer to the latter part if (stencilShadows) { unsafe { HardwareVertexBuffer buf = binds.GetBuffer(posBufferIdx); IntPtr src = buf.Lock(BufferLocking.Normal); byte * pSrc = (byte *)src.ToPointer(); // Point dest at second half (remember vertexcount is original count) byte *pDst = pSrc + buf.VertexSize * vertexData.vertexCount; int count = buf.VertexSize * buf.VertexCount; while (count-- > 0) { *pDst++ = *pSrc++; } buf.Unlock(); // Also set up hardware W buffer if appropriate RenderSystem rend = Root.Instance.RenderSystem; if (null != rend && rend.Caps.CheckCap(Capabilities.VertexPrograms)) { buf = HardwareBufferManager.Instance.CreateVertexBuffer(sizeof(float), vertexData.vertexCount * 2, BufferUsage.StaticWriteOnly, false); // Fill the first half with 1.0, second half with 0.0 float *pW = (float *)buf.Lock(BufferLocking.Discard).ToPointer(); for (int v = 0; v < vertexData.vertexCount; ++v) { *pW++ = 1.0f; } for (int v = 0; v < vertexData.vertexCount; ++v) { *pW++ = 0.0f; } buf.Unlock(); vertexData.hardwareShadowVolWBuffer = buf; } } } }