changeset 17527:3850026e0159 draft

(svn r22291) -Add: a linewidth argument to GfxDrawLine() and Blitter::DrawLine().
author frosch <frosch@openttd.org>
date Sat, 02 Apr 2011 16:39:30 +0000
parents 6cca301c11b0
children 2922342c37f1
files src/blitter/base.cpp src/blitter/base.hpp src/gfx.cpp src/gfx_func.h
diffstat 4 files changed, 78 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/src/blitter/base.cpp
+++ b/src/blitter/base.cpp
@@ -11,6 +11,7 @@
 
 #include "../stdafx.h"
 #include "base.hpp"
+#include "../core/math_func.hpp"
 
 /**
  * Draw a line with a given colour.
@@ -22,14 +23,14 @@
  * @param screen_width The width of the screen you are drawing in (to avoid buffer-overflows).
  * @param screen_height The height of the screen you are drawing in (to avoid buffer-overflows).
  * @param colour A 8bpp mapping colour.
+ * @param width Line width.
  */
-void Blitter::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour)
+void Blitter::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width)
 {
 	int dy;
 	int dx;
 	int stepx;
 	int stepy;
-	int frac;
 
 	dy = (y2 - y) * 2;
 	if (dy < 0) {
@@ -47,29 +48,79 @@
 		stepx = 1;
 	}
 
+	int frac_diff = width * max(dx, dy);
+	if (width > 1) {
+		int frac_sq = width * width * (dx * dx + dy * dy);
+		while (frac_diff * frac_diff < frac_sq) frac_diff++;
+	}
+
 	if (dx > dy) {
-		frac = dy - (dx / 2);
-		x2 += stepx; // Make x2 the first column to not draw to
+		int y_low     = y;
+		int y_high    = y;
+		int frac_low  = dy - frac_diff / 2;
+		int frac_high = dy + frac_diff / 2;
+
+		while (frac_low + dx / 2 < 0) {
+			frac_low += dx;
+			y_low -= stepy;
+		}
+		while (frac_high - dx / 2 > 0) {
+			frac_high -= dx;
+			y_high += stepy;
+		}
+		x2 += stepx;
+
 		while (x != x2) {
-			if (x >= 0 && y >= 0 && x < screen_width && y < screen_height) this->SetPixel(video, x, y, colour);
-			if (frac >= 0) {
-				y += stepy;
-				frac -= dx;
+			if (x >= 0 && x < screen_width) {
+				for (int y = y_low; y != y_high; y += stepy) {
+					if (y >= 0 && y < screen_height) this->SetPixel(video, x, y, colour);
+				}
+			}
+			if (frac_low >= 0) {
+				y_low += stepy;
+				frac_low -= dx;
+			}
+			if (frac_high >= 0) {
+				y_high += stepy;
+				frac_high -= dx;
 			}
 			x += stepx;
-			frac += dy;
+			frac_low += dy;
+			frac_high += dy;
 		}
 	} else {
-		frac = dx - (dy / 2);
-		y2 += stepy; // Make y2 the first row to not draw to
+		int x_low     = x;
+		int x_high    = x;
+		int frac_low  = dx - frac_diff / 2;
+		int frac_high = dx + frac_diff / 2;
+
+		while (frac_low + dy / 2 < 0) {
+			frac_low += dy;
+			x_low -= stepx;
+		}
+		while (frac_high - dy / 2 > 0) {
+			frac_high -= dy;
+			x_high += stepx;
+		}
+		y2 += stepy;
+
 		while (y != y2) {
-			if (x >= 0 && y >= 0 && x < screen_width && y < screen_height) this->SetPixel(video, x, y, colour);
-			if (frac >= 0) {
-				x += stepx;
-				frac -= dy;
+			if (y >= 0 && y < screen_height) {
+				for (int x = x_low; x != x_high; x += stepx) {
+					if (x >= 0 && x < screen_width) this->SetPixel(video, x, y, colour);
+				}
+			}
+			if (frac_low >= 0) {
+				x_low += stepx;
+				frac_low -= dy;
+			}
+			if (frac_high >= 0) {
+				x_high += stepx;
+				frac_high -= dy;
 			}
 			y += stepy;
-			frac += dx;
+			frac_low += dx;
+			frac_high += dx;
 		}
 	}
 }
--- a/src/blitter/base.hpp
+++ b/src/blitter/base.hpp
@@ -101,7 +101,7 @@
 	 */
 	virtual void DrawRect(void *video, int width, int height, uint8 colour) = 0;
 
-	void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour);
+	void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width);
 
 	/**
 	 * Copy from a buffer to the screen.
--- a/src/gfx.cpp
+++ b/src/gfx.cpp
@@ -192,23 +192,25 @@
 	}
 }
 
-void GfxDrawLine(int x, int y, int x2, int y2, int colour)
+void GfxDrawLine(int x, int y, int x2, int y2, int colour, int width)
 {
 	Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
 	DrawPixelInfo *dpi = _cur_dpi;
 
+	assert(width > 0);
+
 	x -= dpi->left;
 	x2 -= dpi->left;
 	y -= dpi->top;
 	y2 -= dpi->top;
 
 	/* Check clipping */
-	if (x < 0 && x2 < 0) return;
-	if (y < 0 && y2 < 0) return;
-	if (x > dpi->width  && x2 > dpi->width)  return;
-	if (y > dpi->height && y2 > dpi->height) return;
+	if (x + width / 2 < 0           && x2 + width / 2 < 0          ) return;
+	if (y + width / 2 < 0           && y2 + width / 2 < 0          ) return;
+	if (x - width / 2 > dpi->width  && x2 - width / 2 > dpi->width ) return;
+	if (y - width / 2 > dpi->height && y2 - width / 2 > dpi->height) return;
 
-	blitter->DrawLine(dpi->dst_ptr, x, y, x2, y2, dpi->width, dpi->height, colour);
+	blitter->DrawLine(dpi->dst_ptr, x, y, x2, y2, dpi->width, dpi->height, colour, width);
 }
 
 void GfxDrawLineUnscaled(int x, int y, int x2, int y2, int colour)
@@ -229,7 +231,7 @@
 
 	blitter->DrawLine(dpi->dst_ptr, UnScaleByZoom(x, dpi->zoom), UnScaleByZoom(y, dpi->zoom),
 			UnScaleByZoom(x2, dpi->zoom), UnScaleByZoom(y2, dpi->zoom),
-			UnScaleByZoom(dpi->width, dpi->zoom), UnScaleByZoom(dpi->height, dpi->zoom), colour);
+			UnScaleByZoom(dpi->width, dpi->zoom), UnScaleByZoom(dpi->height, dpi->zoom), colour, 1);
 }
 
 /**
--- a/src/gfx_func.h
+++ b/src/gfx_func.h
@@ -118,7 +118,7 @@
 void DrawCharCentered(uint32 c, int x, int y, TextColour colour);
 
 void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode = FILLRECT_OPAQUE);
-void GfxDrawLine(int left, int top, int right, int bottom, int colour);
+void GfxDrawLine(int left, int top, int right, int bottom, int colour, int width = 1);
 void DrawBox(int x, int y, int dx1, int dy1, int dx2, int dy2, int dx3, int dy3);
 
 Dimension GetStringBoundingBox(const char *str, FontSize start_fontsize = FS_NORMAL);