public GetBuffer ( short index ) : |
||
index | short | Index of the binding to retreive the buffer for. |
Результат |
/// <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 }