Implement Clip Context (#1072)

* Implement clipContext

* Switch over all callers to use new version
This commit is contained in:
Duncan 2021-08-08 13:33:58 +01:00 committed by GitHub
parent 139eebf1c0
commit e698c13357
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 79 additions and 93 deletions

View File

@ -1410,23 +1410,23 @@ namespace OpenLoco::Gfx
call(0x00448D90, regs);
}
bool clipContext(Gfx::Context** dst, Gfx::Context* src, int16_t x, int16_t y, int16_t width, int16_t height)
// 0x004CEC50
std::optional<Gfx::Context> clipContext(const Gfx::Context& src, const Ui::Rect& newRect)
{
registers regs;
regs.ax = x;
regs.bx = width;
regs.edi = X86Pointer(src);
regs.dx = height;
regs.cx = y;
call(0x4cec50, regs);
*dst = X86Pointer<Gfx::Context>(regs.edi);
const Ui::Rect oldRect = src.getUiRect();
Ui::Rect intersect = oldRect.intersection(newRect);
const auto stride = oldRect.size.width + src.pitch;
const int16_t newPitch = stride - intersect.size.width;
auto* newBits = src.bits + (stride * (intersect.origin.y - oldRect.origin.y) + (intersect.origin.x - oldRect.origin.x));
intersect.origin.x = std::max(0, oldRect.origin.x - newRect.origin.x);
intersect.origin.y = std::max(0, oldRect.origin.y - newRect.origin.y);
Gfx::Context newContext{ newBits, static_cast<int16_t>(intersect.origin.x), static_cast<int16_t>(intersect.origin.y), static_cast<int16_t>(intersect.size.width), static_cast<int16_t>(intersect.size.height), newPitch, 0 };
return *dst != nullptr;
}
bool clipContext(Gfx::Context** dst, Gfx::Context* src, Point pos, Ui::Size size)
{
return clipContext(dst, src, pos.x, pos.y, size.width, size.height);
if (newContext.width <= 0 || newContext.height <= 0)
{
return {};
}
return { newContext };
}
G1Element* getG1Element(uint32_t id)

View File

@ -243,7 +243,7 @@ namespace OpenLoco::Gfx
void redrawScreenRect(Ui::Rect rect);
void redrawScreenRect(int16_t left, int16_t top, int16_t right, int16_t bottom);
bool clipContext(Gfx::Context** dst, Gfx::Context* src, int16_t x, int16_t y, int16_t width, int16_t height);
bool clipContext(Gfx::Context** dst, Gfx::Context* src, Ui::Point pos, Ui::Size size);
std::optional<Gfx::Context> clipContext(const Gfx::Context& src, const Ui::Rect& newRect);
G1Element* getG1Element(uint32_t id);
}

View File

