/// <summary> /// Utility method to pull a bunch of floats out of a vertex buffer. /// </summary> /// <param name="data"></param> /// <param name="vBuffer"></param> /// <param name="elem"></param> public static void ReadBuffer( float[ , ] data, HardwareVertexBuffer vBuffer, VertexElement elem ) { int count = data.GetLength( 1 ); IntPtr bufData = vBuffer.Lock( BufferLocking.ReadOnly ); Debug.Assert( vBuffer.VertexSize % sizeof( float ) == 0 ); Debug.Assert( elem.Offset % sizeof( float ) == 0 ); int vertexCount = vBuffer.VertexCount; int vertexSpan = vBuffer.VertexSize / sizeof( float ); int offset = elem.Offset / sizeof( float ); unsafe { float* pFloats = (float*) bufData.ToPointer(); for( int i = 0; i < vertexCount; ++i ) { for( int j = 0; j < count; ++j ) { Debug.Assert( ((offset + i * vertexSpan + j) * sizeof( float )) < (vertexCount * vBuffer.VertexSize), "Read off end of vertex buffer" ); data[ i, j ] = pFloats[ offset + i * vertexSpan + j ]; } } } // unlock the buffer vBuffer.Unlock(); }
public override Axiom.Graphics.VertexElement AddElement(ushort source, int offset, VertexElementType type, VertexElementSemantic semantic, int index) { Axiom.Graphics.VertexElement element = base.AddElement(source, offset, type, semantic, index); needsRebuild = true; return(element); }
public override Axiom.Graphics.VertexElement InsertElement(int position, ushort source, int offset, VertexElementType type, VertexElementSemantic semantic, int index) { Axiom.Graphics.VertexElement element = base.InsertElement(position, source, offset, type, semantic, index); needsRebuild = true; return(element); }
/// <summary> /// Gets the vertex size defined by this declaration for a given source. /// </summary> /// <param name="source">The buffer binding index for which to get the vertex size.</param> public virtual int GetVertexSize(ushort source) { int size = 0; for (int i = 0; i < elements.Count; i++) { VertexElement element = elements[i]; // do they match? if (element.Source == source) { size += element.Size; } } // return the size return(size); }
/// <summary> /// Gets a list of elements which use a given source. /// </summary> public virtual List <VertexElement> FindElementBySource(ushort source) { List <VertexElement> rv = new List <VertexElement>(); for (int i = 0; i < elements.Count; i++) { VertexElement element = elements[i]; // do they match? if (element.Source == source) { rv.Add(element); } } // return the list return(rv); }
// Sort routine for VertexElement #region IComparer Members public int Compare(VertexElement e1, VertexElement e2) { // Sort by source first if (e1 == null && e2 == null) { return(0); } if (e1 == null) { return(-1); } else if (e2 == null) { return(1); } if (e1.Source < e2.Source) { return(-1); } else if (e1.Source == e2.Source) { // Use ordering of semantics to sort if (e1.Semantic < e2.Semantic) { return(-1); } else if (e1.Semantic == e2.Semantic) { // Use index to sort if (e1.Index < e2.Index) { return(-1); } else if (e1.Index == e2.Index) { return(0); } } } return(1); }
/// <summary> /// Tests equality of 2 <see cref="VertexElement"/> objects. /// </summary> /// <param name="left">A <see cref="VertexElement"/></param> /// <param name="right">A <see cref="VertexElement"/></param> /// <returns>true if equal, false otherwise.</returns> public static bool operator ==(VertexDeclaration left, VertexDeclaration right) { // if element lists are different sizes, they can't be equal if (left.elements.Count != right.elements.Count) { return(false); } for (int i = 0; i < right.elements.Count; i++) { VertexElement a = left.elements[i]; VertexElement b = right.elements[i]; // if they are not equal, this declaration differs if (!(a == b)) { return(false); } } // if we got thise far, they are equal return(true); }
/// <summary> /// Clones this vertex data, potentially including replicating any vertex buffers. /// </summary> /// <param name="copyData"> /// If true, makes a copy the vertex buffer in addition to the definition. /// If false, the clone will refer to the same vertex buffer this object refers to. /// </param> /// <returns>A cloned vertex data object.</returns> public VertexData Clone(bool copyData) { VertexData dest = new VertexData(); // Copy vertex buffers in turn Dictionary <ushort, HardwareVertexBuffer> bindings = vertexBufferBinding.Bindings; foreach (ushort source in bindings.Keys) { HardwareVertexBuffer srcbuf = bindings[source]; HardwareVertexBuffer dstBuf; if (copyData) { // create new buffer with the same settings dstBuf = HardwareBufferManager.Instance.CreateVertexBuffer( srcbuf.VertexSize, srcbuf.VertexCount, srcbuf.Usage, srcbuf.HasShadowBuffer); // copy data dstBuf.CopyData(srcbuf, 0, 0, srcbuf.Size, true); } else { // don't copy, point at existing buffer dstBuf = srcbuf; } // Copy binding dest.vertexBufferBinding.SetBinding(source, dstBuf); } // Basic vertex info dest.vertexStart = this.vertexStart; dest.vertexCount = this.vertexCount; // Copy elements for (int i = 0; i < vertexDeclaration.ElementCount; i++) { VertexElement element = vertexDeclaration.GetElement(i); dest.vertexDeclaration.AddElement( element.Source, element.Offset, element.Type, element.Semantic, element.Index); } // Copy hardware shadow buffer if set up if (hardwareShadowVolWBuffer != null) { dest.hardwareShadowVolWBuffer = HardwareBufferManager.Instance.CreateVertexBuffer( hardwareShadowVolWBuffer.VertexSize, hardwareShadowVolWBuffer.VertexCount, hardwareShadowVolWBuffer.Usage, hardwareShadowVolWBuffer.HasShadowBuffer); // copy data dest.hardwareShadowVolWBuffer.CopyData( hardwareShadowVolWBuffer, 0, 0, hardwareShadowVolWBuffer.Size, true); } // copy anim data dest.HWAnimationDataList = HWAnimationDataList; dest.HWAnimDataItemsUsed = HWAnimDataItemsUsed; return(dest); }
/// <summary> /// Modifies the definition of a <see cref="VertexElement"/>. /// </summary> /// <param name="elemIndex">Index of the element to modify.</param> /// <param name="source">Source of the element.</param> /// <param name="offset">Offset of the element.</param> /// <param name="type">Type of the element.</param> /// <param name="semantic">Semantic of the element.</param> /// <param name="index">Usage index of the element.</param> public virtual void ModifyElement(int elemIndex, ushort source, int offset, VertexElementType type, VertexElementSemantic semantic, int index) { elements[elemIndex] = new VertexElement(source, offset, type, semantic, index); }
private LineRenderable CreateNormalLines() { List<Vector3> points = new List<Vector3>(); List<ColorEx> colors = new List<ColorEx>(); foreach (SubEntity subEntity in loadedModel.SubEntities) { if (subEntity.IsVisible) { VertexData vData = subEntity.SubMesh.VertexData; VertexElement[] elems = new VertexElement[4]; elems[0] = vData.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.Position); elems[1] = vData.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.Normal); elems[2] = vData.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.Tangent); elems[3] = vData.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.Binormal); HardwareVertexBuffer[] vBuffers = new HardwareVertexBuffer[4]; for (int i = 0; i < 4; ++i) { if (elems[i] == null) vBuffers[i] = null; else vBuffers[i] = vData.vertexBufferBinding.Bindings[elems[i].Source]; } Vector3[] positionVectors = ReadBuffer(vBuffers[0], elems[0], vData.vertexCount); Vector3[] normalVectors = ReadBuffer(vBuffers[1], elems[1], vData.vertexCount); Vector3[] tangentVectors = ReadBuffer(vBuffers[2], elems[2], vData.vertexCount); Vector3[] binormalVectors = ReadBuffer(vBuffers[3], elems[3], vData.vertexCount); for (int i = 0; i < vData.vertexCount; ++i) BuildAxisLines(points, colors, positionVectors[i], normalsAxisLength * normalVectors[i], normalsAxisLength * tangentVectors[i], normalsAxisLength * binormalVectors[i]); } } if (points.Count == 0) return null; LineRenderable lines = new LineRenderable(); lines.SetPoints(points, colors); lines.MaterialName = "MVLines"; return lines; }
/// <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); } }
protected void BindVertexElementToGpu( VertexElement elem, HardwareVertexBuffer vertexBuffer, int vertexStart, IList<int> attribsBound, IList<int> instanceAttribsBound ) { IntPtr pBufferData; var hwGlBuffer = (GLHardwareVertexBuffer)vertexBuffer; if ( currentCapabilities.HasCapability( Graphics.Capabilities.VertexBuffer ) ) { Gl.glBindBufferARB( Gl.GL_ARRAY_BUFFER_ARB, hwGlBuffer.GLBufferID ); pBufferData = BUFFER_OFFSET( elem.Offset ); } else { // ReSharper disable PossibleInvalidCastException pBufferData = ( (GLDefaultHardwareVertexBuffer)( vertexBuffer ) ).DataPtr( elem.Offset ); // ReSharper restore PossibleInvalidCastException } if ( vertexStart != 0 ) { pBufferData = pBufferData.Offset( vertexStart*vertexBuffer.VertexSize ); } var sem = elem.Semantic; var multitexturing = Capabilities.TextureUnitCount > 1; var isCustomAttrib = false; if ( this.currentVertexProgram != null ) { isCustomAttrib = this.currentVertexProgram.IsAttributeValid( sem, (uint)elem.Index ); if ( hwGlBuffer.IsInstanceData ) { var attrib = this.currentVertexProgram.AttributeIndex( sem, (uint)elem.Index ); glVertexAttribDivisor( (int)attrib, hwGlBuffer.InstanceDataStepRate ); instanceAttribsBound.Add( (int)attrib ); } } // Custom attribute support // tangents, binormals, blendweights etc always via this route // builtins may be done this way too if ( isCustomAttrib ) { var attrib = this.currentVertexProgram.AttributeIndex( sem, (uint)elem.Index ); var typeCount = VertexElement.GetTypeCount( elem.Type ); var normalised = Gl.GL_FALSE; switch ( elem.Type ) { case VertexElementType.Color: case VertexElementType.Color_ABGR: case VertexElementType.Color_ARGB: // Because GL takes these as a sequence of single unsigned bytes, count needs to be 4 // VertexElement::getTypeCount treats them as 1 (RGBA) // Also need to normalise the fixed-point data typeCount = 4; normalised = Gl.GL_TRUE; break; default: break; } Gl.glVertexAttribPointerARB( attrib, typeCount, GLHardwareBufferManager.GetGLType( elem.Type ), normalised, vertexBuffer.VertexSize, pBufferData ); Gl.glEnableVertexAttribArrayARB( attrib ); attribsBound.Add( (int)attrib ); } else { // fixed-function & builtin attribute support switch ( sem ) { case VertexElementSemantic.Position: Gl.glVertexPointer( VertexElement.GetTypeCount( elem.Type ), GLHardwareBufferManager.GetGLType( elem.Type ), vertexBuffer.VertexSize, pBufferData ); Gl.glEnableClientState( Gl.GL_VERTEX_ARRAY ); break; case VertexElementSemantic.Normal: Gl.glNormalPointer( GLHardwareBufferManager.GetGLType( elem.Type ), vertexBuffer.VertexSize, pBufferData ); Gl.glEnableClientState( Gl.GL_NORMAL_ARRAY ); break; case VertexElementSemantic.Diffuse: Gl.glColorPointer( 4, GLHardwareBufferManager.GetGLType( elem.Type ), vertexBuffer.VertexSize, pBufferData ); Gl.glEnableClientState( Gl.GL_COLOR_ARRAY ); break; case VertexElementSemantic.Specular: if ( this.GLEW_EXT_secondary_color ) { Gl.glSecondaryColorPointerEXT( 4, GLHardwareBufferManager.GetGLType( elem.Type ), vertexBuffer.VertexSize, pBufferData ); Gl.glEnableClientState( Gl.GL_SECONDARY_COLOR_ARRAY ); } break; case VertexElementSemantic.TexCoords: if ( this.currentVertexProgram != null ) { // Programmable pipeline - direct UV assignment Gl.glClientActiveTextureARB( Gl.GL_TEXTURE0 + elem.Index ); Gl.glTexCoordPointer( VertexElement.GetTypeCount( elem.Type ), GLHardwareBufferManager.GetGLType( elem.Type ), vertexBuffer.VertexSize, pBufferData ); Gl.glEnableClientState( Gl.GL_TEXTURE_COORD_ARRAY ); } else { // fixed function matching to units based on tex_coord_set for ( var i = 0; i < disabledTexUnitsFrom; i++ ) { // Only set this texture unit's texcoord pointer if it // is supposed to be using this element's index if ( this.texCoordIndex[ i ] != elem.Index || i >= this._fixedFunctionTextureUnits ) { continue; } if ( multitexturing ) { Gl.glClientActiveTextureARB( Gl.GL_TEXTURE0 + i ); } Gl.glTexCoordPointer( VertexElement.GetTypeCount( elem.Type ), GLHardwareBufferManager.GetGLType( elem.Type ), vertexBuffer.VertexSize, pBufferData ); Gl.glEnableClientState( Gl.GL_TEXTURE_COORD_ARRAY ); } } break; default: break; } } // isCustomAttrib }
/// <summary> /// Inserts a new <see cref="VertexElement"/> at a given position in this declaration. /// </summary> /// <remarks> /// This method adds a single element (positions, normals etc) at a given position in this /// vertex declaration. <b>Please read the information in VertexDeclaration about /// the importance of ordering and structure for compatibility with older D3D drivers</b>. /// </remarks> /// <param name="position">Position to insert into.</param> /// <param name="source">The binding index of HardwareVertexBuffer which will provide the source for this element.</param> /// <param name="offset">The offset in bytes where this element is located in the buffer.</param> /// <param name="type">The data format of the element (3 floats, a color, etc).</param> /// <param name="semantic">The meaning of the data (position, normal, diffuse color etc).</param> /// <param name="index">Optional index for multi-input elements like texture coordinates.</param> /// <returns>A reference to the newly created element.</returns> public virtual VertexElement InsertElement(int position, ushort source, int offset, VertexElementType type, VertexElementSemantic semantic, int index) { if(position >= elements.Count) { return AddElement(source, offset, type, semantic, index); } VertexElement element = new VertexElement(source, offset, type, semantic, index); elements.Insert(position, element); return element; }
/// <summary> /// Adds a new VertexElement to this declaration. /// </summary> /// <remarks> /// This method adds a single element (positions, normals etc) to the /// vertex declaration. <b>Please read the information in <see cref="VertexDeclaration"/> about /// the importance of ordering and structure for compatibility with older D3D drivers</b>. /// </remarks> /// <param name="source"> /// The binding index of HardwareVertexBuffer which will provide the source for this element. /// </param> /// <param name="offset">The offset in bytes where this element is located in the buffer.</param> /// <param name="type">The data format of the element (3 floats, a color etc).</param> /// <param name="semantic">The meaning of the data (position, normal, diffuse color etc).</param> /// <param name="index">Optional index for multi-input elements like texture coordinates.</param> public virtual VertexElement AddElement(ushort source, int offset, VertexElementType type, VertexElementSemantic semantic, int index) { VertexElement element = new VertexElement(source, offset, type, semantic, index); elements.Add(element); return element; }
/// <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 }
public List <TriangleVertices> Build() { List <TriangleVertices> triangles = new List <TriangleVertices>(); try { for (int ind = 0, indexSet = 0; ind < indexDataList.Count; ind++, indexSet++) { int vertexSet = (int)indexDataVertexDataSetList[ind]; IndexData indexData = (IndexData)indexDataList[indexSet]; OperationType opType = operationTypes[indexSet]; int iterations = 0; switch (opType) { case OperationType.TriangleList: iterations = indexData.indexCount / 3; break; case OperationType.TriangleFan: case OperationType.TriangleStrip: iterations = indexData.indexCount - 2; break; } // locate position element & the buffer to go with it VertexData vertexData = (VertexData)vertexDataList[vertexSet]; VertexElement posElem = vertexData.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.Position); HardwareVertexBuffer posBuffer = vertexData.vertexBufferBinding.GetBuffer(posElem.Source); try { IntPtr posPtr = posBuffer.Lock(BufferLocking.ReadOnly); IntPtr idxPtr = indexData.indexBuffer.Lock(BufferLocking.ReadOnly); unsafe { byte *pBaseVertex = (byte *)posPtr.ToPointer(); ushort *p16Idx = null; uint * p32Idx = null; // counters used for pointer indexing int count16 = 0; int count32 = 0; if (indexData.indexBuffer.Type == IndexType.Size16) { p16Idx = (ushort *)idxPtr.ToPointer(); } else { p32Idx = (uint *)idxPtr.ToPointer(); } float *pReal = null; int triStart = triangles.Count; // iterate over all the groups of 3 indices triangles.Capacity = triStart + iterations; uint[] index = new uint[3]; for (int t = 0; t < iterations; t++) { Vector3[] v = new Vector3[3]; TriangleVertices tri = new TriangleVertices(v); bool broken = false; for (int i = 0; i < 3; i++) { // Standard 3-index read for tri list or first tri in strip / fan if (opType == OperationType.TriangleList || t == 0) { if (indexData.indexBuffer.Type == IndexType.Size32) { index[i] = p32Idx[count32++]; } else { index[i] = p16Idx[count16++]; } } else { // Strips and fans are formed from last 2 indexes plus the // current one for triangles after the first if (indexData.indexBuffer.Type == IndexType.Size32) { index[i] = p32Idx[i - 2]; } else { index[i] = p16Idx[i - 2]; } // Perform single-index increment at the last tri index if (i == 2) { if (indexData.indexBuffer.Type == IndexType.Size32) { count32++; } else { count16++; } } } // Retrieve the vertex position if (index[i] >= posBuffer.VertexCount) { log.InfoFormat("TriangleListBuilder.Build: Error: index[i] {0} is not less than posBuffer.VertexCount {1}, iteration t {2}", index[i], posBuffer.VertexCount, t); broken = true; break; } Debug.Assert(index[i] < posBuffer.VertexCount); byte *pVertex = pBaseVertex + (index[i] * posBuffer.VertexSize); pReal = (float *)(pVertex + posElem.Offset); v[i].x = *pReal++; v[i].y = *pReal++; v[i].z = *pReal++; } if (!broken) { // Put the points in in counter-clockwise order if (((v[0].x - v[2].x) * (v[1].y - v[2].y) - (v[1].x - v[2].x) * (v[0].y - v[2].y)) < 0) { // Clockwise, so reverse points 1 and 2 Vector3 tmp = v[1]; v[1] = v[2]; v[2] = tmp; } // Debug.Assert(((v[0].x - v[2].x) * (v[1].y - v[2].y) - (v[1].x - v[2].x) * (v[0].y - v[2].y)) >= 0); // Add to the list of triangles triangles.Add(new TriangleVertices(v)); } } // for iterations } // unsafe } finally { // unlock those buffers! indexData.indexBuffer.Unlock(); posBuffer.Unlock(); } } return(triangles); } catch (Exception e) { log.ErrorFormat("TriangleListBuilder.Build: Exception raised during triangle building: {0}", e.Message); triangles.Clear(); return(triangles); } }
/// <summary> /// /// </summary> /// <param name="indexSet"></param> /// <param name="vertexSet"></param> protected void BuildTrianglesEdges(int indexSet, int vertexSet) { IndexData indexData = (IndexData)indexDataList[indexSet]; OperationType opType = operationTypes[indexSet]; int iterations = 0; switch (opType) { case OperationType.TriangleList: iterations = indexData.indexCount / 3; break; case OperationType.TriangleFan: case OperationType.TriangleStrip: iterations = indexData.indexCount - 2; break; } // locate postion element & the buffer to go with it VertexData vertexData = (VertexData)vertexDataList[vertexSet]; VertexElement posElem = vertexData.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.Position); HardwareVertexBuffer posBuffer = vertexData.vertexBufferBinding.GetBuffer(posElem.Source); IntPtr posPtr = posBuffer.Lock(BufferLocking.ReadOnly); IntPtr idxPtr = indexData.indexBuffer.Lock(BufferLocking.ReadOnly); unsafe { byte *pBaseVertex = (byte *)posPtr.ToPointer(); short *p16Idx = null; int * p32Idx = null; // counters used for pointer indexing int count16 = 0; int count32 = 0; if (indexData.indexBuffer.Type == IndexType.Size16) { p16Idx = (short *)idxPtr.ToPointer(); } else { p32Idx = (int *)idxPtr.ToPointer(); } float *pReal = null; int triStart = edgeData.triangles.Count; // iterate over all the groups of 3 indices edgeData.triangles.Capacity = triStart + iterations; for (int t = 0; t < iterations; t++) { EdgeData.Triangle tri = new EdgeData.Triangle(); tri.indexSet = indexSet; tri.vertexSet = vertexSet; int[] index = new int[3]; Vector3[] v = new Vector3[3]; for (int i = 0; i < 3; i++) { // Standard 3-index read for tri list or first tri in strip / fan if (opType == OperationType.TriangleList || t == 0) { if (indexData.indexBuffer.Type == IndexType.Size32) { index[i] = p32Idx[count32++]; } else { index[i] = p16Idx[count16++]; } } else { // Strips and fans are formed from last 2 indexes plus the // current one for triangles after the first if (indexData.indexBuffer.Type == IndexType.Size32) { index[i] = p32Idx[i - 2]; } else { index[i] = p16Idx[i - 2]; } // Perform single-index increment at the last tri index if (i == 2) { if (indexData.indexBuffer.Type == IndexType.Size32) { count32++; } else { count16++; } } } // populate tri original vertex index tri.vertIndex[i] = index[i]; // Retrieve the vertex position byte *pVertex = pBaseVertex + (index[i] * posBuffer.VertexSize); pReal = (float *)(pVertex + posElem.Offset); v[i].x = *pReal++; v[i].y = *pReal++; v[i].z = *pReal++; // find this vertex in the existing vertex map, or create it tri.sharedVertIndex[i] = FindOrCreateCommonVertex(v[i], vertexSet, indexSet, index[i]); } // Calculate triangle normal (NB will require recalculation for // skeletally animated meshes) tri.normal = MathUtil.CalculateFaceNormal(v[0], v[1], v[2]); // Add triangle to list edgeData.triangles.Add(tri); try { // create edges from common list if (tri.sharedVertIndex[0] < tri.sharedVertIndex[1]) { CreateEdge(vertexSet, triStart + t, tri.vertIndex[0], tri.vertIndex[1], tri.sharedVertIndex[0], tri.sharedVertIndex[1]); } if (tri.sharedVertIndex[1] < tri.sharedVertIndex[2]) { CreateEdge(vertexSet, triStart + t, tri.vertIndex[1], tri.vertIndex[2], tri.sharedVertIndex[1], tri.sharedVertIndex[2]); } if (tri.sharedVertIndex[2] < tri.sharedVertIndex[0]) { CreateEdge(vertexSet, triStart + t, tri.vertIndex[2], tri.vertIndex[0], tri.sharedVertIndex[2], tri.sharedVertIndex[0]); } } catch (Exception ex) { //Debug.WriteLine(ex.ToString()); //Debug.WriteLine(ex.StackTrace); // unlock those buffers! indexData.indexBuffer.Unlock(); posBuffer.Unlock(); throw ex; } } // for iterations } // unsafe // unlock those buffers! indexData.indexBuffer.Unlock(); posBuffer.Unlock(); }
private static Vector3[] ReadBuffer(HardwareVertexBuffer vBuffer, VertexElement elem, int vertexCount) { Vector3[] rv = new Vector3[vertexCount]; if (vBuffer == null) { for (int i = 0; i < vertexCount; ++i) rv[i] = Vector3.Zero; return rv; } float[,] data = new float[vertexCount, 3]; HardwareBufferHelper.ReadBuffer( data, vBuffer, elem ); for (int i = 0; i < vertexCount; ++i) for (int j = 0; j < 3; ++j) rv[i][j] = data[i, j]; return rv; }
public unsafe void DebugLog(Log log) { log.Write("EdgeListBuilder Log"); log.Write("-------------------"); log.Write("Number of vertex sets: {0}", vertexDataList.Count); log.Write("Number of index sets: {0}", indexDataList.Count); int i, j; // Log original vertex data for (i = 0; i < vertexDataList.Count; i++) { VertexData vData = (VertexData)vertexDataList[i]; log.Write("."); log.Write("Original vertex set {0} - vertex count {1}", i, vData.vertexCount); VertexElement posElem = vData.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.Position); HardwareVertexBuffer vbuf = vData.vertexBufferBinding.GetBuffer(posElem.Source); // lock the buffer for reading IntPtr basePtr = vbuf.Lock(BufferLocking.ReadOnly); byte *pBaseVertex = (byte *)basePtr.ToPointer(); float *pReal; for (j = 0; j < vData.vertexCount; j++) { pReal = (float *)(pBaseVertex + posElem.Offset); log.Write("Vertex {0}: ({1}, {2}, {3})", j, pReal[0], pReal[1], pReal[2]); pBaseVertex += vbuf.VertexSize; } vbuf.Unlock(); } // Log original index data for (i = 0; i < indexDataList.Count; i += 3) { IndexData iData = (IndexData)indexDataList[i]; log.Write("."); log.Write("Original triangle set {0} - index count {1} - vertex set {2})", i, iData.indexCount, indexDataVertexDataSetList[i]); // Get the indexes ready for reading short *p16Idx = null; int * p32Idx = null; IntPtr idxPtr = iData.indexBuffer.Lock(BufferLocking.ReadOnly); if (iData.indexBuffer.Type == IndexType.Size32) { p32Idx = (int *)idxPtr.ToPointer(); } else { p16Idx = (short *)idxPtr.ToPointer(); } for (j = 0; j < iData.indexCount / 3; j++) { if (iData.indexBuffer.Type == IndexType.Size32) { log.Write("Triangle {0}: ({1}, {2}, {3})", j, *p32Idx++, *p32Idx++, *p32Idx++); } else { log.Write("Triangle {0}: ({1}, {2}, {3})", j, *p16Idx++, *p16Idx++, *p16Idx++); } } iData.indexBuffer.Unlock(); // Log common vertex list log.Write("."); log.Write("Common vertex list - vertex count {0}", vertices.Count); for (i = 0; i < vertices.Count; i++) { CommonVertex c = (CommonVertex)vertices[i]; log.Write("Common vertex {0}: (vertexSet={1}, originalIndex={2}, position={3}", i, c.vertexSet, c.index, c.position); } } }
protected void WriteGeometryVertexElement( BinaryWriter writer, VertexElement vertexElement ) { var start_offset = writer.Seek( 0, SeekOrigin.Current ); WriteChunk( writer, MeshChunkID.GeometryVertexElement, 0 ); WriteUShort( writer, (ushort)vertexElement.Source ); WriteUShort( writer, (ushort)vertexElement.Type ); WriteUShort( writer, (ushort)vertexElement.Semantic ); WriteUShort( writer, (ushort)vertexElement.Offset ); WriteUShort( writer, (ushort)vertexElement.Index ); var end_offset = writer.Seek( 0, SeekOrigin.Current ); writer.Seek( (int)start_offset, SeekOrigin.Begin ); WriteChunk( writer, MeshChunkID.GeometryVertexElement, (int)( end_offset - start_offset ) ); writer.Seek( (int)end_offset, SeekOrigin.Begin ); }
protected void SetPointsImpl(List <Vector3> points, List <ColorEx> colors, List <List <VertexBoneAssignment> > boneAssignments) { if (colors != null && points.Count != colors.Count) { throw new Exception("Invalid parameters to SetPoints. Point list length does not match colors list length"); } Vector3 min = Vector3.Zero; Vector3 max = Vector3.Zero; // set up vertex data vertexData = new VertexData(); // set up vertex declaration VertexDeclaration vertexDeclaration = vertexData.vertexDeclaration; int currentOffset = 0; // always need positions vertexDeclaration.AddElement(0, currentOffset, VertexElementType.Float3, VertexElementSemantic.Position); currentOffset += VertexElement.GetTypeSize(VertexElementType.Float3); int colorOffset = currentOffset / sizeof(float); if (colors != null) { vertexDeclaration.AddElement(0, currentOffset, VertexElementType.Color, VertexElementSemantic.Diffuse); currentOffset += VertexElement.GetTypeSize(VertexElementType.Color); } int boneIndexOffset = currentOffset / sizeof(float); if (boneAssignments != null) { vertexDeclaration.AddElement(0, currentOffset, VertexElementType.UByte4, VertexElementSemantic.BlendIndices); currentOffset += VertexElement.GetTypeSize(VertexElementType.UByte4); } int boneWeightOffset = currentOffset / sizeof(float); if (boneAssignments != null) { vertexDeclaration.AddElement(0, currentOffset, VertexElementType.Float4, VertexElementSemantic.BlendWeights); currentOffset += VertexElement.GetTypeSize(VertexElementType.Float4); } int stride = currentOffset / sizeof(float); vertexData.vertexCount = points.Count; // allocate vertex buffer HardwareVertexBuffer vertexBuffer = HardwareBufferManager.Instance.CreateVertexBuffer(vertexDeclaration.GetVertexSize(0), vertexData.vertexCount, BufferUsage.StaticWriteOnly); // set up the binding, one source only VertexBufferBinding binding = vertexData.vertexBufferBinding; binding.SetBinding(0, vertexBuffer); // Generate vertex data unsafe { // lock the vertex buffer IntPtr data = vertexBuffer.Lock(BufferLocking.Discard); byte * pData = (byte *)data.ToPointer(); float *pFloat = (float *)pData; uint * pInt = (uint *)pData; for (int i = 0; i < points.Count; ++i) { Vector3 vec = points[i]; // assign to geometry pFloat[stride * i] = vec.x; pFloat[stride * i + 1] = vec.y; pFloat[stride * i + 2] = vec.z; if (colors != null) { // assign to diffuse pInt[stride * i + colorOffset] = Root.Instance.RenderSystem.ConvertColor(colors[i]); } if (boneAssignments != null) { for (int j = 0; j < 4; ++j) { pData[4 * (stride * i + boneIndexOffset) + j] = (byte)(boneAssignments[i][j].boneIndex); pFloat[stride * i + boneWeightOffset + j] = boneAssignments[i][j].weight; } } } // unlock the buffer vertexBuffer.Unlock(); } // unsafe for (int i = 0; i < points.Count; ++i) { Vector3 vec = points[i]; // Also update the bounding sphere radius float len = vec.Length; if (len > boundingSphereRadius) { boundingSphereRadius = len; } // Also update the bounding box if (vec.x < min.x) { min.x = vec.x; } if (vec.y < min.y) { min.y = vec.y; } if (vec.z < min.z) { min.z = vec.z; } if (vec.x > max.x) { max.x = vec.x; } if (vec.y > max.y) { max.y = vec.y; } if (vec.z > max.z) { max.z = vec.z; } } // Set the SimpleRenderable bounding box box = new AxisAlignedBox(min, max); }