Skip to content

Commit

Permalink
Rewrite map_Height so that the height it reports matches with what th…
Browse files Browse the repository at this point in the history
…e terrain renderer shows.

git-svn-id: svn+ssh://svn.gna.org/svn/warzone/trunk@6838 4a71c877-e1ca-e34f-864e-861f7616d084

Cherry-picked 380c32b from master.
  • Loading branch information
Gerard Krol authored and cybersphinx committed Oct 18, 2010
1 parent 6bdd4cd commit e28711f
Showing 1 changed file with 76 additions and 122 deletions.
198 changes: 76 additions & 122 deletions src/map.c
Original file line number Diff line number Diff line change
Expand Up @@ -1964,151 +1964,105 @@ BOOL map_Intersect(int* Cx, int* Cy, int* Vx, int* Vy, int* Sx, int* Sy)
return false;
}

/* Return linear interpolated height of x,y */
/// The height of the terrain at the specified world coordinates
extern SWORD map_Height(int x, int y)
{
int retVal, tileX, tileY, tileYOffset, tileX2, tileY2Offset, dx, dy, ox, oy;
int h0, hx, hy, hxy, wTL = 0, wTR = 0, wBL = 0, wBR = 0;
BOOL bWaterTile = false;

// Clamp x and y values to actual ones
// Give one tile worth of leeway before asserting, for units/transporters coming in from off-map.
ASSERT(x >= -TILE_UNITS, "map_Height: x value is too small (%d,%d) in %dx%d",map_coord(x),map_coord(y),mapWidth,mapHeight);
ASSERT(y >= -TILE_UNITS, "map_Height: y value is too small (%d,%d) in %dx%d",map_coord(x),map_coord(y),mapWidth,mapHeight);
x = (x < 0 ? 0 : x);
y = (y < 0 ? 0 : y);
ASSERT(x < world_coord(mapWidth)+TILE_UNITS, "map_Height: x value is too big (%d,%d) in %dx%d",map_coord(x),map_coord(y),mapWidth,mapHeight);
ASSERT(y < world_coord(mapHeight)+TILE_UNITS, "map_Height: y value is too big (%d,%d) in %dx%d",map_coord(x),map_coord(y),mapWidth,mapHeight);
x = (x >= world_coord(mapWidth) ? world_coord(mapWidth) - 1 : x);
y = (y >= world_coord(mapHeight) ? world_coord(mapHeight) - 1 : y);

/* Turn into tile coordinates */
int tileX, tileY;
int i, j;
float height[2][2], center;
float onTileX, onTileY;
float left, right, middle;
float onBottom, result;
float towardsCenter, towardsRight;

// make sure we have valid coordinates
if (x < 0 ||
y < 0 ||
x >= world_coord(mapWidth-1) ||
y >= world_coord(mapHeight-1))
{
// we don't so give an arbitrary height
return 0;
}

// on which tile are these coords?
tileX = map_coord(x);
tileY = map_coord(y);

/* Inter tile comp */
ox = map_round(x);
oy = map_round(y);

if (terrainType(mapTile(tileX,tileY)) == TER_WATER)
{
bWaterTile = true;
wTL = environGetValue(tileX,tileY)/2;
wTR = environGetValue(tileX+1,tileY)/2;
wBL = environGetValue(tileX,tileY+1)/2;
wBR = environGetValue(tileX+1,tileY+1)/2;
}
// where on the tile? (scale to (0,1))
onTileX = (x - world_coord(tileX))/(float)world_coord(1);
onTileY = (y - world_coord(tileY))/(float)world_coord(1);

// to account for the border of the map
if(tileX + 1 < mapWidth)
// get the height for the corners and center
center = 0;
for (i = 0; i < 2; i++)
{
tileX2 = tileX + 1;
}
else
{
tileX2 = tileX;
}
tileYOffset = (tileY * mapWidth);
if(tileY + 1 < mapHeight)
{
tileY2Offset = tileYOffset + mapWidth;
}
else
{
tileY2Offset = tileYOffset;
for (j = 0; j < 2; j++)
{
height[i][j] = map_TileHeight(tileX+i, tileY+j);
center += height[i][j];
}
}
center /= 4;

ASSERT( ox < TILE_UNITS, "mapHeight: x offset too big" );
ASSERT( oy < TILE_UNITS, "mapHeight: y offset too big" );
ASSERT( ox >= 0, "mapHeight: x offset too small" );
ASSERT( oy >= 0, "mapHeight: y offset too small" );
// we have:
// y ->
// x 0,0 A 0,1
// |
// V D center B
//
// 1,0 C 1,1

//different code for 4 different triangle cases
if (psMapTiles[tileX + tileYOffset].texture & TILE_TRIFLIP)
// get heights for left and right corners and the distances
if (onTileY > onTileX)
{
if ((ox + oy) > TILE_UNITS)//tile split top right to bottom left object if in bottom right half
if (onTileY < 1 - onTileX)
{
ox = TILE_UNITS - ox;
oy = TILE_UNITS - oy;
hy = psMapTiles[tileX + tileY2Offset].height;
hx = psMapTiles[tileX2 + tileYOffset].height;
hxy= psMapTiles[tileX2 + tileY2Offset].height;
if(bWaterTile)
{
hy+=wBL;
hx+=wTR;
hxy+=wBR;
}

dx = ((hy - hxy) * ox )/ TILE_UNITS;
dy = ((hx - hxy) * oy )/ TILE_UNITS;

retVal = (SDWORD)(((hxy + dx + dy)) * ELEVATION_SCALE);
ASSERT( retVal<MAX_HEIGHT,"Map height's gone weird!!!" );
return ((SWORD)retVal);
// A
right = height[0][0];
left = height[0][1];
towardsCenter = onTileX;
towardsRight = 1 - onTileY;
}
else //tile split top right to bottom left object if in top left half
else
{
h0 = psMapTiles[tileX + tileYOffset].height;
hy = psMapTiles[tileX + tileY2Offset].height;
hx = psMapTiles[tileX2 + tileYOffset].height;

if(bWaterTile)
{
h0+=wTL;
hy+=wBL;
hx+=wTR;
}
dx = ((hx - h0) * ox )/ TILE_UNITS;
dy = ((hy - h0) * oy )/ TILE_UNITS;

retVal = (SDWORD)((h0 + dx + dy) * ELEVATION_SCALE);
ASSERT( retVal<MAX_HEIGHT,"Map height's gone weird!!!" );
return ((SWORD)retVal);
// B
right = height[0][1];
left = height[1][1];
towardsCenter = 1 - onTileY;
towardsRight = 1 - onTileX;
}
}
else
{
if (ox > oy) //tile split topleft to bottom right object if in top right half
if (onTileX > 1 - onTileY)
{
h0 = psMapTiles[tileX + tileYOffset].height;
hx = psMapTiles[tileX2 + tileYOffset].height;
ASSERT( tileX2 + tileY2Offset < mapWidth*mapHeight, "array out of bounds");
hxy= psMapTiles[tileX2 + tileY2Offset].height;

if(bWaterTile)
{
h0+=wTL;
hx+=wTR;
hxy+=wBR;
}
dx = ((hx - h0) * ox )/ TILE_UNITS;
dy = ((hxy - hx) * oy )/ TILE_UNITS;
retVal = (SDWORD)(((h0 + dx + dy)) * ELEVATION_SCALE);
ASSERT( retVal<MAX_HEIGHT,"Map height's gone weird!!!" );
return ((SWORD)retVal);
// C
right = height[1][1];
left = height[1][0];
towardsCenter = 1 - onTileX;
towardsRight = onTileY;
}
else //tile split topleft to bottom right object if in bottom left half
else
{
h0 = psMapTiles[tileX + tileYOffset].height;
hy = psMapTiles[tileX + tileY2Offset].height;
hxy = psMapTiles[tileX2 + tileY2Offset].height;

if(bWaterTile)
{
h0+=wTL;
hy+=wBL;
hxy+=wBR;
}
dx = ((hxy - hy) * ox )/ TILE_UNITS;
dy = ((hy - h0) * oy )/ TILE_UNITS;

retVal = (SDWORD)((h0 + dx + dy) * ELEVATION_SCALE);
ASSERT( retVal<MAX_HEIGHT,"Map height's gone weird!!!" );
return ((SWORD)retVal);
// D
right = height[1][0];
left = height[0][0];
towardsCenter = onTileY;
towardsRight = onTileX;
}
}
return 0;
ASSERT(towardsCenter <= 0.5, "towardsCenter is too high");

// now we have:
// center
// left m right

middle = (left + right)/2;
onBottom = left * (1 - towardsRight) + right * towardsRight;
result = onBottom + (center - middle) * towardsCenter * 2;

return (SDWORD)(result+0.5f);
}

/* returns true if object is above ground */
Expand Down

0 comments on commit e28711f

Please sign in to comment.