Need to find the corresponding Z (height) of a given position X,Y? Heres a little thingy i got together the other day to solve that problem. Its not optimized, it is straight forward ugly, but works. I got approx 0.1 unit error in result when testing it. You will need som basic vector class to do the final calcs, but thats trivial (Direct3D will do fine). Between height values it approximates with a plane through the triangle. Of course it will only work for ADTs in memory, so the max distance will vary from zone to zone...
Creds to Malu05 for explaining how ADTs are loaded in memory in his terrain management app, and to wow dev wiki in general for all data explainations...
bool FindTerrainZ(float x, float y, float* z)
{
bool result = false;
DWORD base = 0x012CA9F8; // 3.2.0a
DWORD tileY = (int)floor((32 * 1600.0 / 3 - y) / (1600.0 / 3));
DWORD tileX = (int)floor((32 * 1600.0 / 3 - x) / (1600.0 / 3));
DWORD adt1 = base + 256 * tileX + 4 * tileY;
DWORD adt2 = *(LPDWORD)(adt1);
if(adt2 != 0)
{
DWORD adtBase = *(LPDWORD)(adt2 + 0x23;
if(adtBase != 0)
{
DWORD mcin = adtBase + 0x14 + *(LPDWORD)(adtBase + 0x14 + 0x04);
DWORD firstChnk = *(LPDWORD)(mcin + 0x0+ adtBase;
float maxX = *(float*) (firstChnk + 0x08 + 0x6;
float maxY = *(float*) (firstChnk + 0x08 + 0x6C);
float chunkSize = 1600.0 / 3 / 16;
float unitsBetweenHights = chunkSize / 8;
int col = (int)floor((maxY - y) / chunkSize);
int row = (int)floor((maxX - x) / chunkSize);
DWORD chnk = *(LPDWORD)(mcin + 0x08 + (row * 16 + col) * 0x10) + adtBase;
DWORD mcvt = *(LPDWORD)(chnk + 0x08 + 0x14) + chnk;
float* heights = (float*)(mcvt + 0x0;
float chnkX = *(float*)(chnk + 0x08 + 0x6;
float chnkY = *(float*)(chnk + 0x08 + 0x6C);
float chnkZ = *(float*)(chnk + 0x08 + 0x70);
col = (int)floor((chnkY - y) / unitsBetweenHights);
row = (int)floor((chnkX - x) / unitsBetweenHights);
float colR = (chnkY - y) / unitsBetweenHights - col;
float rowR = (chnkX - x) / unitsBetweenHights - row;
Vector3 vv1(chnkX- row * unitsBetweenHights, chnkY - col * unitsBetweenHights, chnkZ + heights[row * 17 + col]);
Vector3 vv2(chnkX- row * unitsBetweenHights, chnkY - (col + 1) * unitsBetweenHights, chnkZ + heights[row * 17 + col + 1]);
Vector3 vv3(chnkX- (row + 0.5) * unitsBetweenHights, chnkY - (col + 0.5) * unitsBetweenHights, chnkZ + heights[row * 17 + 9 + col]);
Vector3 vv4(chnkX- (row + 1) * unitsBetweenHights, chnkY - col * unitsBetweenHights, chnkZ + heights[(row + 1) * 17 + col]);
Vector3 vv5(chnkX- (row + 1) * unitsBetweenHights, chnkY - (col + 1) * unitsBetweenHights, chnkZ + heights[(row + 1) * 17 + col + 1]);
Vector3 v1, v2, v3, u, v;
if(colR + rowR < 1) // Upper triangle
{
if(rowR > colR) // t1
{
v1 = vv4;
v2 = vv1;
v3 = vv3;
}
else //t2
{
v1 = vv1;
v2 = vv2;
v3 = vv3;
}
}
else // lower triangle
{
if(rowR < colR) // t3
{
v1 = vv2;
v2 = vv5;
v3 = vv3;
}
else // t4
{
v1 = vv5;
v2 = vv4;
v3 = vv3;
}
}
u = Vector3::Sub(v2, v1);
v = Vector3::Sub(v3, v1);
Vector3 n = Vector3::Cross(u, v);
Vector3 nn = Vector3::Multiply(n, -1);
float d = Vector3:ot(nn, v1);
*z = (-d - n.X * x - n.Y * y) / n.Z;
//DbgPrintf(L"RESULT: :%.2f", *z);
result = true;
}
}
return result;
}