@ -294,8 +294,8 @@ namespace OpenLoco::Ui
// 0x004CAAB9
void Widget::drawFrame(Gfx::Context* context, const Window* window, uint16_t flags, uint8_t colour)
{
Gfx::Context* clipped = nullptr;
if (Gfx::clipContext(&clipped, context, left + window->x, top + window->y, right - left, 41))
auto clipped = Gfx::clipContext(*context, Ui::Rect(left + window->x, top + window->y, right - left, 41));
if (clipped)
{
uint32_t imageId = image;
if (window->flags & WindowFlags::flag_11)
@ -306,7 +306,7 @@ namespace OpenLoco::Ui
{
imageId = Gfx::recolour(ImageIds::frame_background_image_alt, Colour::opaque(colour));
}
Gfx::drawImage(clipped, 0, 0, imageId);
Gfx::drawImage(&*clipped, 0, 0, imageId);
}
uint8_t shade;

View File

@ -486,9 +486,8 @@ namespace OpenLoco::Ui::Windows::Construction
if (self->current_tab == widx::tab_station - widx::tab_construction)
height++;
Gfx::Context* clipped = nullptr;
if (Gfx::clipContext(&clipped, context, x, y, width, height))
auto clipped = Gfx::clipContext(*context, Ui::Rect(x, y, width, height));
if (clipped)
{
clipped->zoom_level = 1;
clipped->width <<= 1;
@ -497,14 +496,14 @@ namespace OpenLoco::Ui::Windows::Construction
clipped->y <<= 1;
auto roadStationObj = ObjectManager::get<RoadStationObject>(_lastSelectedStationType);
auto imageId = Gfx::recolour(roadStationObj->image, companyColour);
Gfx::drawImage(clipped, -4, -10, imageId);
Gfx::drawImage(&*clipped, -4, -10, imageId);
auto colour = _byte_5045FA[companyColour];
if (!(roadStationObj->flags & RoadStationFlags::recolourable))
{
colour = PaletteIndex::index_2E;
}
imageId = Gfx::recolour(roadStationObj->image, colour) + 1;
Gfx::drawImage(clipped, -4, -10, imageId);
Gfx::drawImage(&*clipped, -4, -10, imageId);
}
Widget::drawTab(self, context, -2, widx::tab_station);
@ -578,9 +577,8 @@ namespace OpenLoco::Ui::Windows::Construction
if (self->current_tab == widx::tab_station - widx::tab_construction)
height++;
Gfx::Context* clipped = nullptr;
if (Gfx::clipContext(&clipped, context, x, y, width, height))
auto clipped = Gfx::clipContext(*context, Ui::Rect(x, y, width, height));
if (clipped)
{
clipped->zoom_level = 1;
clipped->width *= 2;
@ -590,7 +588,7 @@ namespace OpenLoco::Ui::Windows::Construction
auto trainStationObj = ObjectManager::get<TrainStationObject>(_lastSelectedStationType);
auto imageId = Gfx::recolour(trainStationObj->image + TrainStation::ImageIds::preview_image, companyColour);
Gfx::drawImage(clipped, -4, -9, imageId);
Gfx::drawImage(&*clipped, -4, -9, imageId);
auto colour = _byte_5045FA[companyColour];
if (!(trainStationObj->flags & TrainStationFlags::recolourable))
@ -598,7 +596,7 @@ namespace OpenLoco::Ui::Windows::Construction
colour = PaletteIndex::index_2E;
}
imageId = Gfx::recolourTranslucent(trainStationObj->image + TrainStation::ImageIds::preview_image_windows, colour);
Gfx::drawImage(clipped, -4, -9, imageId);
Gfx::drawImage(&*clipped, -4, -9, imageId);
}
Widget::drawTab(self, context, -2, widx::tab_station);
@ -618,9 +616,8 @@ namespace OpenLoco::Ui::Windows::Construction
if (self->current_tab == widx::tab_station - widx::tab_construction)
height++;
Gfx::Context* clipped = nullptr;
if (Gfx::clipContext(&clipped, context, x, y, width, height))
auto clipped = Gfx::clipContext(*context, Ui::Rect(x, y, width, height));
if (clipped)
{
auto trainSignalObject = ObjectManager::get<TrainSignalObject>(_lastSelectedSignal);
auto imageId = trainSignalObject->image;
@ -633,7 +630,7 @@ namespace OpenLoco::Ui::Windows::Construction
frameIndex <<= 3;
imageId += frameIndex;
}
Gfx::drawImage(clipped, 15, 31, imageId);
Gfx::drawImage(&*clipped, 15, 31, imageId);
}
Widget::drawTab(self, context, -2, widx::tab_signal);

View File

