Use stack on the heap for roof fill (#263)

This commit is contained in:
Vasilii Rogin 2023-04-18 11:06:07 +03:00 committed by GitHub
parent 99bc14cf3a
commit 0a85ce520b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -5,6 +5,7 @@
#include <string.h>
#include <algorithm>
#include <stack>
#include "art.h"
#include "color.h"
@ -49,11 +50,16 @@ typedef struct UpsideDownTriangle {
int field_8;
} UpsideDownTriangle;
struct roof_fill_task {
int x;
int y;
};
static void tileSetBorder(int windowWidth, int windowHeight, int hexGridWidth, int hexGridHeight);
static void tileRefreshMapper(Rect* rect, int elevation);
static void tileRefreshGame(Rect* rect, int elevation);
static void roof_fill_on(int x, int y, int elevation);
static void roof_fill_off(int x, int y, int elevation);
static void roof_fill_push_task_if_in_bounds(std::stack<roof_fill_task>& tasks_stack, int x, int y);
static void roof_fill_off_process_task(std::stack<roof_fill_task>& tasks_stack, int elevation, bool on);
static void tileRenderRoof(int fid, int x, int y, Rect* rect, int light);
static void _draw_grid(int tile, int elevation, Rect* rect);
static void tileRenderFloor(int fid, int x, int y, Rect* rect);
@ -1258,27 +1264,39 @@ void tileRenderRoofsInRect(Rect* rect, int elevation)
}
}
// 0x4B22D0
static void roof_fill_on(int x, int y, int elevation)
static void roof_fill_push_task_if_in_bounds(std::stack<roof_fill_task>& tasks_stack, int x, int y)
{
if (x >= 0 && x < gSquareGridWidth && y >= 0 && y < gSquareGridHeight) {
int squareTileIndex = gSquareGridWidth * y + x;
int squareTile = gTileSquares[elevation]->field_0[squareTileIndex];
int roof = (squareTile >> 16) & 0xFFFF;
tasks_stack.push(roof_fill_task { x, y });
};
};
int id = roof & 0xFFF;
if (buildFid(OBJ_TYPE_TILE, id, 0, 0, 0) != buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0)) {
int flag = (roof & 0xF000) >> 12;
if ((flag & 0x01) != 0) {
static void roof_fill_off_process_task(std::stack<roof_fill_task>& tasks_stack, int elevation, bool on)
{
auto [x, y] = tasks_stack.top();
tasks_stack.pop();
int squareTileIndex = gSquareGridWidth * y + x;
int squareTile = gTileSquares[elevation]->field_0[squareTileIndex];
int roof = (squareTile >> 16) & 0xFFFF;
int id = roof & 0xFFF;
if (buildFid(OBJ_TYPE_TILE, id, 0, 0, 0) != buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0)) {
int flag = (roof & 0xF000) >> 12;
if (on ? ((flag & 0x01) != 0) : ((flag & 0x03) == 0)) {
if (on) {
flag &= ~0x01;
gTileSquares[elevation]->field_0[squareTileIndex] = (squareTile & 0xFFFF) | (((flag << 12) | id) << 16);
roof_fill_on(x - 1, y, elevation);
roof_fill_on(x + 1, y, elevation);
roof_fill_on(x, y - 1, elevation);
roof_fill_on(x, y + 1, elevation);
} else {
flag |= 0x01;
}
gTileSquares[elevation]->field_0[squareTileIndex] = (squareTile & 0xFFFF) | (((flag << 12) | id) << 16);
roof_fill_push_task_if_in_bounds(tasks_stack, x - 1, y);
roof_fill_push_task_if_in_bounds(tasks_stack, x + 1, y);
roof_fill_push_task_if_in_bounds(tasks_stack, x, y - 1);
roof_fill_push_task_if_in_bounds(tasks_stack, x, y + 1);
}
}
}
@ -1286,35 +1304,12 @@ static void roof_fill_on(int x, int y, int elevation)
// 0x4B23D4
void tile_fill_roof(int x, int y, int elevation, bool on)
{
if (on) {
roof_fill_on(x, y, elevation);
} else {
roof_fill_off(x, y, elevation);
}
}
std::stack<roof_fill_task> tasks_stack;
// 0x4B23DC
static void roof_fill_off(int x, int y, int elevation)
{
if (x >= 0 && x < gSquareGridWidth && y >= 0 && y < gSquareGridHeight) {
int squareTileIndex = gSquareGridWidth * y + x;
int squareTile = gTileSquares[elevation]->field_0[squareTileIndex];
int roof = (squareTile >> 16) & 0xFFFF;
roof_fill_push_task_if_in_bounds(tasks_stack, x, y);
int id = roof & 0xFFF;
if (buildFid(OBJ_TYPE_TILE, id, 0, 0, 0) != buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0)) {
int flag = (roof & 0xF000) >> 12;
if ((flag & 0x03) == 0) {
flag |= 0x01;
gTileSquares[elevation]->field_0[squareTileIndex] = (squareTile & 0xFFFF) | (((flag << 12) | id) << 16);
roof_fill_off(x - 1, y, elevation);
roof_fill_off(x + 1, y, elevation);
roof_fill_off(x, y - 1, elevation);
roof_fill_off(x, y + 1, elevation);
}
}
while (!tasks_stack.empty()) {
roof_fill_off_process_task(tasks_stack, elevation, on);
}
}