unsafe void UpdateVertexBufferr(HardwareVertexBuffer posbuf, HardwareVertexBuffer deltabuf, Rectangle rect)
{
// potentially reset our bounds depending on coverage of the update
ResetBounds(rect);
// Main data
ushort inc = (ushort)((mTerrain.Size-1) / (mVertexDataRecord.Resolution-1));
long destOffsetX = rect.Left <= mOffsetX ? 0 : (rect.Left - mOffsetX) / inc;
long destOffsetY = rect.Top <= mOffsetY ? 0 : (rect.Top - mOffsetY) / inc;
// Fill the buffers
BufferLocking lockMode;
if (destOffsetX != 0 || destOffsetY != 0|| rect.Right - rect.Left < mSize
|| rect.Bottom - rect.Top < mSize)
{
lockMode = BufferLocking.Normal;
}
else
{
lockMode = BufferLocking.Discard;
}
Real uvScale = 1.0 / (mTerrain.Size - 1);
float* pBaseHeight = (float*)mTerrain.GetHeightData(rect.Left, rect.Top);
float* pBaseDelta = (float*)mTerrain.GetDeltaData(rect.Left, rect.Top);
ushort rowskip = (ushort)(mTerrain.Size * inc);
ushort destPosRowSkip = 0, destDeltaRowSkip = 0;
byte* pRootPosBuf = (byte*)IntPtr.Zero;
byte* pRootDeltaBuf = (byte*)IntPtr.Zero;
byte* pRowPosBuf = (byte*)IntPtr.Zero;
byte* pRowDeltaBuf = (byte*)IntPtr.Zero;
if (posbuf != null)
{
destPosRowSkip = (ushort)(mVertexDataRecord.Size * posbuf.VertexSize);
pRootPosBuf = (byte*)(posbuf.Lock(lockMode));
pRowPosBuf = pRootPosBuf;
// skip dest buffer in by left/top
pRowPosBuf += destOffsetY * destPosRowSkip + destOffsetX * posbuf.VertexSize;
}
if (deltabuf != null)
{
destDeltaRowSkip = (ushort)(mVertexDataRecord.Size * deltabuf.VertexSize);
pRootDeltaBuf = (byte*)(deltabuf.Lock(lockMode));
pRowDeltaBuf = pRootDeltaBuf;
// skip dest buffer in by left/top
pRowDeltaBuf += destOffsetY * destDeltaRowSkip + destOffsetX * deltabuf.VertexSize;
}
Vector3 pos = Vector3.Zero;
int posIndex = 0;
for (ushort y = (ushort)rect.Top; y < rect.Bottom; y += inc)
{
float* pHeight = pBaseHeight;
float* pDelta = pBaseDelta;
float* pPosBuf = (float*)(pRowPosBuf);
float* pDeltaBuf = (float*)(pRowDeltaBuf);
for (ushort x = (ushort)rect.Left; x < rect.Right; x += inc)
{
if (pPosBuf != (float*)IntPtr.Zero)
{
mTerrain.GetPoint(x, y, pBaseHeight[posIndex], ref pos);
// Update bounds *before* making relative
MergeIntoBounds(x, y, pos);
// relative to local centre
pos -= mLocalCentre;
//pHeight += inc;
posIndex += inc;
*pPosBuf++ = pos.x;
*pPosBuf++ = pos.y;
*pPosBuf++ = pos.z;
// UVs - base UVs vary from 0 to 1, all other values
// will be derived using scalings
*pPosBuf++ = x * uvScale;
*pPosBuf++ = 1.0 - (y * uvScale);
}
if (pDeltaBuf != (float*)IntPtr.Zero)
{
// delta
*pDeltaBuf++ = *pDelta;
pDelta += inc;
// delta LOD threshold
// we want delta to apply to LODs no higher than this value
// at runtime this will be combined with a per-renderable parameter
// to ensure we only apply morph to the correct LOD
*pDeltaBuf++ = (float)mTerrain.GetLODLevelWhenVertexEliminated(x, y) - 1.0f;
}
}
//pBaseHeight += rowskip;
posIndex += rowskip;
pBaseDelta += rowskip;
if (pRowPosBuf != (float*)IntPtr.Zero)
pRowPosBuf += destPosRowSkip;
if (pRowDeltaBuf!= (float*)IntPtr.Zero)
pRowDeltaBuf += destDeltaRowSkip;
}
// Skirts now
// skirt spacing based on top-level resolution (* inc to cope with resolution which is not the max)
ushort skirtSpacing = (ushort)(mVertexDataRecord.SkirtRowColSkip * inc);
Vector3 skirtOffset = Vector3.Zero;
mTerrain.GetVector(0, 0, -mTerrain.SkirtSize, ref skirtOffset);
// skirt rows
// clamp rows to skirt spacing (round up)
long skirtStartX = rect.Left;
long skirtStartY = rect.Top;
if (skirtStartY % skirtSpacing != 0)
skirtStartY += skirtSpacing - (skirtStartY % skirtSpacing);
skirtStartY = System.Math.Max(skirtStartY, (long)mOffsetY);
pBaseHeight = (float*)mTerrain.GetHeightData(skirtStartX, skirtStartY);
if (posbuf != null)
{
// position dest buffer just after the main vertex data
pRowPosBuf = pRootPosBuf + posbuf.VertexSize
* mVertexDataRecord.Size * mVertexDataRecord.Size;
// move it onwards to skip the skirts we don't need to update
pRowPosBuf += destPosRowSkip * (skirtStartY - mOffsetY) / skirtSpacing;
pRowPosBuf += posbuf.VertexSize * (skirtStartX - mOffsetX);
}
if (deltabuf != null)
{
// position dest buffer just after the main vertex data
pRowDeltaBuf = pRootDeltaBuf + deltabuf.VertexSize
* mVertexDataRecord.Size * mVertexDataRecord.Size;
// move it onwards to skip the skirts we don't need to update
pRowDeltaBuf += destDeltaRowSkip * (skirtStartY - mOffsetY) / skirtSpacing;
pRowDeltaBuf += deltabuf.VertexSize * (skirtStartX - mOffsetX);
}
for (ushort y = (ushort)skirtStartY; y < rect.Bottom; y += skirtSpacing)
{
float* pHeight = pBaseHeight;
float* pPosBuf = (float*)(pRowPosBuf);
float* pDeltaBuf = (float*)(pRowDeltaBuf);
for (ushort x = (ushort)skirtStartX; x < rect.Right; x += inc)
{
if (pPosBuf != (float*)IntPtr.Zero)
{
mTerrain.GetPoint(x, y, *pHeight, ref pos);
// relative to local centre
pos -= mLocalCentre;
pHeight += inc;
pos += skirtOffset;
*pPosBuf++ = pos.x;
*pPosBuf++ = pos.y;
*pPosBuf++ = pos.z;
// UVs - same as base
*pPosBuf++ = x * uvScale;
*pPosBuf++ = 1.0 - (y * uvScale);
}
if (pDeltaBuf != (float*)IntPtr.Zero)
{
// delta (none)
*pDeltaBuf++ = 0;
// delta threshold (irrelevant)
*pDeltaBuf++ = 99;
}
}
pBaseHeight += mTerrain.Size * skirtSpacing;
if (pRowPosBuf != (byte*)IntPtr.Zero)
pRowPosBuf += destPosRowSkip;
if (pRowDeltaBuf != (byte*)IntPtr.Zero)
pRowDeltaBuf += destDeltaRowSkip;
}
// skirt cols
// clamp cols to skirt spacing (round up)
skirtStartX = rect.Left;
if (skirtStartX % skirtSpacing != 0)
skirtStartX += skirtSpacing - (skirtStartX % skirtSpacing);
skirtStartY = rect.Top;
skirtStartX = System.Math.Max(skirtStartX, (long)mOffsetX);
if (posbuf != null)
{
// position dest buffer just after the main vertex data and skirt rows
pRowPosBuf = pRootPosBuf + posbuf.VertexSize
* mVertexDataRecord.Size * mVertexDataRecord.Size;
// skip the row skirts
pRowPosBuf += mVertexDataRecord.NumSkirtRowsCols * mVertexDataRecord.Size * posbuf.VertexSize;
// move it onwards to skip the skirts we don't need to update
pRowPosBuf += destPosRowSkip * (skirtStartX - mOffsetX) / skirtSpacing;
pRowPosBuf += posbuf.VertexSize * (skirtStartY - mOffsetY);
}
if (deltabuf != null)
{
// Deltaition dest buffer just after the main vertex data and skirt rows
pRowDeltaBuf = pRootDeltaBuf + deltabuf.VertexSize
* mVertexDataRecord.Size * mVertexDataRecord.Size;
// skip the row skirts
pRowDeltaBuf += mVertexDataRecord.NumSkirtRowsCols * mVertexDataRecord.Size * deltabuf.VertexSize;
// move it onwards to skip the skirts we don't need to update
pRowDeltaBuf += destDeltaRowSkip * (skirtStartX - mOffsetX) / skirtSpacing;
pRowDeltaBuf += deltabuf.VertexSize * (skirtStartY - mOffsetY);
}
for (ushort x = (ushort)skirtStartX; x < rect.Right; x += skirtSpacing)
{
float* pPosBuf = (float*)(pRowPosBuf);
float* pDeltaBuf = (float*)(pRowDeltaBuf);
for (ushort y = (ushort)skirtStartY; y < rect.Bottom; y += inc)
{
if (pPosBuf != (float*)IntPtr.Zero)
{
mTerrain.GetPoint(x, y, mTerrain.GetHeightAtPoint(x, y), ref pos);
// relative to local centre
pos -= mLocalCentre;
pos += skirtOffset;
*pPosBuf++ = pos.x;
*pPosBuf++ = pos.y;
*pPosBuf++ = pos.z;
// UVs - same as base
*pPosBuf++ = x * uvScale;
*pPosBuf++ = 1.0 - (y * uvScale);
}
if (pDeltaBuf != (float*)IntPtr.Zero)
{
// delta (none)
*pDeltaBuf++ = 0;
// delta threshold (irrelevant)
*pDeltaBuf++ = 99;
}
}
if (pRowPosBuf != (byte*)IntPtr.Zero)
pRowPosBuf += destPosRowSkip;
if (pRowDeltaBuf != (byte*)IntPtr.Zero)
pRowDeltaBuf += destDeltaRowSkip;
}
if (posbuf != null)
posbuf.Unlock();
if (deltabuf != null)
deltabuf.Unlock();
}
/// <summary>