I don't like the way you've organised your scaling functions, but I didn't touch them in case they were part of some greater scheme I was unaware of.
A reliable method of scaling your terrain involves only a uniform scaling factor (GetScale(), shall we say) and perhaps a height-scale (GetHeightScale()), if your heightmap image didn't take care of it for you. I'm assuming you're not planning on implementing any geomipmapping ('cause then things get a bit more complicated).
When creating the mesh, you should calculate absolutely everything as if it were on a 1:1:1 scale (so there will be no need to call GetScale, GetSpacing etc. during the loop) but just before you put the data into the buffer, scale the x, y, z values accordingly. This way, you can eliminate the modulus error you're getting. An example follows.
int CQuadTree::NumTrianglesInRange(){ return (m_iMaxX - m_iMinX) * (m_iMaxZ - m_iMinZ) * 2;}void CQuadTree::CreateRenderMesh(){ // Get our triangle count. int triangleCount = NumTrianglesInRange(); CHeightMap::terrainVertex* vertex; if(FAILED(D3DXCreateMeshFVF(triangleCount, (triangleCount *3), D3DXMESH_MANAGED, D3DFVF_XYZ |D3DFVF_TEX1, CRenderer::GetInstance()->GetDevice(), &m_pMesh))) { MessageBox(NULL, "FAILED", "FAILED", MB_OK); } // Populate the VB. if(FAILED(m_pMesh->LockVertexBuffer(0, (void**)&vertex))) { MessageBox(NULL, "FAILED", "FAILED", MB_OK); } int PatchVertexWidth = (m_iMaxX - m_iMinX) + 1; int vertexIndex = 0; int i = 0; int j = 0; for(int z = m_iMinZ; z <= m_iMaxZ; z += 1) { for(int x = m_iMinX; x <= m_iMaxX; x += 1) { i = x - m_iMinX; j = z - m_iMinZ; int index = j * PatchVertexWidth + i; float height = CHeightMap::GetInstance()->GetHeightMapEntry(x, z); vertex[index].x = (float) x GetScale(); vertex[index].y = height * GetScale() * GetHeightScale(); // vertex[index].y = 0.0f; vertex[index].z = (float) z GetScale(); vertex[index].u = 0.0f; vertex[index].v = 0.0f; } } if(FAILED(m_pMesh->UnlockVertexBuffer())) { MessageBox(NULL, "FAILED", "FAILED", MB_OK); } // Populate the Index Buffer. WORD* indexBuffer = 0; if(FAILED(m_pMesh->LockIndexBuffer(0, (void**)&indexBuffer))) { MessageBox(NULL, "FAILED", "FAILED", MB_OK); } int baseIndex = 0; int PatchIndexXWidth = (m_iMaxX - m_iMinX); int PatchIndexZWidth = (m_iMaxZ - m_iMinZ); for(int i = 0; i < PatchIndexZWidth; i++) { for(int j = 0; j < PatchIndexXWidth; j++) { indexBuffer[baseIndex] = i * PatchVertexWidth + j; indexBuffer[baseIndex + 1] = i * PatchVertexWidth + j + 1; indexBuffer[baseIndex + 2] = (i + 1) * PatchVertexWidth + j; indexBuffer[baseIndex + 3] = (i + 1) * PatchVertexWidth + j; indexBuffer[baseIndex + 4] = i * PatchVertexWidth + j + 1; indexBuffer[baseIndex + 5] = (i + 1) * PatchVertexWidth + j + 1; baseIndex += 6; } } if(FAILED(m_pMesh->UnlockIndexBuffer())) { MessageBox(NULL, "FAILED", "FAILED", MB_OK); } // Populate attribute buffer, all triangles = Subset 0 DWORD* attributeBuffer = 0; if(FAILED(m_pMesh->LockAttributeBuffer(0, &attributeBuffer))) { MessageBox(NULL, "FAILED", "FAILED", MB_OK); } for(int i = 0; i < triangleCount; i++) { attributeBuffer = 0; } if(FAILED(m_pMesh->UnlockAttributeBuffer())) { MessageBox(NULL, "FAILED", "FAILED", MB_OK); } // Optimization functions. DWORD* adjacencyBuffer = new DWORD[m_pMesh->GetNumFaces() * 3]; if(FAILED(m_pMesh->GenerateAdjacency(0.001f, &adjacencyBuffer[0]))) { MessageBox(NULL, "FAILED", "FAILED", MB_OK); } if(FAILED(m_pMesh->OptimizeInplace(D3DXMESHOPT_IGNOREVERTS, &adjacencyBuffer[0], NULL, NULL, NULL))) { MessageBox(NULL, "FAILED", "FAILED", MB_OK); } delete [] adjacencyBuffer;}
Note that this code requires the quadtree to be initialised with dimensionless values (so XMin etc. represent the number of vertices, rather than the physical size of the terrain). Also GetHeightmapEntry() will need adaptation. In general, dimensionless units are easier to manage, so after all the painstaking conversion, your code will be smaller, cleaner and you'll never look back.
Regards
Admiral