Fix object rendering
Previous solution did not work well on high resolutions due to incorrect tile calculations - was not updating edges and sometimes hanged in endless loop trying to find upper-left or bottom-right tiles. New solution follows Sfall's HRP implementation.
This commit is contained in:
parent
7496afa4f8
commit
ac64fde502
|
@ -768,47 +768,23 @@ void _obj_render_pre_roof(Rect* rect, int elevation)
|
|||
int minY = updatedRect.top - 240;
|
||||
int maxX = updatedRect.right + 320;
|
||||
int maxY = updatedRect.bottom + 240;
|
||||
int topLeftTile = tileFromScreenXY(minX, minY, elevation);
|
||||
int upperLeftTile = tileFromScreenXY(minX, minY, elevation, true);
|
||||
int updateAreaHexWidth = (maxX - minX + 1) / 32;
|
||||
int updateAreaHexHeight = (maxY - minY + 1) / 12;
|
||||
|
||||
// On some maps (which were designed too close to edges) HRP brings a new
|
||||
// problem - extended update rect (+/- 320/240 stuff above) may end up
|
||||
// outside of the map edge. In this case `topLeftTile` will be -1 which
|
||||
// affect all subsequent calculations. In order to fix that attempt to
|
||||
// find closest valid tile.
|
||||
while (!hexGridTileIsValid(topLeftTile)) {
|
||||
minX += 32;
|
||||
minY += 12;
|
||||
topLeftTile = tileFromScreenXY(minX, minY, elevation);
|
||||
}
|
||||
|
||||
// Do the same for the for bottom-right part of the extended update rect.
|
||||
int bottomRightTile = tileFromScreenXY(maxX, maxY, elevation);
|
||||
while (!hexGridTileIsValid(bottomRightTile)) {
|
||||
maxX -= 32;
|
||||
maxY -= 12;
|
||||
bottomRightTile = tileFromScreenXY(maxX, maxY, elevation);
|
||||
}
|
||||
|
||||
updateAreaHexWidth = (maxX - minX + 1) / 32;
|
||||
updateAreaHexHeight = (maxY - minY + 1) / 12;
|
||||
|
||||
int parity = gCenterTile & 1;
|
||||
int* orders = _orderTable[parity];
|
||||
int* offsets = _offsetTable[parity];
|
||||
|
||||
_outlineCount = 0;
|
||||
|
||||
int renderCount = 0;
|
||||
for (int i = 0; i < gObjectsUpdateAreaHexSize; i++) {
|
||||
int offsetIndex = *orders++;
|
||||
int offsetIndex = _orderTable[parity][i];
|
||||
if (updateAreaHexHeight > _offsetDivTable[offsetIndex] && updateAreaHexWidth > _offsetModTable[offsetIndex]) {
|
||||
int lightIntensity;
|
||||
|
||||
ObjectListNode* objectListNode = hexGridTileIsValid(topLeftTile + offsets[offsetIndex])
|
||||
? gObjectListHeadByTile[topLeftTile + offsets[offsetIndex]]
|
||||
int tile = upperLeftTile + _offsetTable[parity][offsetIndex];
|
||||
ObjectListNode* objectListNode = hexGridTileIsValid(tile)
|
||||
? gObjectListHeadByTile[tile]
|
||||
: NULL;
|
||||
|
||||
int lightIntensity;
|
||||
if (objectListNode != NULL) {
|
||||
// NOTE: Calls `lightGetTileIntensity` twice.
|
||||
lightIntensity = std::max(ambientIntensity, lightGetTileIntensity(elevation, objectListNode->obj->tile));
|
||||
|
@ -2995,7 +2971,7 @@ int _obj_intersects_with(Object* object, int x, int y)
|
|||
// 0x48C5C4
|
||||
int _obj_create_intersect_list(int x, int y, int elevation, int objectType, ObjectWithFlags** entriesPtr)
|
||||
{
|
||||
int v5 = tileFromScreenXY(x - 320, y - 240, elevation);
|
||||
int upperLeftTile = tileFromScreenXY(x - 320, y - 240, elevation, true);
|
||||
*entriesPtr = NULL;
|
||||
|
||||
if (gObjectsUpdateAreaHexSize <= 0) {
|
||||
|
@ -3006,9 +2982,12 @@ int _obj_create_intersect_list(int x, int y, int elevation, int objectType, Obje
|
|||
|
||||
int parity = gCenterTile & 1;
|
||||
for (int index = 0; index < gObjectsUpdateAreaHexSize; index++) {
|
||||
int v7 = _orderTable[parity][index];
|
||||
if (_offsetDivTable[v7] < 30 && _offsetModTable[v7] < 20) {
|
||||
ObjectListNode* objectListNode = gObjectListHeadByTile[_offsetTable[parity][v7] + v5];
|
||||
int offsetIndex = _orderTable[parity][index];
|
||||
if (_offsetDivTable[offsetIndex] < 30 && _offsetModTable[offsetIndex] < 20) {
|
||||
int tile = _offsetTable[parity][offsetIndex] + upperLeftTile;
|
||||
ObjectListNode* objectListNode = hexGridTileIsValid(tile)
|
||||
? gObjectListHeadByTile[tile]
|
||||
: NULL;
|
||||
while (objectListNode != NULL) {
|
||||
Object* object = objectListNode->obj;
|
||||
if (object->elevation > elevation) {
|
||||
|
|
11
src/tile.cc
11
src/tile.cc
|
@ -692,8 +692,13 @@ int tileToScreenXY(int tile, int* screenX, int* screenY, int elevation)
|
|||
return 0;
|
||||
}
|
||||
|
||||
// CE: Added optional `ignoreBounds` param to return tile number without
|
||||
// validating hex grid bounds. The resulting invalid tile number serves as an
|
||||
// origin for calculations using prepared offsets table during objects
|
||||
// rendering.
|
||||
//
|
||||
// 0x4B1754
|
||||
int tileFromScreenXY(int screenX, int screenY, int elevation)
|
||||
int tileFromScreenXY(int screenX, int screenY, int elevation, bool ignoreBounds)
|
||||
{
|
||||
int v2;
|
||||
int v3;
|
||||
|
@ -763,6 +768,10 @@ int tileFromScreenXY(int screenX, int screenY, int elevation)
|
|||
return gHexGridWidth * v10 + v12;
|
||||
}
|
||||
|
||||
if (ignoreBounds) {
|
||||
return gHexGridWidth * v10 + v12;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ void tileWindowRefresh();
|
|||
int tileSetCenter(int tile, int flags);
|
||||
int tileRoofIsVisible();
|
||||
int tileToScreenXY(int tile, int* x, int* y, int elevation);
|
||||
int tileFromScreenXY(int x, int y, int elevation);
|
||||
int tileFromScreenXY(int x, int y, int elevation, bool ignoreBounds = false);
|
||||
int tileDistanceBetween(int a1, int a2);
|
||||
bool tileIsInFrontOf(int tile1, int tile2);
|
||||
bool tileIsToRightOf(int tile1, int tile2);
|
||||
|
|
Loading…
Reference in New Issue