1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-18 20:43:04 +01:00

Added line clipping code to OpenGL renderer

This commit is contained in:
Michael Bernardi
2024-07-16 01:46:24 +10:00
parent ef97216ea1
commit 0b50ef6fd2
2 changed files with 102 additions and 5 deletions

View File

@@ -32,6 +32,7 @@
- Fix: [#22265] Button for switching covered tracks on slides doesnt stay pressed.
- Fix: [#22284] Unrated rides cause high amount of nausea.
- Fix: [#22304] Graphs dont draw lines on the left edge of the screen.
- Fix: [#22308] OpenGL draws lines incorrectly in some cases.
- Fix: [#22318] Water sparkles are missing if transparent water is enabled without RCT1 linked.
- Fix: [#22333] Tile inspector closes other tool windows.
- Fix: [#22339] Printing ui.tool.cursor in console crashes the game.

View File

@@ -50,6 +50,12 @@ struct OpenGLVersion
constexpr OpenGLVersion OPENGL_MINIMUM_REQUIRED_VERSION = { 3, 3 };
constexpr uint8_t kCSInside = 0b0000;
constexpr uint8_t kCSLeft = 0b0001;
constexpr uint8_t kCSRight = 0b0010;
constexpr uint8_t kCSTop = 0b0100;
constexpr uint8_t kCSBottom = 0b1000;
class OpenGLDrawingEngine;
class OpenGLDrawingContext final : public IDrawingContext
@@ -82,6 +88,9 @@ private:
RectCommandBatch transparent;
} _commandBuffers;
static uint8_t ComputeOutCode(ScreenCoordsXY, ScreenCoordsXY, ScreenCoordsXY);
static bool CohenSutherlandLineClip(ScreenLine&, const DrawPixelInfo&);
public:
explicit OpenGLDrawingContext(OpenGLDrawingEngine& engine);
~OpenGLDrawingContext() override;
@@ -576,17 +585,104 @@ void OpenGLDrawingContext::FilterRect(
command.depth = _drawCount++;
}
// Compute the bit code for a point p relative to the clip rectangle defined by topLeft and bottomRight
uint8_t OpenGLDrawingContext::ComputeOutCode(
const ScreenCoordsXY p, const ScreenCoordsXY topLeft, const ScreenCoordsXY bottomRight)
{
uint8_t code = kCSInside;
if (p.x < topLeft.x)
code |= kCSLeft;
else if (p.x > bottomRight.x)
code |= kCSRight;
if (p.y < topLeft.y)
code |= kCSTop;
else if (p.y > bottomRight.y)
code |= kCSBottom;
return code;
}
// Trims the line to be within the bounds of the dpi.
// based on: https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm
bool OpenGLDrawingContext::CohenSutherlandLineClip(ScreenLine& line, const DrawPixelInfo& dpi)
{
ScreenCoordsXY topLeft = { dpi.x, dpi.y };
ScreenCoordsXY bottomRight = { dpi.x + dpi.width - 1, dpi.y + dpi.height - 1 };
uint8_t outcode1 = ComputeOutCode(line.Point1, topLeft, bottomRight);
uint8_t outcode2 = ComputeOutCode(line.Point2, topLeft, bottomRight);
while (true)
{
if (outcode1 == kCSInside && outcode2 == kCSInside)
{
// both points inside dpi
return true;
}
if (outcode1 & outcode2)
{
// both points share an outside zone so both must be outside dpi
return false;
}
// At least one endpoint is outside the clip rectangle; pick it.
uint8_t outcodeOut = outcode2 > outcode1 ? outcode2 : outcode1;
ScreenCoordsXY clipped;
// clang-format off
if (outcodeOut & kCSBottom)
{
clipped.x = line.Point1.x + (line.Point2.x - line.Point1.x) *
(bottomRight.y - line.Point1.y) / (line.Point2.y - line.Point1.y);
clipped.y = bottomRight.y;
}
else if (outcodeOut & kCSTop)
{
clipped.x = line.Point1.x + (line.Point2.x - line.Point1.x) *
(topLeft.y - line.Point1.y) / (line.Point2.y - line.Point1.y);
clipped.y = topLeft.y;
}
else if (outcodeOut & kCSRight)
{
clipped.y = line.Point1.y + (line.Point2.y - line.Point1.y) *
(bottomRight.x - line.Point1.x) / (line.Point2.x - line.Point1.x);
clipped.x = bottomRight.x;
}
else if (outcodeOut & kCSLeft)
{
clipped.y = line.Point1.y + (line.Point2.y - line.Point1.y) *
(topLeft.x - line.Point1.x) / (line.Point2.x - line.Point1.x);
clipped.x = topLeft.x;
}
// clang-format on
if (outcodeOut == outcode1)
{
line.Point1 = clipped;
outcode1 = ComputeOutCode(line.Point1, topLeft, bottomRight);
}
else
{
line.Point2 = clipped;
outcode2 = ComputeOutCode(line.Point2, topLeft, bottomRight);
}
}
}
void OpenGLDrawingContext::DrawLine(DrawPixelInfo& dpi, uint32_t colour, const ScreenLine& line)
{
// Note: this function does not respect DPI bounds.
ScreenLine trimmedLine = line;
if (!CohenSutherlandLineClip(trimmedLine, dpi))
return;
CalculcateClipping(dpi);
DrawLineCommand& command = _commandBuffers.lines.allocate();
const int32_t x1 = dpi.zoom_level.ApplyInversedTo(line.GetX1() - dpi.x) + _clipLeft;
const int32_t y1 = dpi.zoom_level.ApplyInversedTo(line.GetY1() - dpi.y) + _clipTop;
const int32_t x2 = dpi.zoom_level.ApplyInversedTo(line.GetX2() - dpi.x) + _clipLeft;
const int32_t y2 = dpi.zoom_level.ApplyInversedTo(line.GetY2() - dpi.y) + _clipTop;
const int32_t x1 = dpi.zoom_level.ApplyInversedTo(trimmedLine.GetX1() - dpi.x) + _clipLeft;
const int32_t y1 = dpi.zoom_level.ApplyInversedTo(trimmedLine.GetY1() - dpi.y) + _clipTop;
const int32_t x2 = dpi.zoom_level.ApplyInversedTo(trimmedLine.GetX2() - dpi.x) + _clipLeft;
const int32_t y2 = dpi.zoom_level.ApplyInversedTo(trimmedLine.GetY2() - dpi.y) + _clipTop;
command.bounds = { x1, y1, x2, y2 };
command.colour = colour & 0xFF;