MCPcopy Create free account
hub / github.com/OpenTTD/OpenTTD / GfxDoDrawLine

Function GfxDoDrawLine

src/gfx.cpp:317–365  ·  view source on GitHub ↗

* Check line clipping by using a linear equation and draw the visible part of * the line given by x/y and x2/y2. * @param video Destination pointer to draw into. * @param x X coordinate of first point. * @param y Y coordinate of first point. * @param x2 X coordinate of second point. * @param y2 Y coordinate of second point. * @param screen_width With of the screen to check clipping against.

Source from the content-addressed store, hash-verified

315 * @param dash Length of dashes for dashed lines. 0 means solid line.
316 */
317static inline void GfxDoDrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, PixelColour colour, int width, int dash = 0)
318{
319 Blitter *blitter = BlitterFactory::GetCurrentBlitter();
320
321 assert(width > 0);
322
323 if (y2 == y || x2 == x) {
324 /* Special case: horizontal/vertical line. All checks already done in GfxPreprocessLine. */
325 blitter->DrawLine(video, x, y, x2, y2, screen_width, screen_height, colour, width, dash);
326 return;
327 }
328
329 int grade_y = y2 - y;
330 int grade_x = x2 - x;
331
332 /* Clipping rectangle. Slightly extended so we can ignore the width of the line. */
333 int extra = (int)CeilDiv(3 * width, 4); // not less then "width * sqrt(2) / 2"
334 Rect clip = { -extra, -extra, screen_width - 1 + extra, screen_height - 1 + extra };
335
336 /* prevent integer overflows. */
337 int margin = 1;
338 while (INT_MAX / abs(grade_y) < std::max(abs(clip.left - x), abs(clip.right - x))) {
339 grade_y /= 2;
340 grade_x /= 2;
341 margin *= 2; // account for rounding errors
342 }
343
344 /* Prevent division by zero. */
345 if (grade_x == 0) grade_x = 1;
346
347 /* Imagine that the line is infinitely long and it intersects with
348 * infinitely long left and right edges of the clipping rectangle.
349 * If both intersection points are outside the clipping rectangle
350 * and both on the same side of it, we don't need to draw anything. */
351 int left_isec_y = y + (clip.left - x) * grade_y / grade_x;
352 int right_isec_y = y + (clip.right - x) * grade_y / grade_x;
353 if ((left_isec_y > clip.bottom + margin && right_isec_y > clip.bottom + margin) ||
354 (left_isec_y < clip.top - margin && right_isec_y < clip.top - margin)) {
355 return;
356 }
357
358 /* It is possible to use the line equation to further reduce the amount of
359 * work the blitter has to do by shortening the effective line segment.
360 * However, in order to get that right and prevent the flickering effects
361 * of rounding errors so much additional code has to be run here that in
362 * the general case the effect is not noticeable. */
363
364 blitter->DrawLine(video, x, y, x2, y2, screen_width, screen_height, colour, width, dash);
365}
366
367/**
368 * Align parameters of a line to the given DPI and check simple clipping.

Callers 2

GfxDrawLineFunction · 0.85
GfxDrawLineUnscaledFunction · 0.85

Calls 3

CeilDivFunction · 0.85
absFunction · 0.85
DrawLineMethod · 0.45

Tested by

no test coverage detected