@ -1987,9 +1987,8 @@ namespace OpenLoco::Ui::Windows::Construction::Construction
auto width = self->widgets[widx::construct].width();
auto height = self->widgets[widx::construct].height();
Gfx::Context* clipped = nullptr;
if (Gfx::clipContext(&clipped, context, x, y, width, height))
auto clipped = Gfx::clipContext(*context, Ui::Rect(x, y, width, height));
if (clipped)
{
const auto& roadPiece = Map::TrackData::getRoadPiece(_lastSelectedTrackPieceId);
const auto& lastRoadPart = roadPiece.back();
@ -2010,8 +2009,9 @@ namespace OpenLoco::Ui::Windows::Construction::Construction
pos3D.z += 0x1CC;
auto pos2D = gameToScreen(pos3D, gCurrentRotation);
Point pos = { pos2D.x, pos2D.y };
drawRoadCost(self, clipped, context, pos, width, height);
drawRoadCost(self, &*clipped, context, pos, width, height);
}
else
{
@ -2037,9 +2037,8 @@ namespace OpenLoco::Ui::Windows::Construction::Construction
auto width = self->widgets[widx::construct].width();
auto height = self->widgets[widx::construct].height();
Gfx::Context* clipped = nullptr;
if (Gfx::clipContext(&clipped, context, x, y, width, height))
auto clipped = Gfx::clipContext(*context, Ui::Rect(x, y, width, height));
if (clipped)
{
const auto& trackPiece = Map::TrackData::getTrackPiece(_lastSelectedTrackPieceId);
const auto& lastTrackPart = trackPiece.back();
@ -2060,8 +2059,9 @@ namespace OpenLoco::Ui::Windows::Construction::Construction
pos3D.z += 0x1CC;
auto pos2D = gameToScreen(pos3D, gCurrentRotation);
Point pos = { pos2D.x, pos2D.y };
drawTrackCost(self, clipped, context, pos, width, height);
drawTrackCost(self, &*clipped, context, pos, width, height);
}
else
{

View File

@ -240,13 +240,12 @@ namespace OpenLoco::Ui::Windows::Construction::Overhead
Common::drawTabs(self, context);
if (_lastSelectedMods & 0xF)
{
Gfx::Context* clipped = nullptr;
auto xPos = self->x + self->widgets[widx::image].left + 1;
auto yPos = self->y + self->widgets[widx::image].top + 1;
auto width = self->widgets[widx::image].width();
auto height = self->widgets[widx::image].height();
if (Gfx::clipContext(&clipped, context, xPos, yPos, width, height))
auto clipped = Gfx::clipContext(*context, Ui::Rect(xPos, yPos, width, height));
if (clipped)
{
coord_t x = 0x2010;
coord_t y = 0x2010;
@ -259,7 +258,7 @@ namespace OpenLoco::Ui::Windows::Construction::Overhead
clipped->x += screenPos.x;
clipped->y += screenPos.y;
_dword_E0C3E0 = clipped;
_dword_E0C3E0 = &*clipped;
x = 0x2000;
y = 0x2000;
@ -278,6 +277,7 @@ namespace OpenLoco::Ui::Windows::Construction::Overhead
Construction::drawTrack(x, y, _lastSelectedMods, 0x1D0, _trackType, 0, companyColour, gCurrentRotation);
}
_byte_522095 = _byte_522095 & ~(1 << 0);
_dword_E0C3E0 = nullptr;
}
}

View File

@ -68,10 +68,10 @@ namespace OpenLoco::Ui::Windows::DragVehiclePart
static void draw(Ui::Window* const self, Gfx::Context* const context)
{
Gfx::Context* clipped;
if (Gfx::clipContext(&clipped, context, self->x, self->y, self->width, self->height))
auto clipped = Gfx::clipContext(*context, Ui::Rect(self->x, self->y, self->width, self->height));
if (clipped)
{
Vehicle::Common::sub_4B743B(0, 0, 0, 19, _dragCarComponent, clipped);
Vehicle::Common::sub_4B743B(0, 0, 0, 19, _dragCarComponent, &*clipped);
}
}

View File

@ -895,11 +895,10 @@ namespace OpenLoco::Ui::Windows::IndustryList
auto industryObj = ObjectManager::get<IndustryObject>(self.row_info[i]);
Gfx::Context* clipped = nullptr;
if (Gfx::clipContext(&clipped, &context, xPos + 1, yPos + 1, 110, 110))
auto clipped = Gfx::clipContext(context, Ui::Rect(xPos + 1, yPos + 1, 110, 110));
if (clipped)
{
industryObj->drawIndustry(clipped, 56, 96);
industryObj->drawIndustry(&*clipped, 56, 96);
}
xPos += rowHeight;

View File

@ -164,11 +164,10 @@ namespace OpenLoco::Ui::Windows::NewsWindow::Ticker
auto y = self->y;
auto width = self->width;
auto height = self->height;
Gfx::Context* clipped = nullptr;
Gfx::clipContext(&clipped, context, x, y, width, height);
auto clipped = Gfx::clipContext(*context, { x, y, width, height });
if (clipped == nullptr)
if (!clipped)
return;
auto colour = Colour::getShade(Colour::white, 5);
@ -222,7 +221,7 @@ namespace OpenLoco::Ui::Windows::NewsWindow::Ticker
}
uint32_t ebp = (((_word_525CE0 & ~(1 << 15)) >> 2) << 16) | 109;
sub_4950EF(clipped, StringIds::buffer_2039, (1 << 18), ebp, 55, 0);
sub_4950EF(&*clipped, StringIds::buffer_2039, (1 << 18), ebp, 55, 0);
}
void initEvents()

View File

