protected void buildVertexData()
        {
            // accumulate the number of verts and triangles from the patches
            int numVerts     = 0;
            int numTriangles = 0;

            for (int z = 0; z < numTiles; z++)
            {
                for (int x = 0; x < numTiles; x++)
                {
                    numVerts     += terrainPatches[x, z].NumVerts;
                    numTriangles += terrainPatches[x, z].NumTriangles;
                }
            }

            //
            // Create the vertex buffer
            //
            VertexData localVertexData = new VertexData();

            localVertexData.vertexCount = numVerts;
            localVertexData.vertexStart = 0;

            // free the original vertex declaration to avoid a leak
            HardwareBufferManager.Instance.DestroyVertexDeclaration(localVertexData.vertexDeclaration);

            localVertexData.vertexDeclaration = terrainVertexDeclaration;

            // create the hardware vertex buffer and set up the buffer binding
            HardwareVertexBuffer hvBuffer = HardwareBufferManager.Instance.CreateVertexBuffer(
                localVertexData.vertexDeclaration.GetVertexSize(0), localVertexData.vertexCount,
                BufferUsage.StaticWriteOnly, false);

            localVertexData.vertexBufferBinding.SetBinding(0, hvBuffer);
            renderOp.vertexData = localVertexData;

            //
            // Create the index buffer
            //
            IndexData localIndexData = new IndexData();

            localIndexData.indexCount = numTriangles * 3;
            localIndexData.indexStart = 0;

            localIndexData.indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer(
                IndexType.Size16, localIndexData.indexCount, BufferUsage.StaticWriteOnly);

            renderOp.indexData = localIndexData;

            // lock the vertex and index buffers
            IntPtr vertexBufferPtr = hvBuffer.Lock(BufferLocking.Discard);
            IntPtr indexBufferPtr  = localIndexData.indexBuffer.Lock(BufferLocking.Discard);

            int vertOff  = 0;
            int indexOff = 0;

            for (int z = 0; z < numTiles; z++)
            {
                for (int x = 0; x < numTiles; x++)
                {
                    TerrainPatch patch = terrainPatches[x, z];
                    int          nv    = patch.NumVerts;
                    int          nt    = patch.NumTriangles;
                    patch.BuildVertexIndexData(vertexBufferPtr, vertOff, indexBufferPtr, indexOff);

                    // update buffer offsets
                    vertOff  += nv * VertexSize;
                    indexOff += (3 * nt);
                }
            }

            // unlock the buffers
            localIndexData.indexBuffer.Unlock();
            hvBuffer.Unlock();
        }