/// <summary> /// Internal method that forces the release of copies of a given buffer. /// </summary> /// <remarks> /// This usually means that the buffer which the copies are based on has /// been changed in some fundamental way, and the owner of the original /// wishes to make that known so that new copies will reflect the changes. /// </remarks> /// <param name="sourceBuffer">Buffer to release temp copies of.</param> internal void ForceReleaseBufferCopies(HardwareVertexBuffer sourceBuffer) { // erase the copies which are licensed out for (int i = tempVertexBufferLicenses.Count - 1; i >= 0; i--) { VertexBufferLicense vbl = (VertexBufferLicense)tempVertexBufferLicenses[i]; if (vbl.originalBuffer == sourceBuffer) { // Just tell the owner that this is being released vbl.licensee.LicenseExpired(vbl.buffer); tempVertexBufferLicenses.RemoveAt(i); } } // TODO: Verify this works foreach (DictionaryEntry entry in freeTempVertexBufferMap) { if (entry.Key == sourceBuffer) { ArrayList list = (ArrayList)entry.Value; list.Clear(); } } }
/// <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(); }
/// <summary> /// Updates the face normals for this edge list based on (changed) /// position information, useful for animated objects. /// </summary> /// <param name="vertexSet">The vertex set we are updating.</param> /// <param name="positionBuffer">The updated position buffer, must contain ONLY xyz.</param> public void UpdateFaceNormals(int vertexSet, HardwareVertexBuffer positionBuffer) { unsafe { Debug.Assert(positionBuffer.VertexSize == sizeof(float) * 3, "Position buffer should contain only positions!"); // Lock buffer for reading IntPtr posPtr = positionBuffer.Lock(BufferLocking.ReadOnly); float *pVert = (float *)posPtr.ToPointer(); // Iterate over the triangles for (int i = 0; i < triangles.Count; i++) { Triangle t = (Triangle)triangles[i]; // Only update tris which are using this vertex set if (t.vertexSet == vertexSet) { int offset = t.vertIndex[0] * 3; Vector3 v1 = new Vector3(pVert[offset], pVert[offset + 1], pVert[offset + 2]); offset = t.vertIndex[1] * 3; Vector3 v2 = new Vector3(pVert[offset], pVert[offset + 1], pVert[offset + 2]); offset = t.vertIndex[2] * 3; Vector3 v3 = new Vector3(pVert[offset], pVert[offset + 1], pVert[offset + 2]); t.normal = MathUtil.CalculateFaceNormal(v1, v2, v3); } } } // unlock the buffer positionBuffer.Unlock(); }
public virtual void RegisterVertexBufferSourceAndCopy(HardwareVertexBuffer sourceBuffer, HardwareVertexBuffer copy) { lock (TempBuffersMutex) { // Add copy to free temporary vertex buffers this.freeTempVertexBufferMap.Add(sourceBuffer, copy); } }
/// <summary> /// Gets the buffer bound to the given source index. /// </summary> /// <param name="index">Index of the binding to retreive the buffer for.</param> /// <returns>Buffer at the specified index.</returns> public virtual HardwareVertexBuffer GetBuffer(ushort index) { Debug.Assert(bindingMap.ContainsKey(index), "No buffer is bound to index " + index); HardwareVertexBuffer buf = bindingMap[index]; return(buf); }
/// <summary> /// /// </summary> public VertexBufferLicense(HardwareVertexBuffer originalBuffer, BufferLicenseRelease licenseType, int expiredDelay, HardwareVertexBuffer buffer, IHardwareBufferLicensee licensee) { this.originalBuffer = originalBuffer; this.licenseType = licenseType; this.expiredDelay = expiredDelay; this.buffer = buffer; this.licensee = licensee; }
/// <summary> /// Implementation of LicenseExpired. /// </summary> /// <param name="buffer"></param> public void LicenseExpired(HardwareBuffer buffer) { if (buffer == destPositionBuffer) { destPositionBuffer = null; } if (buffer == destNormalBuffer) { destNormalBuffer = null; } }
/// <summary> /// Utility method, checks out temporary copies of src into dest. /// </summary> public void CheckoutTempCopies(bool positions, bool normals, bool tangents, bool binormals) { bindPositions = positions; bindNormals = normals; bindTangents = tangents; bindBinormals = binormals; if (bindPositions && destPositionBuffer == null) { destPositionBuffer = HardwareBufferManager.Instance.AllocateVertexBufferCopy( srcPositionBuffer, BufferLicenseRelease.Automatic, this); } if (bindNormals && !posNormalShareBuffer && srcNormalBuffer != null && destNormalBuffer == null) { destNormalBuffer = HardwareBufferManager.Instance.AllocateVertexBufferCopy( srcNormalBuffer, BufferLicenseRelease.Automatic, this); } if (bindTangents && srcTangentBuffer != null) { if (this.tanBindIndex != this.posBindIndex && this.tanBindIndex != this.normBindIndex) { destTangentBuffer = HardwareBufferManager.Instance.AllocateVertexBufferCopy( srcTangentBuffer, BufferLicenseRelease.Automatic, this); } } if (bindNormals && srcBinormalBuffer != null) { if (this.binormBindIndex != this.posBindIndex && this.binormBindIndex != this.normBindIndex && this.binormBindIndex != this.tanBindIndex) { destBinormalBuffer = HardwareBufferManager.Instance.AllocateVertexBufferCopy( srcBinormalBuffer, BufferLicenseRelease.Automatic, this); } } }
/// <summary> /// Manually release a vertex buffer copy for others to subsequently use. /// </summary> /// <remarks> /// Only required if the original call to <see cref="AllocateVertexBufferCopy"/> /// included a licenseType of <see cref="BufferLicenseRelease.Manual"/>. /// </remarks> /// <param name="bufferCopy"> /// The buffer copy. The caller is expected to no longer use this reference, /// since another user may well begin to modify the contents of the buffer. /// </param> public virtual void ReleaseVertexBufferCopy(HardwareVertexBuffer bufferCopy) { for (int i = 0; i < tempVertexBufferLicenses.Count; i++) { VertexBufferLicense vbl = (VertexBufferLicense)tempVertexBufferLicenses[i]; if (vbl.buffer != bufferCopy) { continue; } vbl.licensee.LicenseExpired(bufferCopy); tempVertexBufferLicenses.RemoveAt(i); return; } }
/// <summary> /// Tell engine that the vertex buffer copy intent to reuse. /// </summary> /// <remarks> /// Ogre internal keep an expired delay counter of BLT_AUTOMATIC_RELEASE /// buffers, when the counter count down to zero, it'll release for other /// purposes later. But you can use this function to reset the counter to /// the internal configured value, keep the buffer not get released for /// some frames. /// </remarks> /// <param name="bufferCopy" The buffer copy. The caller is expected to keep this /// buffer copy for use.</param> public void TouchVertexBufferCopy(HardwareVertexBuffer bufferCopy) { for (int i = 0; i < tempVertexBufferLicenses.Count; i++) { VertexBufferLicense vbl = (VertexBufferLicense)tempVertexBufferLicenses[i]; if (vbl.buffer != bufferCopy) { continue; } Debug.Assert(vbl.licenseType == BufferLicenseRelease.Automatic); vbl.expiredDelay = expiredDelayFrameThreshold; } }
/// <summary> /// Sets the corners of the rectangle, in relative coordinates. /// </summary> /// <param name="left">Left position in screen relative coordinates, -1 = left edge, 1.0 = right edge.</param> /// <param name="top">Top position in screen relative coordinates, 1 = top edge, -1 = bottom edge.</param> /// <param name="right">Position in screen relative coordinates.</param> /// <param name="bottom">Position in screen relative coordinates.</param> public void SetCorners(float left, float top, float right, float bottom) { float[] data = new float[] { left, top, -1, left, bottom, -1, right, top, -1, right, bottom, -1 }; HardwareVertexBuffer buffer = vertexData.vertexBufferBinding.GetBuffer(POSITION); buffer.WriteData(0, buffer.Size, data, true); box = new AxisAlignedBox(); box.SetExtents(new Vector3(left, top, 0), new Vector3(right, bottom, 0)); }
/// <summary> /// Utility method for extruding vertices based on a light. /// </summary> /// <remarks> /// Unfortunately, because D3D cannot handle homogenous (4D) position /// coordinates in the fixed-function pipeline (GL can, but we have to /// be cross-API), when we extrude in software we cannot extrude to /// infinity the way we do in the vertex program (by setting w to /// 0.0f). Therefore we extrude by a fixed distance, which may cause /// some problems with larger scenes. Luckily better hardware (ie /// vertex programs) can fix this. /// </remarks> /// <param name="vertexBuffer">The vertex buffer containing ONLY xyz position /// values, which must be originalVertexCount * 2 * 3 floats long.</param> /// <param name="originalVertexCount">The count of the original number of /// vertices, ie the number in the mesh, not counting the doubling /// which has already been done (by <see cref="VertexData.PrepareForShadowVolume"/>) /// to provide the extruded area of the buffer.</param> /// <param name="lightPosition"> 4D light position in object space, when w=0.0f this /// represents a directional light</param> /// <param name="extrudeDistance">The distance to extrude.</param> public static void ExtrudeVertices(HardwareVertexBuffer vertexBuffer, int originalVertexCount, Vector4 lightPosition, float extrudeDistance) { #if !AXIOM_SAFE_ONLY unsafe #endif { Debug.Assert(vertexBuffer.VertexSize == sizeof(float) * 3, "Position buffer should contain only positions!"); // Extrude the first area of the buffer into the second area // Lock the entire buffer for writing, even though we'll only be // updating the latter because you can't have 2 locks on the same // buffer var srcPtr = vertexBuffer.Lock(BufferLocking.Normal); var destPtr = srcPtr + (originalVertexCount * 3 * 4); var pSrc = srcPtr.ToFloatPointer(); var pDest = destPtr.ToFloatPointer(); int destCount = 0, srcCount = 0; // Assume directional light, extrusion is along light direction var extrusionDir = new Vector3(-lightPosition.x, -lightPosition.y, -lightPosition.z); extrusionDir.Normalize(); extrusionDir *= extrudeDistance; for (var vert = 0; vert < originalVertexCount; vert++) { if (lightPosition.w != 0.0f) { // Point light, adjust extrusionDir extrusionDir.x = pSrc[srcCount + 0] - lightPosition.x; extrusionDir.y = pSrc[srcCount + 1] - lightPosition.y; extrusionDir.z = pSrc[srcCount + 2] - lightPosition.z; extrusionDir.Normalize(); extrusionDir *= extrudeDistance; } pDest[destCount++] = pSrc[srcCount++] + extrusionDir.x; pDest[destCount++] = pSrc[srcCount++] + extrusionDir.y; pDest[destCount++] = pSrc[srcCount++] + extrusionDir.z; } } vertexBuffer.Unlock(); }
private static void ReadBuffer(HardwareVertexBuffer vBuffer, int vertexCount, int vertexSize, ref Vector3[] data) { IntPtr bufData = vBuffer.Lock(BufferLocking.ReadOnly); unsafe { float* pFloats = (float*)bufData.ToPointer(); for (int i = 0; i < vertexCount; ++i) for (int j = 0; j < 3; ++j) { Debug.Assert(sizeof(float) * (i * 3 + j) < vertexCount * vertexSize, "Read off end of vertex buffer"); data[i][j] = pFloats[i * 3 + j]; } } // unlock the buffer vBuffer.Unlock(); }
/// <summary> /// Utility method for extruding vertices based on a light. /// </summary> /// <remarks> /// Unfortunately, because D3D cannot handle homogenous (4D) position /// coordinates in the fixed-function pipeline (GL can, but we have to /// be cross-API), when we extrude in software we cannot extrude to /// infinity the way we do in the vertex program (by setting w to /// 0.0f). Therefore we extrude by a fixed distance, which may cause /// some problems with larger scenes. Luckily better hardware (ie /// vertex programs) can fix this. /// </remarks> /// <param name="vertexBuffer">The vertex buffer containing ONLY xyz position /// values, which must be originalVertexCount * 2 * 3 floats long.</param> /// <param name="originalVertexCount">The count of the original number of /// vertices, ie the number in the mesh, not counting the doubling /// which has already been done (by <see cref="VertexData.PrepareForShadowVolume"/>) /// to provide the extruded area of the buffer.</param> /// <param name="lightPosition"> 4D light position in object space, when w=0.0f this /// represents a directional light</param> /// <param name="extrudeDistance">The distance to extrude.</param> public static void ExtrudeVertices(HardwareVertexBuffer vertexBuffer, int originalVertexCount, Vector4 lightPosition, float extrudeDistance) { unsafe { Debug.Assert(vertexBuffer.VertexSize == sizeof(float) * 3, "Position buffer should contain only positions!"); // Extrude the first area of the buffer into the second area // Lock the entire buffer for writing, even though we'll only be // updating the latter because you can't have 2 locks on the same // buffer IntPtr srcPtr = vertexBuffer.Lock(BufferLocking.Normal); IntPtr destPtr = new IntPtr(srcPtr.ToInt32() + (originalVertexCount * 3 * 4)); float* pSrc = (float*)srcPtr.ToPointer(); float* pDest = (float*)destPtr.ToPointer(); int destCount = 0, srcCount = 0; // Assume directional light, extrusion is along light direction Vector3 extrusionDir = new Vector3(-lightPosition.x, -lightPosition.y, -lightPosition.z); extrusionDir.Normalize(); extrusionDir *= extrudeDistance; for (int vert = 0; vert < originalVertexCount; vert++) { if (lightPosition.w != 0.0f) { // Point light, adjust extrusionDir extrusionDir.x = pSrc[srcCount + 0] - lightPosition.x; extrusionDir.y = pSrc[srcCount + 1] - lightPosition.y; extrusionDir.z = pSrc[srcCount + 2] - lightPosition.z; extrusionDir.Normalize(); extrusionDir *= extrudeDistance; } pDest[destCount++] = pSrc[srcCount++] + extrusionDir.x; pDest[destCount++] = pSrc[srcCount++] + extrusionDir.y; pDest[destCount++] = pSrc[srcCount++] + extrusionDir.z; } } vertexBuffer.Unlock(); }
/// <summary> /// Allocates a copy of a given vertex buffer. /// </summary> /// <remarks> /// This method allocates a temporary copy of an existing vertex buffer. /// This buffer is subsequently stored and can be made available for /// other purposes later without incurring the cost of construction / /// destruction. /// </remarks> /// <param name="sourceBuffer">The source buffer to use as a copy.</param> /// <param name="licenseType"> /// The type of license required on this buffer - automatic /// release causes this class to release licenses every frame so that /// they can be reallocated anew. /// </param> /// <param name="licensee"> /// Reference back to the class requesting the copy, which must /// implement <see cref="IHardwareBufferLicense"/> in order to be notified when the license /// expires. /// </param> /// <param name="copyData">If true, the current data is copied as well as the structure of the buffer.</param> /// <returns></returns> public virtual HardwareVertexBuffer AllocateVertexBufferCopy(HardwareVertexBuffer sourceBuffer, BufferLicenseRelease licenseType, IHardwareBufferLicensee licensee, bool copyData) { HardwareVertexBuffer vbuf = null; // Locate existing buffer copy in free list IList list = (IList)freeTempVertexBufferMap[sourceBuffer]; if (list == null) { list = new ArrayList(); freeTempVertexBufferMap[sourceBuffer] = list; } // Are there any free buffers? if (list.Count == 0) { // copy buffer, use shadow buffer and make dynamic vbuf = MakeBufferCopy(sourceBuffer, BufferUsage.DynamicWriteOnly, true); } else { // grab the available buffer and remove it from the free list int lastIndex = list.Count - 1; vbuf = (HardwareVertexBuffer)list[lastIndex]; list.RemoveAt(lastIndex); } // Copy data? if (copyData) { vbuf.CopyData(sourceBuffer, 0, 0, sourceBuffer.Size, true); } // Insert copy into licensee list tempVertexBufferLicenses.Add(new VertexBufferLicense(sourceBuffer, licenseType, expiredDelayFrameThreshold, vbuf, licensee)); return(vbuf); }
public Rectangle2D(bool includeTextureCoordinates) { vertexData = new VertexData(); vertexData.vertexStart = 0; vertexData.vertexCount = 4; VertexDeclaration decl = vertexData.vertexDeclaration; VertexBufferBinding binding = vertexData.vertexBufferBinding; decl.AddElement(POSITION, 0, VertexElementType.Float3, VertexElementSemantic.Position); HardwareVertexBuffer buffer = HardwareBufferManager.Instance.CreateVertexBuffer( decl.GetVertexSize(POSITION), vertexData.vertexCount, BufferUsage.StaticWriteOnly); binding.SetBinding(POSITION, buffer); if (includeTextureCoordinates) { decl.AddElement(TEXCOORD, 0, VertexElementType.Float2, VertexElementSemantic.TexCoords); buffer = HardwareBufferManager.Instance.CreateVertexBuffer( decl.GetVertexSize(TEXCOORD), vertexData.vertexCount, BufferUsage.StaticWriteOnly); binding.SetBinding(TEXCOORD, buffer); buffer.WriteData(0, buffer.Size, texCoords, true); } // TODO: Fix material = MaterialManager.Instance.GetByName("BaseWhite"); material.Lighting = false; }
/// <summary> /// Updates the face normals for this edge list based on (changed) /// position information, useful for animated objects. /// </summary> /// <param name="vertexSet">The vertex set we are updating.</param> /// <param name="positionBuffer">The updated position buffer, must contain ONLY xyz.</param> public void UpdateFaceNormals(int vertexSet, HardwareVertexBuffer positionBuffer) { #if !AXIOM_SAFE_ONLY unsafe #endif { Debug.Assert(positionBuffer.VertexSize == sizeof(float) * 3, "Position buffer should contain only positions!"); // Lock buffer for reading var posPtr = positionBuffer.Lock(BufferLocking.ReadOnly); var pVert = posPtr.ToFloatPointer(); // Iterate over the triangles for (var i = 0; i < this.triangles.Count; i++) { var t = (Triangle)this.triangles[i]; // Only update tris which are using this vertex set if (t.vertexSet == vertexSet) { var offset = t.vertIndex[0] * 3; var v1 = new Vector3(pVert[offset], pVert[offset + 1], pVert[offset + 2]); offset = t.vertIndex[1] * 3; var v2 = new Vector3(pVert[offset], pVert[offset + 1], pVert[offset + 2]); offset = t.vertIndex[2] * 3; var v3 = new Vector3(pVert[offset], pVert[offset + 1], pVert[offset + 2]); t.normal = CalculateFaceNormal(v1, v2, v3); } } } // unlock the buffer positionBuffer.Unlock(); }
private static void GenerateCurvedIllusionPlaneVertexData(HardwareVertexBuffer vertexBuffer, int ySegments, int xSegments, float xSpace, float halfWidth, float ySpace, float halfHeight, Matrix4 xform, bool firstTime, bool normals, Quaternion orientation, float cameraPosition, float sphereRadius, float uTiles, float vTiles, int numberOfTexCoordSets, ref Vector3 min, ref Vector3 max, ref float maxSquaredLength) { Vector3 vec; Vector3 norm; float sphereDistance; unsafe { // lock the vertex buffer IntPtr data = vertexBuffer.Lock(BufferLocking.Discard); float* pData = (float*)data.ToPointer(); for (int y = 0; y < ySegments + 1; ++y) { for (int x = 0; x < xSegments + 1; ++x) { // centered on origin vec.x = (x * xSpace) - halfWidth; vec.y = (y * ySpace) - halfHeight; vec.z = 0.0f; // transform by orientation and distance vec = xform * vec; // assign to geometry *pData++ = vec.x; *pData++ = vec.y; *pData++ = vec.z; // build bounds as we go if (firstTime) { min = vec; max = vec; maxSquaredLength = vec.LengthSquared; firstTime = false; } else { min.Floor(vec); max.Ceil(vec); maxSquaredLength = MathUtil.Max(maxSquaredLength, vec.LengthSquared); } if (normals) { norm = Vector3.UnitZ; norm = orientation * norm; *pData++ = vec.x; *pData++ = vec.y; *pData++ = vec.z; } // generate texture coordinates, normalize position, modify by orientation to return +y up vec = orientation.Inverse() * vec; vec.Normalize(); // find distance to sphere sphereDistance = MathUtil.Sqrt(cameraPosition * cameraPosition * (vec.y * vec.y - 1.0f) + sphereRadius * sphereRadius) - cameraPosition * vec.y; vec.x *= sphereDistance; vec.z *= sphereDistance; // use x and y on sphere as texture coordinates, tiled float s = vec.x * (0.01f * uTiles); float t = vec.z * (0.01f * vTiles); for (int i = 0; i < numberOfTexCoordSets; i++) { *pData++ = s; *pData++ = (1 - t); } } // x } // y // unlock the buffer vertexBuffer.Unlock(); } // unsafe }
/// <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); } }
public override void NotifyVertexBufferDestroyed( HardwareVertexBuffer buffer ) { _baseInstance.NotifyVertexBufferDestroyed( buffer ); }
public override void ReleaseVertexBufferCopy( HardwareVertexBuffer bufferCopy ) { _baseInstance.ReleaseVertexBufferCopy( bufferCopy ); }
private void _generateCurvedIllusionPlaneVertexData( HardwareVertexBuffer vertexBuffer, int ySegments, int xSegments, float xSpace, float halfWidth, float ySpace, float halfHeight, Matrix4 xform, bool firstTime, bool normals, Quaternion orientation, float curvature, float uTiles, float vTiles, int numberOfTexCoordSets, ref Vector3 min, ref Vector3 max, ref float maxSquaredLength ) { // Imagine a large sphere with the camera located near the top // The lower the curvature, the larger the sphere // Use the angle from viewer to the points on the plane // Credit to Aftershock for the general approach Real cameraPosition; // Camera position relative to sphere center // Derive sphere radius //Vector3 vertPos; // position relative to camera //Real sphDist; // Distance from camera to sphere along box vertex vector // Vector3 camToSph; // camera position to sphere Real sphereRadius;// Sphere radius // Actual values irrelevant, it's the relation between sphere radius and camera position that's important Real sphRadius = 100.0f; Real camDistance = 5.0f; sphereRadius = sphRadius - curvature; cameraPosition = sphereRadius - camDistance; Vector3 vec; Vector3 norm; float sphereDistance; unsafe { // lock the vertex buffer IntPtr data = vertexBuffer.Lock( BufferLocking.Discard ); float* pData = (float*)data.ToPointer(); for ( int y = 0; y < ySegments + 1; ++y ) { for ( int x = 0; x < xSegments + 1; ++x ) { // centered on origin vec.x = ( x * xSpace ) - halfWidth; vec.y = ( y * ySpace ) - halfHeight; vec.z = 0.0f; // transform by orientation and distance vec = xform * vec; // assign to geometry *pData++ = vec.x; *pData++ = vec.y; *pData++ = vec.z; // build bounds as we go if ( firstTime ) { min = vec; max = vec; maxSquaredLength = vec.LengthSquared; firstTime = false; } else { min.Floor( vec ); max.Ceil( vec ); maxSquaredLength = Utility.Max( maxSquaredLength, vec.LengthSquared ); } if ( normals ) { norm = Vector3.UnitZ; norm = orientation * norm; *pData++ = vec.x; *pData++ = vec.y; *pData++ = vec.z; } // generate texture coordinates, normalize position, modify by orientation to return +y up vec = orientation.Inverse() * vec; vec.Normalize(); // find distance to sphere sphereDistance = Utility.Sqrt( cameraPosition * cameraPosition * ( vec.y * vec.y - 1.0f ) + sphereRadius * sphereRadius ) - cameraPosition * vec.y; vec.x *= sphereDistance; vec.z *= sphereDistance; // use x and y on sphere as texture coordinates, tiled float s = vec.x * ( 0.01f * uTiles ); float t = vec.z * ( 0.01f * vTiles ); for ( int i = 0; i < numberOfTexCoordSets; i++ ) { *pData++ = s; *pData++ = ( 1 - t ); } } // x } // y // unlock the buffer vertexBuffer.Unlock(); } // unsafe }
private void _generatePlaneVertexData( HardwareVertexBuffer vbuf, int ySegments, int xSegments, float xSpace, float halfWidth, float ySpace, float halfHeight, Matrix4 transform, bool firstTime, bool normals, Matrix4 rotation, int numTexCoordSets, float xTexCoord, float yTexCoord, SubMesh subMesh, ref Vector3 min, ref Vector3 max, ref float maxSquaredLength ) { Vector3 vec; unsafe { // lock the vertex buffer IntPtr data = vbuf.Lock( BufferLocking.Discard ); float* pData = (float*)data.ToPointer(); for ( int y = 0; y <= ySegments; y++ ) { for ( int x = 0; x <= xSegments; x++ ) { // centered on origin vec.x = ( x * xSpace ) - halfWidth; vec.y = ( y * ySpace ) - halfHeight; vec.z = 0.0f; vec = transform.TransformAffine( vec ); *pData++ = vec.x; *pData++ = vec.y; *pData++ = vec.z; // Build bounds as we go if ( firstTime ) { min = vec; max = vec; maxSquaredLength = vec.LengthSquared; firstTime = false; } else { min.Floor( vec ); max.Ceil( vec ); maxSquaredLength = Utility.Max( maxSquaredLength, vec.LengthSquared ); } if ( normals ) { vec = Vector3.UnitZ; vec = rotation.TransformAffine( vec ); *pData++ = vec.x; *pData++ = vec.y; *pData++ = vec.z; } for ( int i = 0; i < numTexCoordSets; i++ ) { *pData++ = x * xTexCoord; *pData++ = 1 - ( y * yTexCoord ); } // for texCoords } // for x } // for y // unlock the buffer vbuf.Unlock(); subMesh.useSharedVertices = true; } // unsafe }
public override void RegisterVertexBufferSourceAndCopy( HardwareVertexBuffer sourceBuffer, HardwareVertexBuffer copy ) { this._baseInstance.RegisterVertexBufferSourceAndCopy( sourceBuffer, copy ); }
/// <summary> /// Creates a new buffer as a copy of the source, does not copy data. /// </summary> /// <param name="source">Source vertex buffer.</param> /// <param name="usage">New usage type.</param> /// <param name="useShadowBuffer">New shadow buffer choice.</param> /// <returns>A copy of the vertex buffer, but data is not copied.</returns> protected HardwareVertexBuffer MakeBufferCopy(HardwareVertexBuffer source, BufferUsage usage, bool useShadowBuffer) { return(CreateVertexBuffer(source.VertexSize, source.VertexCount, usage, useShadowBuffer)); }
/// <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> 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 var renderSystem = Root.Instance.RenderSystem; var useVertexPrograms = false; if (renderSystem != null && renderSystem.Capabilities.HasCapability(Capabilities.VertexPrograms)) { useVertexPrograms = true; } // Look for a position element var posElem = this.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.Position); if (posElem != null) { var posOldSource = posElem.Source; var vbuf = this.vertexBufferBinding.GetBuffer(posOldSource); var 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; var newRemainderDeclaration = (VertexDeclaration)this.vertexDeclaration.Clone(); if (wasSharedBuffer) { var found = false; var index = 0; do { if (newRemainderDeclaration.GetElement(index).Semantic == VertexElementSemantic.Position) { newRemainderDeclaration.RemoveElement(index); found = true; } index++; }while (!found); newRemainderBuffer = HardwareBufferManager.Instance.CreateVertexBuffer(newRemainderDeclaration, vbuf.VertexCount, vbuf.Usage, vbuf.HasShadowBuffer); } // Allocate new position buffer, will be FLOAT3 and 2x the size var oldVertexCount = vbuf.VertexCount; var newVertexCount = oldVertexCount * 2; var newPosDecl = HardwareBufferManager.Instance.CreateVertexDeclaration(); newPosDecl.AddElement(0, 0, VertexElementType.Float3, VertexElementSemantic.Position); newPosBuffer = HardwareBufferManager.Instance.CreateVertexBuffer(newPosDecl, newVertexCount, vbuf.Usage, vbuf.HasShadowBuffer); // Iterate over the old buffer, copying the appropriate elements and initializing the rest var baseSrcPtr = vbuf.Lock(BufferLocking.ReadOnly); // Point first destination pointer at the start of the new position buffer, // the other one half way along var destPtr = newPosBuffer.Lock(BufferLocking.Discard); // oldVertexCount * 3 * 4, since we are dealing with byte offsets here var dest2Ptr = destPtr + (oldVertexCount * 12); var prePosVertexSize = 0; var postPosVertexSize = 0; var 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)); var baseDestRemPtr = newRemainderBuffer.Lock(BufferLocking.Discard); var baseSrcOffset = 0; var baseDestRemOffset = 0; #if !AXIOM_SAFE_ONLY unsafe #endif { var pDest = destPtr.ToFloatPointer(); var pDest2 = dest2Ptr.ToFloatPointer(); int destCount = 0, dest2Count = 0; // Iterate over the vertices for (var v = 0; v < oldVertexCount; v++) { var pSrc = (baseSrcPtr + (posElem.Offset + baseSrcOffset)).ToFloatPointer(); // 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) { #if !AXIOM_SAFE_ONLY unsafe #endif { var decl = HardwareBufferManager.Instance.CreateVertexDeclaration(); decl.AddElement(0, 0, VertexElementType.Float1, VertexElementSemantic.Position); // Now it's time to set up the w buffer this.hardwareShadowVolWBuffer = HardwareBufferManager.Instance.CreateVertexBuffer(decl, newVertexCount, BufferUsage.StaticWriteOnly, false); // Fill the first half with 1.0, second half with 0.0 var wPtr = this.hardwareShadowVolWBuffer.Lock(BufferLocking.Discard); var pDest = wPtr.ToFloatPointer(); var destCount = 0; for (var v = 0; v < oldVertexCount; v++) { pDest[destCount++] = 1.0f; } for (var v = 0; v < oldVertexCount; v++) { pDest[destCount++] = 0.0f; } } // unsafe this.hardwareShadowVolWBuffer.Unlock(); } // if vertexPrograms short newPosBufferSource = 0; if (wasSharedBuffer) { // Get the a new buffer binding index newPosBufferSource = this.vertexBufferBinding.NextIndex; // Re-bind the old index to the remainder buffer this.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 this.vertexBufferBinding.SetBinding(newPosBufferSource, newPosBuffer); // Now, alter the vertex declaration to change the position source // and the offsets of elements using the same buffer for (var i = 0; i < this.vertexDeclaration.ElementCount; i++) { var element = this.vertexDeclaration.GetElement(i); if (element.Semantic == VertexElementSemantic.Position) { // Modify position to point at new position buffer this.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 this.vertexDeclaration.ModifyElement(i, posOldSource /* same old source */, element.Offset - posElem.Size /* less offset now */, element.Type, element.Semantic, element.Index); } } } // if posElem != null }
/// <summary> /// Allocates a copy of a given vertex buffer. /// </summary> /// <remarks> /// This method allocates a temporary copy of an existing vertex buffer. /// This buffer is subsequently stored and can be made available for /// other purposes later without incurring the cost of construction / /// destruction. /// </remarks> /// <param name="sourceBuffer">The source buffer to use as a copy.</param> /// <param name="licenseType"> /// The type of license required on this buffer - automatic /// release causes this class to release licenses every frame so that /// they can be reallocated anew. /// </param> /// <param name="licensee"> /// Reference back to the class requesting the copy, which must /// implement <see cref="IHardwareBufferLicense"/> in order to be notified when the license /// expires. /// </param> /// <returns></returns> public virtual HardwareVertexBuffer AllocateVertexBufferCopy(HardwareVertexBuffer sourceBuffer, BufferLicenseRelease licenseType, IHardwareBufferLicensee licensee) { return(AllocateVertexBufferCopy(sourceBuffer, licenseType, licensee, false)); }
public override void RegisterVertexBufferSourceAndCopy(HardwareVertexBuffer sourceBuffer, HardwareVertexBuffer copy) { this._baseInstance.RegisterVertexBufferSourceAndCopy(sourceBuffer, copy); }
/// <summary> /// Tells the system to build the mesh relating to the surface into externally created buffers. /// </summary> /// <remarks> /// The VertexDeclaration of the vertex buffer must be identical to the one passed into /// <see cref="DefineSurface"/>. In addition, there must be enough space in the buffer to /// accommodate the patch at full detail level; you should check <see cref="RequiredVertexCount"/> /// and <see cref="RequiredIndexCount"/> to determine this. This method does not create an internal /// mesh for this patch and so GetMesh will return null if you call it after building the /// patch this way. /// </remarks> /// <param name="destVertexBuffer">The destination vertex buffer in which to build the patch.</param> /// <param name="vertexStart">The offset at which to start writing vertices for this patch.</param> /// <param name="destIndexBuffer">The destination index buffer in which to build the patch.</param> /// <param name="indexStart">The offset at which to start writing indexes for this patch.</param> public void Build(HardwareVertexBuffer destVertexBuffer, int vertexStart, HardwareIndexBuffer destIndexBuffer, int indexStart) { if(controlPoints.Count == 0) { return; } vertexBuffer = destVertexBuffer; vertexOffset = vertexStart; indexBuffer = destIndexBuffer; indexOffset = indexStart; // lock just the region we are interested in IntPtr lockedBuffer = vertexBuffer.Lock( vertexOffset * declaration.GetVertexSize(0), requiredVertexCount * declaration.GetVertexSize(0), BufferLocking.NoOverwrite); DistributeControlPoints(lockedBuffer); // subdivide the curves to the max // Do u direction first, so need to step over v levels not done yet int vStep = 1 << maxVLevel; int uStep = 1 << maxULevel; // subdivide this row in u for(int v = 0; v < meshHeight; v += vStep) { SubdivideCurve(lockedBuffer, v * meshWidth, uStep, meshWidth / uStep, uLevel); } // Now subdivide in v direction, this time all the u direction points are there so no step for(int u = 0; u < meshWidth; u++) { SubdivideCurve(lockedBuffer, u, vStep * meshWidth, meshHeight / vStep, vLevel); } // don't forget to unlock! vertexBuffer.Unlock(); // Make triangles from mesh at this current level of detail MakeTriangles(); }
private void DestroyBuffers() { // LogManager.Instance.Write(string.Format("BillBoardSet.DestroyBuffers entered; vertexData {0}, indexData {1}, mainBuffer {2}", // vertexData == null ? "null" : vertexData.ToString(), // indexData == null ? "null" : indexData.ToString(), // mainBuffer == null ? "null" : mainBuffer.ToString())); this.vertexData = null; this.indexData = null; this.mainBuffer = null; this.buffersCreated = false; }
/// <summary> /// Performs a software vertex morph, of the kind used for /// morph animation although it can be used for other purposes. /// </summary> /// <remarks> /// This function will linearly interpolate positions between two /// source buffers, into a third buffer. /// </remarks> /// <param name="t">Parametric distance between the start and end buffer positions</param> /// <param name="b1">Vertex buffer containing VertexElementType.Float3 entries for the start positions</param> /// <param name="b2">Vertex buffer containing VertexElementType.Float3 entries for the end positions</param> /// <param name="targetVertexData"> VertexData destination; assumed to have a separate position /// buffer already bound, and the number of vertices must agree with the /// number in start and end /// </param> public static void SoftwareVertexMorph( float t, HardwareVertexBuffer b1, HardwareVertexBuffer b2, VertexData targetVertexData ) { #if !AXIOM_SAFE_ONLY unsafe #endif { var bpb1 = b1.Lock( BufferLocking.ReadOnly ).ToFloatPointer(); var pb1 = 0; var bpb2 = b2.Lock( BufferLocking.ReadOnly ).ToFloatPointer(); var pb2 = 0; var posElem = targetVertexData.vertexDeclaration.FindElementBySemantic( VertexElementSemantic.Position ); Debug.Assert( posElem != null ); var destBuf = targetVertexData.vertexBufferBinding.GetBuffer( posElem.Source ); Debug.Assert( posElem.Size == destBuf.VertexSize, "Positions must be in a buffer on their own for morphing" ); var bpdst = destBuf.Lock( BufferLocking.Discard ).ToFloatPointer(); var pdst = 0; for ( var i = 0; i < targetVertexData.vertexCount; ++i ) { // x bpdst[ pdst++ ] = bpb1[ pb1 ] + t*( bpb2[ pb2 ] - bpb1[ pb1 ] ); ++pb1; ++pb2; // y bpdst[ pdst++ ] = bpb1[ pb1 ] + t*( bpb2[ pb2 ] - bpb1[ pb1 ] ); ++pb1; ++pb2; // z bpdst[ pdst++ ] = bpb1[ pb1 ] + t*( bpb2[ pb2 ] - bpb1[ pb1 ] ); ++pb1; ++pb2; } destBuf.Unlock(); b1.Unlock(); b2.Unlock(); } }
/// <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); }
public override HardwareVertexBuffer AllocateVertexBufferCopy( HardwareVertexBuffer sourceBuffer, BufferLicenseRelease licenseType, #if NET_40 IHardwareBufferLicensee licensee, bool copyData = false )
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; }
private void _generateCurvedPlaneVertexData( HardwareVertexBuffer vbuf, int ySegments, int xSegments, float xSpace, float halfWidth, float ySpace, float halfHeight, Matrix4 transform, bool firstTime, bool normals, Matrix4 rotation, float curvature, int numTexCoordSets, float xTexCoord, float yTexCoord, SubMesh subMesh, ref Vector3 min, ref Vector3 max, ref float maxSquaredLength ) { Vector3 vec; unsafe { // lock the vertex buffer IntPtr data = vbuf.Lock( BufferLocking.Discard ); float* pData = (float*)data.ToPointer(); for ( int y = 0; y <= ySegments; y++ ) { for ( int x = 0; x <= xSegments; x++ ) { // centered on origin vec.x = ( x * xSpace ) - halfWidth; vec.y = ( y * ySpace ) - halfHeight; // Here's where curved plane is different from standard plane. Amazing, I know. Real diff_x = ( x - ( (Real)xSegments / 2 ) ) / (Real)xSegments; Real diff_y = ( y - ( (Real)ySegments / 2 ) ) / (Real)ySegments; Real dist = Utility.Sqrt( diff_x * diff_x + diff_y * diff_y ); vec.z = ( -Utility.Sin( ( 1 - dist ) * ( Utility.PI / 2 ) ) * curvature ) + curvature; // Transform by orientation and distance Vector3 pos = transform.TransformAffine( vec ); *pData++ = pos.x; *pData++ = pos.y; *pData++ = pos.z; // Build bounds as we go if ( firstTime ) { min = vec; max = vec; maxSquaredLength = vec.LengthSquared; firstTime = false; } else { min.Floor( vec ); max.Ceil( vec ); maxSquaredLength = Utility.Max( maxSquaredLength, vec.LengthSquared ); } if ( normals ) { // This part is kinda 'wrong' for curved planes... but curved planes are // very valuable outside sky planes, which don't typically need normals // so I'm not going to mess with it for now. // Default normal is along unit Z //vec = Vector3::UNIT_Z; // Rotate vec = rotation.TransformAffine( vec ); *pData++ = vec.x; *pData++ = vec.y; *pData++ = vec.z; } for ( int i = 0; i < numTexCoordSets; i++ ) { *pData++ = x * xTexCoord; *pData++ = 1 - ( y * yTexCoord ); } // for texCoords } // for x } // for y // unlock the buffer vbuf.Unlock(); subMesh.useSharedVertices = true; } // unsafe }
/// <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(); }
//public override RegisterVertexBufferSourceAndCopy( HardwareVertexBuffer sourceBuffer, HardwareVertexBuffer copy ) //{ //} public override HardwareVertexBuffer AllocateVertexBufferCopy( HardwareVertexBuffer sourceBuffer, BufferLicenseRelease licenseType, IHardwareBufferLicensee licensee, bool copyData ) { return _baseInstance.AllocateVertexBufferCopy( sourceBuffer, licenseType, licensee, copyData ); }
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); } } }
public override void ForceReleaseBufferCopies( HardwareVertexBuffer sourceBuffer ) { _baseInstance.ForceReleaseBufferCopies( sourceBuffer ); }
/// <summary> /// Implementation of LicenseExpired. /// </summary> /// <param name="buffer"></param> public void LicenseExpired(HardwareBuffer buffer) { if(buffer == destPositionBuffer) { destPositionBuffer = null; } if(buffer == destNormalBuffer) { destNormalBuffer = 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> /// Updates the face normals for this edge list based on (changed) /// position information, useful for animated objects. /// </summary> /// <param name="vertexSet">The vertex set we are updating.</param> /// <param name="positionBuffer">The updated position buffer, must contain ONLY xyz.</param> public void UpdateFaceNormals( int vertexSet, HardwareVertexBuffer positionBuffer ) { #if !AXIOM_SAFE_ONLY unsafe #endif { Debug.Assert( positionBuffer.VertexSize == sizeof ( float )*3, "Position buffer should contain only positions!" ); // Lock buffer for reading var posPtr = positionBuffer.Lock( BufferLocking.ReadOnly ); var pVert = posPtr.ToFloatPointer(); // Iterate over the triangles for ( var i = 0; i < this.triangles.Count; i++ ) { var t = (Triangle)this.triangles[ i ]; // Only update tris which are using this vertex set if ( t.vertexSet == vertexSet ) { var offset = t.vertIndex[ 0 ]*3; var v1 = new Vector3( pVert[ offset ], pVert[ offset + 1 ], pVert[ offset + 2 ] ); offset = t.vertIndex[ 1 ]*3; var v2 = new Vector3( pVert[ offset ], pVert[ offset + 1 ], pVert[ offset + 2 ] ); offset = t.vertIndex[ 2 ]*3; var v3 = new Vector3( pVert[ offset ], pVert[ offset + 1 ], pVert[ offset + 2 ] ); t.normal = Utility.CalculateFaceNormal( v1, v2, v3 ); } } } // unlock the buffer positionBuffer.Unlock(); }
/// <summary> /// Set a binding, associating a vertex buffer with a given index. /// </summary> /// <remarks> /// If the index is already associated with a vertex buffer, /// the association will be replaced. This may cause the old buffer /// to be destroyed if nothing else is referring to it. /// You should assign bindings from 0 and not leave gaps, although you can /// bind them in any order. /// </remarks> /// <param name="index">Index at which to bind the buffer.</param> /// <param name="buffer">Vertex buffer to bind.</param> public virtual void SetBinding(short index, HardwareVertexBuffer buffer) { this.bindingMap[index] = buffer; this.highIndex = (short)Utility.Max(this.highIndex, index + 1); }
public virtual HardwareVertexBuffer AllocateVertexBufferCopy(HardwareVertexBuffer sourceBuffer, BufferLicenseRelease licenseType, #if NET_40 IHardwareBufferLicensee licensee, bool copyData = false)
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; }
/// <summary> /// Rebind the source positions for temp buffer users. /// </summary> public void RebindPositionBuffer( VertexData vertexData, bool force ) { if ( force || this.currentVertexData != vertexData ) { this.currentVertexData = vertexData; this.positionBuffer = this.currentVertexData.vertexBufferBinding.GetBuffer( this.originalPosBufferBinding ); renderOperation.vertexData.vertexBufferBinding.SetBinding( 0, this.positionBuffer ); if ( lightCap != null ) { ( (EntityShadowRenderable)lightCap ).RebindPositionBuffer( vertexData, force ); } } }
/// <summary> /// Allocate / reallocate vertex data /// Note that we allocate enough space for ALL the billboards in the pool, but only issue /// rendering operations for the sections relating to the active billboards /// </summary> private void CreateBuffers() { /* Alloc positions ( 1 or 4 verts per billboard, 3 components ) colours ( 1 x RGBA per vertex ) indices ( 6 per billboard ( 2 tris ) if not point rendering ) tex. coords ( 2D coords, 1 or 4 per billboard ) */ // LogManager.Instance.Write(string.Format("BillBoardSet.CreateBuffers entered; vertexData {0}, indexData {1}, mainBuffer {2}", // vertexData == null ? "null" : vertexData.ToString(), // indexData == null ? "null" : indexData.ToString(), // mainBuffer == null ? "null" : mainBuffer.ToString())); // Warn if user requested an invalid setup // Do it here so it only appears once if ( this.pointRendering && this.billboardType != BillboardType.Point ) { LogManager.Instance.Write( "Warning: BillboardSet {0} has point rendering enabled but is using a type " + "other than BillboardType.Point, this may not give you the results you " + "expect.", this.name ); } this.vertexData = new VertexData(); if ( this.pointRendering ) { this.vertexData.vertexCount = this.poolSize; } else { this.vertexData.vertexCount = this.poolSize * 4; } this.vertexData.vertexStart = 0; // Vertex declaration VertexDeclaration decl = this.vertexData.vertexDeclaration; VertexBufferBinding binding = this.vertexData.vertexBufferBinding; int offset = 0; decl.AddElement( 0, offset, VertexElementType.Float3, VertexElementSemantic.Position ); offset += VertexElement.GetTypeSize( VertexElementType.Float3 ); decl.AddElement( 0, offset, VertexElementType.Color, VertexElementSemantic.Diffuse ); offset += VertexElement.GetTypeSize( VertexElementType.Color ); // Texture coords irrelevant when enabled point rendering (generated // in point sprite mode, and unused in standard point mode) if ( !this.pointRendering ) { decl.AddElement( 0, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 0 ); } this.mainBuffer = HardwareBufferManager.Instance.CreateVertexBuffer( decl.Clone( 0 ), this.vertexData.vertexCount, BufferUsage.DynamicWriteOnlyDiscardable ); // bind position and diffuses binding.SetBinding( 0, this.mainBuffer ); if ( !this.pointRendering ) { this.indexData = new IndexData(); // calc index buffer size this.indexData.indexStart = 0; this.indexData.indexCount = this.poolSize * 6; // create the index buffer this.indexData.indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer( IndexType.Size16, this.indexData.indexCount, BufferUsage.StaticWriteOnly ); /* Create indexes (will be the same every frame) Using indexes because it means 1/3 less vertex transforms (4 instead of 6) Billboard layout relative to camera: 0-----1 | /| | / | |/ | 2-----3 */ // lock the index buffer IntPtr idxPtr = this.indexData.indexBuffer.Lock( BufferLocking.Discard ); unsafe { ushort* pIdx = (ushort*)idxPtr.ToPointer(); for ( int idx, idxOffset, bboard = 0; bboard < this.poolSize; ++bboard ) { // Do indexes idx = bboard * 6; idxOffset = bboard * 4; pIdx[ idx ] = (ushort)idxOffset; // + 0;, for clarity pIdx[ idx + 1 ] = (ushort)( idxOffset + 2 ); pIdx[ idx + 2 ] = (ushort)( idxOffset + 1 ); pIdx[ idx + 3 ] = (ushort)( idxOffset + 1 ); pIdx[ idx + 4 ] = (ushort)( idxOffset + 2 ); pIdx[ idx + 5 ] = (ushort)( idxOffset + 3 ); } // for } // unsafe // unlock the buffers this.indexData.indexBuffer.Unlock(); } this.buffersCreated = true; }
/// <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> 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.Capabilities.HasCapability( Capabilities.VertexPrograms ) ) { useVertexPrograms = true; } // Look for a position element VertexElement posElem = vertexDeclaration.FindElementBySemantic( VertexElementSemantic.Position ); if ( posElem != null ) { short 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; VertexDeclaration newRemainderDeclaration = (VertexDeclaration)vertexDeclaration.Clone(); if ( wasSharedBuffer ) { bool found = false; int index = 0; do { if (newRemainderDeclaration.GetElement(index).Semantic == VertexElementSemantic.Position) { newRemainderDeclaration.RemoveElement(index); found = true; } index++; } while ( !found ); newRemainderBuffer = HardwareBufferManager.Instance.CreateVertexBuffer( newRemainderDeclaration, 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; VertexDeclaration newPosDecl = HardwareBufferManager.Instance.CreateVertexDeclaration(); newPosDecl.AddElement( 0, 0, VertexElementType.Float3, VertexElementSemantic.Position ); newPosBuffer = HardwareBufferManager.Instance.CreateVertexBuffer( newPosDecl, 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.ToInt64() + ( 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 { VertexDeclaration decl = HardwareBufferManager.Instance.CreateVertexDeclaration(); decl.AddElement(0, 0, VertexElementType.Float1, VertexElementSemantic.Position); // Now it's time to set up the w buffer hardwareShadowVolWBuffer = HardwareBufferManager.Instance.CreateVertexBuffer( decl, 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 short 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 }
protected void WriteGeometryVertexBuffer( BinaryWriter writer, short bindIndex, HardwareVertexBuffer vertexBuffer ) { var start_offset = writer.Seek( 0, SeekOrigin.Current ); WriteChunk( writer, MeshChunkID.GeometryVertexBuffer, 0 ); WriteShort( writer, bindIndex ); WriteShort( writer, (short)vertexBuffer.VertexSize ); var buf = vertexBuffer.Lock( BufferLocking.Discard ); try { WriteGeometryVertexBufferData( writer, vertexBuffer.Size, buf ); } finally { vertexBuffer.Unlock(); } var end_offset = writer.Seek( 0, SeekOrigin.Current ); writer.Seek( (int)start_offset, SeekOrigin.Begin ); WriteChunk( writer, MeshChunkID.GeometryVertexBuffer, (int)( end_offset - start_offset ) ); writer.Seek( (int)end_offset, SeekOrigin.Begin ); }
/// <summary> /// Set a binding, associating a vertex buffer with a given index. /// </summary> /// <remarks> /// If the index is already associated with a vertex buffer, /// the association will be replaced. This may cause the old buffer /// to be destroyed if nothing else is referring to it. /// You should assign bindings from 0 and not leave gaps, although you can /// bind them in any order. /// </remarks> /// <param name="index">Index at which to bind the buffer.</param> /// <param name="buffer">Vertex buffer to bind.</param> public virtual void SetBinding(ushort index, HardwareVertexBuffer buffer) { bindingMap[index] = buffer; highIndex = (ushort)MathUtil.Max(highIndex, index + 1); }
public EntityShadowRenderable( Entity parent, HardwareIndexBuffer indexBuffer, VertexData vertexData, bool createSeparateLightCap, SubEntity subEntity, bool isLightCap ) { this.parent = parent; // Save link to vertex data this.currentVertexData = vertexData; // Initialize render op renderOperation.indexData = new IndexData(); renderOperation.indexData.indexBuffer = indexBuffer; renderOperation.indexData.indexStart = 0; // index start and count are sorted out later // Create vertex data which just references position component (and 2 component) renderOperation.vertexData = new VertexData(); renderOperation.vertexData.vertexDeclaration = HardwareBufferManager.Instance.CreateVertexDeclaration(); renderOperation.vertexData.vertexBufferBinding = HardwareBufferManager.Instance.CreateVertexBufferBinding(); // Map in position data renderOperation.vertexData.vertexDeclaration.AddElement( 0, 0, VertexElementType.Float3, VertexElementSemantic.Position ); this.originalPosBufferBinding = vertexData.vertexDeclaration.FindElementBySemantic( VertexElementSemantic.Position ).Source; this.positionBuffer = vertexData.vertexBufferBinding.GetBuffer( this.originalPosBufferBinding ); renderOperation.vertexData.vertexBufferBinding.SetBinding( 0, this.positionBuffer ); // Map in w-coord buffer (if present) if ( vertexData.hardwareShadowVolWBuffer != null ) { renderOperation.vertexData.vertexDeclaration.AddElement( 1, 0, VertexElementType.Float1, VertexElementSemantic.TexCoords, 0 ); this.wBuffer = vertexData.hardwareShadowVolWBuffer; renderOperation.vertexData.vertexBufferBinding.SetBinding( 1, this.wBuffer ); } // Use same vertex start as input renderOperation.vertexData.vertexStart = vertexData.vertexStart; if ( isLightCap ) { // Use original vertex count, no extrusion renderOperation.vertexData.vertexCount = vertexData.vertexCount; } else { // Vertex count must take into account the doubling of the buffer, // because second half of the buffer is the extruded copy renderOperation.vertexData.vertexCount = vertexData.vertexCount*2; if ( createSeparateLightCap ) { // Create child light cap lightCap = new EntityShadowRenderable( parent, indexBuffer, vertexData, false, subEntity, true ); } } }
/// <summary> /// Utility method, checks out temporary copies of src into dest. /// </summary> public void CheckoutTempCopies(bool positions, bool normals, bool tangents, bool binormals) { bindPositions = positions; bindNormals = normals; bindTangents = tangents; bindBinormals = binormals; if(bindPositions && destPositionBuffer == null) { destPositionBuffer = HardwareBufferManager.Instance.AllocateVertexBufferCopy( srcPositionBuffer, BufferLicenseRelease.Automatic, this); } if (bindNormals && !posNormalShareBuffer && srcNormalBuffer != null && destNormalBuffer == null) { destNormalBuffer = HardwareBufferManager.Instance.AllocateVertexBufferCopy( srcNormalBuffer, BufferLicenseRelease.Automatic, this); } if (bindTangents && srcTangentBuffer != null) { if (this.tanBindIndex != this.posBindIndex && this.tanBindIndex != this.normBindIndex) { destTangentBuffer = HardwareBufferManager.Instance.AllocateVertexBufferCopy( srcTangentBuffer, BufferLicenseRelease.Automatic, this); } } if (bindNormals && srcBinormalBuffer != null) { if (this.binormBindIndex != this.posBindIndex && this.binormBindIndex != this.normBindIndex && this.binormBindIndex != this.tanBindIndex) { destBinormalBuffer = HardwareBufferManager.Instance.AllocateVertexBufferCopy( srcBinormalBuffer, BufferLicenseRelease.Automatic, this); } } }
/// <summary> /// /// </summary> /// <param name="disposeManagedResources"></param> protected override void dispose( bool disposeManagedResources ) { if ( !IsDisposed ) { if ( disposeManagedResources ) { // Dispose managed resources. if ( lightCap != null ) { if ( !lightCap.IsDisposed ) { lightCap.Dispose(); } lightCap = null; } if ( this.wBuffer != null ) { if ( !this.wBuffer.IsDisposed ) { this.wBuffer.Dispose(); } this.wBuffer = null; } if ( this.positionBuffer != null ) { if ( !this.positionBuffer.IsDisposed ) { this.positionBuffer.Dispose(); } this.positionBuffer = null; } if ( this.subEntity != null ) { if ( !this.subEntity.IsDisposed ) { this.subEntity.Dispose(); } this.subEntity = null; } if ( this.currentVertexData != null ) { if ( !this.currentVertexData.IsDisposed ) { this.currentVertexData.Dispose(); } this.currentVertexData = null; } } // There are no unmanaged resources to release, but // if we add them, they need to be released here. } // If it is available, make the call to the // base class's Dispose(Boolean) method base.dispose( disposeManagedResources ); }
/// <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 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); }