@ -316,10 +316,10 @@ namespace OpenLoco::Ui::Windows::ObjectSelectionWindow
{
auto type = header->getType();
Gfx::Context* clipped = nullptr;
// Clip the draw area to simplify image draw
Ui::Point drawAreaPos = Ui::Point{ x, y } - objectPreviewOffset;
if (!Gfx::clipContext(&clipped, context, drawAreaPos, objectPreviewSize))
auto clipped = Gfx::clipContext(*context, Ui::Rect(drawAreaPos.x, drawAreaPos.y, objectPreviewSize.width, objectPreviewSize.height));
if (!clipped)
return;
switch (type)
@ -451,11 +451,11 @@ namespace OpenLoco::Ui::Windows::ObjectSelectionWindow
static void drawDescription(ObjectHeader* header, Window* self, Gfx::Context* context, int16_t x, int16_t y, void* objectPtr)
{
Gfx::Context* clipped = nullptr;
int16_t width = self->x + self->width - x;
int16_t height = self->y + self->height - y;
// Clip the draw area to simplify image draw
if (!Gfx::clipContext(&clipped, context, x, y, width, height))
auto clipped = Gfx::clipContext(*context, Ui::Rect(x, y, width, height));
if (!clipped)
return;
switch (header->getType())

View File

@ -98,12 +98,12 @@ namespace OpenLoco::Ui::Windows::ProgressBar
{
self->draw(context);
Gfx::Context* clipped = nullptr;
if (!Gfx::clipContext(&clipped, context, Ui::Point(self->x + 2, self->y + 17), Ui::Size(self->width - 5, self->height - 19)))
auto clipped = Gfx::clipContext(*context, Ui::Rect(self->x + 2, self->y + 17, self->width - 5, self->height - 19));
if (!clipped)
return;
// First, draw the train track.
Gfx::drawImage(clipped, 0, 0, ImageIds::progressbar_track);
Gfx::drawImage(&*clipped, 0, 0, ImageIds::progressbar_track);
// What train image to use depends on the progress bar style.
uint32_t trainImage;
@ -134,7 +134,7 @@ namespace OpenLoco::Ui::Windows::ProgressBar
// Draw the train image from the right of the window,
int16_t xPos = _progressBarValue - 255;
Gfx::drawImage(clipped, xPos, 0, trainImage);
Gfx::drawImage(&*clipped, xPos, 0, trainImage);
}
static void initEvents()

View File

@ -476,14 +476,8 @@ namespace OpenLoco::Ui::Windows::PromptBrowse
Gfx::drawString_494B3F(*context, window->x + 3, window->y + filenameBox.top + 2, 0, StringIds::window_browse_filename, nullptr);
// Clip to text box
Gfx::Context* context2;
if (Gfx::clipContext(
&context2,
context,
window->x + filenameBox.left + 1,
window->y + filenameBox.top + 1,
filenameBox.right - filenameBox.left - 1,
filenameBox.bottom - filenameBox.top - 1))
auto context2 = Gfx::clipContext(*context, Ui::Rect(window->x + filenameBox.left + 1, window->y + filenameBox.top + 1, filenameBox.right - filenameBox.left - 1, filenameBox.bottom - filenameBox.top - 1));
if (context2)
{
drawTextInput(window, *context2, inputSession.buffer.c_str(), inputSession.cursorPosition, (inputSession.cursorFrame & 0x10) == 0);
}

View File

@ -916,11 +916,10 @@ namespace OpenLoco::Ui::Windows::Terraform
}
auto treeObj = ObjectManager::get<TreeObject>(self.row_info[i]);
Gfx::Context* clipped = nullptr;
if (Gfx::clipContext(&clipped, &context, xPos + 1, yPos + 1, 64, rowHeight - 2))
auto clipped = Gfx::clipContext(context, Ui::Rect(xPos + 1, yPos + 1, 64, rowHeight - 2));
if (clipped)
{
drawTreeThumb(treeObj, clipped);
drawTreeThumb(treeObj, &*clipped);
}
xPos += columnWidth;
@ -2351,10 +2350,9 @@ namespace OpenLoco::Ui::Windows::Terraform
auto wallObj = ObjectManager::get<WallObject>(self.row_info[i]);
Gfx::Context* clipped = nullptr;
if (Gfx::clipContext(&clipped, &context, xPos + 1, yPos + 1, 39, 47))
Gfx::drawImage(clipped, 34, 28, wallObj->sprite);
auto clipped = Gfx::clipContext(context, Ui::Rect(xPos + 1, yPos + 1, 39, 47));
if (clipped)
Gfx::drawImage(&*clipped, 34, 28, wallObj->sprite);
xPos += 40;

View File

@ -243,8 +243,8 @@ namespace OpenLoco::Ui::Windows::TextInput
Gfx::drawStringCentredWrapped(*context, position, window->width - 8, 0, StringIds::wcolour2_stringid, &_commonFormatArgs[0]);
auto widget = &_widgets[Widx::input];
Gfx::Context* clipped = nullptr;
if (!Gfx::clipContext(&clipped, context, widget->left + 1 + window->x, widget->top + 1 + window->y, widget->width() - 2, widget->height() - 2))
auto clipped = Gfx::clipContext(*context, Ui::Rect(widget->left + 1 + window->x, widget->top + 1 + window->y, widget->width() - 2, widget->height() - 2));
if (!clipped)
{
return;
}
@ -268,7 +268,7 @@ namespace OpenLoco::Ui::Windows::TextInput
*((string_id*)(&_commonFormatArgs[0])) = StringIds::buffer_2039;
position = { inputSession.xOffset, 1 };
Gfx::drawString_494B3F(*clipped, &position, 0, StringIds::black_stringid, _commonFormatArgs);
Gfx::fillRect(clipped, position.x, position.y, position.x, position.y + 9, Colour::getShade(window->getColour(WindowColour::secondary), 9));
Gfx::fillRect(&*clipped, position.x, position.y, position.x, position.y + 9, Colour::getShade(window->getColour(WindowColour::secondary), 9));
}
// 0x004CE8B6

