GetBuffer() public method

Gets the buffer bound to the given source index.
public GetBuffer ( short index ) : HardwareVertexBuffer
index short Index of the binding to retreive the buffer for.
return HardwareVertexBuffer
        /// <summary>
        ///		Utility method, extract info from the given VertexData
        /// </summary>
        public void ExtractFrom(VertexData sourceData)
        {
            // Release old buffer copies first
            HardwareBufferManager mgr = HardwareBufferManager.Instance;

            if (destPositionBuffer != null)
            {
                mgr.ReleaseVertexBufferCopy(destPositionBuffer);
                Debug.Assert(destPositionBuffer == null);
            }
            if (destNormalBuffer != null)
            {
                mgr.ReleaseVertexBufferCopy(destNormalBuffer);
                Debug.Assert(destNormalBuffer == null);
            }

            VertexDeclaration   decl       = sourceData.vertexDeclaration;
            VertexBufferBinding bind       = sourceData.vertexBufferBinding;
            VertexElement       posElem    = decl.FindElementBySemantic(VertexElementSemantic.Position);
            VertexElement       normElem   = decl.FindElementBySemantic(VertexElementSemantic.Normal);
            VertexElement       tanElem    = decl.FindElementBySemantic(VertexElementSemantic.Tangent);
            VertexElement       binormElem = decl.FindElementBySemantic(VertexElementSemantic.Binormal);

            Debug.Assert(posElem != null, "Positions are required");

            posBindIndex      = posElem.Source;
            srcPositionBuffer = bind.GetBuffer(posBindIndex);

            if (normElem == null)
            {
                posNormalShareBuffer = false;
                srcNormalBuffer      = null;
            }
            else
            {
                normBindIndex = normElem.Source;
                if (normBindIndex == posBindIndex)
                {
                    posNormalShareBuffer = true;
                    srcNormalBuffer      = null;
                }
                else
                {
                    posNormalShareBuffer = false;
                    srcNormalBuffer      = bind.GetBuffer(normBindIndex);
                }
            }
            if (tanElem == null)
            {
                srcTangentBuffer = null;
            }
            else
            {
                tanBindIndex     = tanElem.Source;
                srcTangentBuffer = bind.GetBuffer(tanBindIndex);
            }

            if (binormElem == null)
            {
                srcBinormalBuffer = null;
            }
            else
            {
                binormBindIndex   = binormElem.Source;
                srcBinormalBuffer = bind.GetBuffer(binormBindIndex);
            }
        }
        /// <summary>
        ///		Modifies the vertex data to be suitable for use for rendering shadow geometry.
        /// </summary>
        /// <remarks>
        ///		<para>
        ///			Preparing vertex data to generate a shadow volume involves firstly ensuring that the
        ///			vertex buffer containing the positions is a standalone vertex buffer,
        ///			with no other components in it. This method will therefore break apart any existing
        ///			vertex buffers if position is sharing a vertex buffer.
        ///			Secondly, it will double the size of this vertex buffer so that there are 2 copies of
        ///			the position data for the mesh. The first half is used for the original, and the second
        ///			half is used for the 'extruded' version. The vertex count used to render will remain
        ///			the same though, so as not to add any overhead to regular rendering of the object.
        ///			Both copies of the position are required in one buffer because shadow volumes stretch
        ///			from the original mesh to the extruded version.
        ///		</para>
        ///		<para>
        ///			It's important to appreciate that this method can fundamentally change the structure of your
        ///			vertex buffers, although in reality they will be new buffers. As it happens, if other
        ///			objects are using the original buffers then they will be unaffected because the reference
        ///			counting will keep them intact. However, if you have made any assumptions about the
        ///			structure of the vertex data in the buffers of this object, you may have to rethink them.
        ///		</para>
        /// </remarks>
        // TODO: Step through and test
        public void PrepareForShadowVolume()
        {
            /* NOTE
             * Sinbad would dearly, dearly love to just use a 4D position buffer in order to
             * store the extra 'w' value I need to differentiate between extruded and
             * non-extruded sections of the buffer, so that vertex programs could use that.
             * Hey, it works fine for GL. However, D3D9 in it's infinite stupidity, does not
             * support 4d position vertices in the fixed-function pipeline. If you use them,
             * you just see nothing. Since we can't know whether the application is going to use
             * fixed function or vertex programs, we have to stick to 3d position vertices and
             * store the 'w' in a separate 1D texture coordinate buffer, which is only used
             * when rendering the shadow.
             */

            // Upfront, lets check whether we have vertex program capability
            RenderSystem renderSystem      = Root.Instance.RenderSystem;
            bool         useVertexPrograms = false;

            if (renderSystem != null && renderSystem.Caps.CheckCap(Capabilities.VertexPrograms))
            {
                useVertexPrograms = true;
            }

            // Look for a position element
            VertexElement posElem =
                vertexDeclaration.FindElementBySemantic(VertexElementSemantic.Position);

            if (posElem != null)
            {
                ushort posOldSource = posElem.Source;

                HardwareVertexBuffer vbuf = vertexBufferBinding.GetBuffer(posOldSource);

                bool wasSharedBuffer = false;

                // Are there other elements in the buffer except for the position?
                if (vbuf.VertexSize > posElem.Size)
                {
                    // We need to create another buffer to contain the remaining elements
                    // Most drivers don't like gaps in the declaration, and in any case it's waste
                    wasSharedBuffer = true;
                }

                HardwareVertexBuffer newPosBuffer = null, newRemainderBuffer = null;

                if (wasSharedBuffer)
                {
                    newRemainderBuffer = HardwareBufferManager.Instance.CreateVertexBuffer(
                        vbuf.VertexSize - posElem.Size, vbuf.VertexCount, vbuf.Usage,
                        vbuf.HasShadowBuffer);
                }

                // Allocate new position buffer, will be FLOAT3 and 2x the size
                int oldVertexCount = vbuf.VertexCount;
                int newVertexCount = oldVertexCount * 2;

                newPosBuffer = HardwareBufferManager.Instance.CreateVertexBuffer(
                    VertexElement.GetTypeSize(VertexElementType.Float3),
                    newVertexCount, vbuf.Usage, vbuf.HasShadowBuffer);

                // Iterate over the old buffer, copying the appropriate elements and initializing the rest
                IntPtr baseSrcPtr = vbuf.Lock(BufferLocking.ReadOnly);

                // Point first destination pointer at the start of the new position buffer,
                // the other one half way along
                IntPtr destPtr = newPosBuffer.Lock(BufferLocking.Discard);
                // oldVertexCount * 3 * 4, since we are dealing with byte offsets here
                IntPtr dest2Ptr = new IntPtr(destPtr.ToInt32() + (oldVertexCount * 12));

                int prePosVertexSize = 0;
                int postPosVertexSize   = 0;
                int postPosVertexOffset = 0;

                if (wasSharedBuffer)
                {
                    // Precalculate any dimensions of vertex areas outside the position
                    prePosVertexSize    = posElem.Offset;
                    postPosVertexOffset = prePosVertexSize + posElem.Size;
                    postPosVertexSize   = vbuf.VertexSize - postPosVertexOffset;

                    // the 2 separate bits together should be the same size as the remainder buffer vertex
                    Debug.Assert(newRemainderBuffer.VertexSize == (prePosVertexSize + postPosVertexSize));

                    IntPtr baseDestRemPtr = newRemainderBuffer.Lock(BufferLocking.Discard);

                    int baseSrcOffset     = 0;
                    int baseDestRemOffset = 0;

                    unsafe {
                        float *pDest  = (float *)destPtr.ToPointer();
                        float *pDest2 = (float *)dest2Ptr.ToPointer();

                        int destCount = 0, dest2Count = 0;

                        // Iterate over the vertices
                        for (int v = 0; v < oldVertexCount; v++)
                        {
                            float *pSrc = (float *)((byte *)baseSrcPtr.ToPointer() + posElem.Offset + baseSrcOffset);

                            // Copy position, into both buffers
                            pDest[destCount++] = pDest2[dest2Count++] = pSrc[0];
                            pDest[destCount++] = pDest2[dest2Count++] = pSrc[1];
                            pDest[destCount++] = pDest2[dest2Count++] = pSrc[2];

                            // now deal with any other elements
                            // Basically we just memcpy the vertex excluding the position
                            if (prePosVertexSize > 0)
                            {
                                Memory.Copy(
                                    baseSrcPtr, baseDestRemPtr,
                                    baseSrcOffset, baseDestRemOffset,
                                    prePosVertexSize);
                            }

                            if (postPosVertexSize > 0)
                            {
                                Memory.Copy(
                                    baseSrcPtr, baseDestRemPtr,
                                    baseSrcOffset + postPosVertexOffset,
                                    baseDestRemOffset + prePosVertexSize,
                                    postPosVertexSize);
                            }

                            // increment the pointer offsets
                            baseDestRemOffset += newRemainderBuffer.VertexSize;
                            baseSrcOffset     += vbuf.VertexSize;
                        }                 // next vertex
                    }                     // unsafe
                }
                else
                {
                    // copy the data directly
                    Memory.Copy(baseSrcPtr, destPtr, vbuf.Size);
                    Memory.Copy(baseSrcPtr, dest2Ptr, vbuf.Size);
                }

                vbuf.Unlock();
                newPosBuffer.Unlock();

                if (wasSharedBuffer)
                {
                    newRemainderBuffer.Unlock();
                }

                // At this stage, he original vertex buffer is going to be destroyed
                // So we should force the deallocation of any temporary copies
                HardwareBufferManager.Instance.ForceReleaseBufferCopies(vbuf);

                if (useVertexPrograms)
                {
                    unsafe {
                        // Now it's time to set up the w buffer
                        hardwareShadowVolWBuffer =
                            HardwareBufferManager.Instance.CreateVertexBuffer(
                                sizeof(float),
                                newVertexCount,
                                BufferUsage.StaticWriteOnly,
                                false);

                        // Fill the first half with 1.0, second half with 0.0
                        IntPtr wPtr      = hardwareShadowVolWBuffer.Lock(BufferLocking.Discard);
                        float *pDest     = (float *)wPtr.ToPointer();
                        int    destCount = 0;

                        for (int v = 0; v < oldVertexCount; v++)
                        {
                            pDest[destCount++] = 1.0f;
                        }
                        for (int v = 0; v < oldVertexCount; v++)
                        {
                            pDest[destCount++] = 0.0f;
                        }
                    }                     // unsafe

                    hardwareShadowVolWBuffer.Unlock();
                }                 // if vertexPrograms

                ushort newPosBufferSource = 0;

                if (wasSharedBuffer)
                {
                    // Get the a new buffer binding index
                    newPosBufferSource = vertexBufferBinding.NextIndex;

                    // Re-bind the old index to the remainder buffer
                    vertexBufferBinding.SetBinding(posOldSource, newRemainderBuffer);
                }
                else
                {
                    // We can just re-use the same source idex for the new position buffer
                    newPosBufferSource = posOldSource;
                }

                // Bind the new position buffer
                vertexBufferBinding.SetBinding(newPosBufferSource, newPosBuffer);

                // Now, alter the vertex declaration to change the position source
                // and the offsets of elements using the same buffer
                for (int i = 0; i < vertexDeclaration.ElementCount; i++)
                {
                    VertexElement element = vertexDeclaration.GetElement(i);

                    if (element.Semantic == VertexElementSemantic.Position)
                    {
                        // Modify position to point at new position buffer
                        vertexDeclaration.ModifyElement(
                            i,
                            newPosBufferSource,            // new source buffer
                            0,                             // no offset now
                            VertexElementType.Float3,
                            VertexElementSemantic.Position);
                    }
                    else if (wasSharedBuffer &&
                             element.Source == posOldSource &&
                             element.Offset > prePosVertexSize)
                    {
                        // This element came after position, remove the position's
                        // size
                        vertexDeclaration.ModifyElement(
                            i,
                            posOldSource,                             // same old source
                            element.Offset - posElem.Size,            // less offset now
                            element.Type,
                            element.Semantic,
                            element.Index);
                    }
                }
            }             // if posElem != null
        }