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 minY = updatedRect.top - 240;
|
||||||
int maxX = updatedRect.right + 320;
|
int maxX = updatedRect.right + 320;
|
||||||
int maxY = updatedRect.bottom + 240;
|
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 updateAreaHexWidth = (maxX - minX + 1) / 32;
|
||||||
int updateAreaHexHeight = (maxY - minY + 1) / 12;
|
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 parity = gCenterTile & 1;
|
||||||
int* orders = _orderTable[parity];
|
|
||||||
int* offsets = _offsetTable[parity];
|
|
||||||
|
|
||||||
_outlineCount = 0;
|
_outlineCount = 0;
|
||||||
|
|
||||||
int renderCount = 0;
|
int renderCount = 0;
|
||||||
for (int i = 0; i < gObjectsUpdateAreaHexSize; i++) {
|
for (int i = 0; i < gObjectsUpdateAreaHexSize; i++) {
|
||||||
int offsetIndex = *orders++;
|
int offsetIndex = _orderTable[parity][i];
|
||||||
if (updateAreaHexHeight > _offsetDivTable[offsetIndex] && updateAreaHexWidth > _offsetModTable[offsetIndex]) {
|
if (updateAreaHexHeight > _offsetDivTable[offsetIndex] && updateAreaHexWidth > _offsetModTable[offsetIndex]) {
|
||||||
int lightIntensity;
|
int tile = upperLeftTile + _offsetTable[parity][offsetIndex];
|
||||||
|
ObjectListNode* objectListNode = hexGridTileIsValid(tile)
|
||||||
ObjectListNode* objectListNode = hexGridTileIsValid(topLeftTile + offsets[offsetIndex])
|
? gObjectListHeadByTile[tile]
|
||||||
? gObjectListHeadByTile[topLeftTile + offsets[offsetIndex]]
|
|
||||||
: NULL;
|
: NULL;
|
||||||
|
|
||||||
|
int lightIntensity;
|
||||||
if (objectListNode != NULL) {
|
if (objectListNode != NULL) {
|
||||||
// NOTE: Calls `lightGetTileIntensity` twice.
|
// NOTE: Calls `lightGetTileIntensity` twice.
|
||||||
lightIntensity = std::max(ambientIntensity, lightGetTileIntensity(elevation, objectListNode->obj->tile));
|
lightIntensity = std::max(ambientIntensity, lightGetTileIntensity(elevation, objectListNode->obj->tile));
|
||||||
|
@ -2995,7 +2971,7 @@ int _obj_intersects_with(Object* object, int x, int y)
|
||||||
// 0x48C5C4
|
// 0x48C5C4
|
||||||
int _obj_create_intersect_list(int x, int y, int elevation, int objectType, ObjectWithFlags** entriesPtr)
|
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;
|
*entriesPtr = NULL;
|
||||||
|
|
||||||
if (gObjectsUpdateAreaHexSize <= 0) {
|
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;
|
int parity = gCenterTile & 1;
|
||||||
for (int index = 0; index < gObjectsUpdateAreaHexSize; index++) {
|
for (int index = 0; index < gObjectsUpdateAreaHexSize; index++) {
|
||||||
int v7 = _orderTable[parity][index];
|
int offsetIndex = _orderTable[parity][index];
|
||||||
if (_offsetDivTable[v7] < 30 && _offsetModTable[v7] < 20) {
|
if (_offsetDivTable[offsetIndex] < 30 && _offsetModTable[offsetIndex] < 20) {
|
||||||
ObjectListNode* objectListNode = gObjectListHeadByTile[_offsetTable[parity][v7] + v5];
|
int tile = _offsetTable[parity][offsetIndex] + upperLeftTile;
|
||||||
|
ObjectListNode* objectListNode = hexGridTileIsValid(tile)
|
||||||
|
? gObjectListHeadByTile[tile]
|
||||||
|
: NULL;
|
||||||
while (objectListNode != NULL) {
|
while (objectListNode != NULL) {
|
||||||
Object* object = objectListNode->obj;
|
Object* object = objectListNode->obj;
|
||||||
if (object->elevation > elevation) {
|
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;
|
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
|
// 0x4B1754
|
||||||
int tileFromScreenXY(int screenX, int screenY, int elevation)
|
int tileFromScreenXY(int screenX, int screenY, int elevation, bool ignoreBounds)
|
||||||
{
|
{
|
||||||
int v2;
|
int v2;
|
||||||
int v3;
|
int v3;
|
||||||
|
@ -763,6 +768,10 @@ int tileFromScreenXY(int screenX, int screenY, int elevation)
|
||||||
return gHexGridWidth * v10 + v12;
|
return gHexGridWidth * v10 + v12;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ignoreBounds) {
|
||||||
|
return gHexGridWidth * v10 + v12;
|
||||||
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ void tileWindowRefresh();
|
||||||
int tileSetCenter(int tile, int flags);
|
int tileSetCenter(int tile, int flags);
|
||||||
int tileRoofIsVisible();
|
int tileRoofIsVisible();
|
||||||
int tileToScreenXY(int tile, int* x, int* y, int elevation);
|
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);
|
int tileDistanceBetween(int a1, int a2);
|
||||||
bool tileIsInFrontOf(int tile1, int tile2);
|
bool tileIsInFrontOf(int tile1, int tile2);
|
||||||
bool tileIsToRightOf(int tile1, int tile2);
|
bool tileIsToRightOf(int tile1, int tile2);
|
||||||
|
|
Loading…
Reference in New Issue