View File

@ -1205,9 +1205,8 @@ namespace OpenLoco::Ui::Windows::TownList
auto buildingObj = ObjectManager::get<BuildingObject>(self.row_info[i]);
Gfx::Context* clipped = nullptr;
if (Gfx::clipContext(&clipped, &context, xPos + 1, yPos + 1, 110, 110))
auto clipped = Gfx::clipContext(context, Ui::Rect(xPos + 1, yPos + 1, 110, 110));
if (clipped)
{
Colour_t colour = _buildingColour;
if (self.row_hover != self.row_info[i])
@ -1217,7 +1216,7 @@ namespace OpenLoco::Ui::Windows::TownList
colour = 0;
}
buildingObj->drawBuilding(clipped, _buildingRotation, 56, 96, colour);
buildingObj->drawBuilding(&*clipped, _buildingRotation, 56, 96, colour);
}
xPos += 112;

View File

@ -400,8 +400,8 @@ namespace OpenLoco::Ui::Windows::Town
self->draw(context);
Common::drawTabs(self, context);
Gfx::Context* clipped = nullptr;
if (!Gfx::clipContext(&clipped, context, self->x, self->y + 44, self->width, self->height - 44))
auto clipped = Gfx::clipContext(*context, Ui::Rect(self->x, self->y + 44, self->width, self->height - 44));
if (!clipped)
return;
auto town = TownManager::get(self->number);
@ -414,7 +414,7 @@ namespace OpenLoco::Ui::Windows::Town
args.push(yTick);
const uint16_t xPos = 39;
Gfx::drawRect(clipped, xPos, yPos, 241, 1, Colour::getShade(self->getColour(WindowColour::secondary), 4));
Gfx::drawRect(&*clipped, xPos, yPos, 241, 1, Colour::getShade(self->getColour(WindowColour::secondary), 4));
Gfx::drawString_494C78(*clipped, xPos, yPos - 6, Colour::black, StringIds::population_graph_people, &args);
@ -441,7 +441,7 @@ namespace OpenLoco::Ui::Windows::Town
Gfx::drawStringCentred(*clipped, xPos, yPos, Colour::black, StringIds::population_graph_year, &args);
}
Gfx::drawRect(clipped, xPos, 11, 1, self->height - 66, Colour::getShade(self->getColour(WindowColour::secondary), 4));
Gfx::drawRect(&*clipped, xPos, 11, 1, self->height - 66, Colour::getShade(self->getColour(WindowColour::secondary), 4));
}
// Draw population graph
@ -450,7 +450,7 @@ namespace OpenLoco::Ui::Windows::Town
// Do not draw current segment yet; it may be zeroed.
if (i < town->history_size - 1)
Gfx::drawLine(clipped, xPos, yPos1, xPos + 1, yPos2, Colour::getShade(self->getColour(WindowColour::secondary), 7));
Gfx::drawLine(&*clipped, xPos, yPos1, xPos + 1, yPos2, Colour::getShade(self->getColour(WindowColour::secondary), 7));
month--;
if (month < 0)