# base.cpp

Go to the documentation of this file.

    00001 /* $Id: base.cpp 25911 2013-10-23 19:41:20Z fonsinchen $ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
    00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
    00008  */
    00009
    00012 #include "../stdafx.h"
    00013 #include "base.hpp"
    00014 #include "../core/math_func.hpp"
    00015
    00016 void Blitter::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash)
    00017 {
    00018   int dy;
    00019   int dx;
    00020   int stepx;
    00021   int stepy;
    00022
    00023   dy = (y2 - y) * 2;
    00024   if (dy < 0) {
    00025     dy = -dy;
    00026     stepy = -1;
    00027   } else {
    00028     stepy = 1;
    00029   }
    00030
    00031   dx = (x2 - x) * 2;
    00032   if (dx < 0) {
    00033     dx = -dx;
    00034     stepx = -1;
    00035   } else {
    00036     stepx = 1;
    00037   }
    00038
    00039   if (dx == 0 && dy == 0) {
    00040     /* The algorithm below cannot handle this special case; make it work at least for line width 1 */
    00041     if (x >= 0 && x < screen_width && y >= 0 && y < screen_height) this->SetPixel(video, x, y, colour);
    00042     return;
    00043   }
    00044
    00045   int frac_diff = width * max(dx, dy);
    00046   if (width > 1) {
    00047     /* compute frac_diff = width * sqrt(dx*dx + dy*dy)
    00048      * Start interval:
    00049      *    max(dx, dy) <= sqrt(dx*dx + dy*dy) <= sqrt(2) * max(dx, dy) <= 3/2 * max(dx, dy) */
    00050     int frac_sq = width * width * (dx * dx + dy * dy);
    00051     int frac_max = 3 * frac_diff / 2;
    00052     while (frac_diff < frac_max) {
    00053       int frac_test = (frac_diff + frac_max) / 2;
    00054       if (frac_test * frac_test < frac_sq) {
    00055         frac_diff = frac_test + 1;
    00056       } else {
    00057         frac_max = frac_test - 1;
    00058       }
    00059     }
    00060   }
    00061
    00062   int gap = dash;
    00063   if (dash == 0) dash = 1;
    00064   int dash_count = 0;
    00065   if (dx > dy) {
    00066     int y_low     = y;
    00067     int y_high    = y;
    00068     int frac_low  = dy - frac_diff / 2;
    00069     int frac_high = dy + frac_diff / 2;
    00070
    00071     while (frac_low + dx / 2 < 0) {
    00072       frac_low += dx;
    00073       y_low -= stepy;
    00074     }
    00075     while (frac_high - dx / 2 >= 0) {
    00076       frac_high -= dx;
    00077       y_high += stepy;
    00078     }
    00079     x2 += stepx;
    00080
    00081     while (x != x2) {
    00082       if (dash_count < dash && x >= 0 && x < screen_width) {
    00083         for (int y = y_low; y != y_high; y += stepy) {
    00084           if (y >= 0 && y < screen_height) this->SetPixel(video, x, y, colour);
    00085         }
    00086       }
    00087       if (frac_low >= 0) {
    00088         y_low += stepy;
    00089         frac_low -= dx;
    00090       }
    00091       if (frac_high >= 0) {
    00092         y_high += stepy;
    00093         frac_high -= dx;
    00094       }
    00095       x += stepx;
    00096       frac_low += dy;
    00097       frac_high += dy;
    00098       if (++dash_count >= dash + gap) dash_count = 0;
    00099     }
    00100   } else {
    00101     int x_low     = x;
    00102     int x_high    = x;
    00103     int frac_low  = dx - frac_diff / 2;
    00104     int frac_high = dx + frac_diff / 2;
    00105
    00106     while (frac_low + dy / 2 < 0) {
    00107       frac_low += dy;
    00108       x_low -= stepx;
    00109     }
    00110     while (frac_high - dy / 2 >= 0) {
    00111       frac_high -= dy;
    00112       x_high += stepx;
    00113     }
    00114     y2 += stepy;
    00115
    00116     while (y != y2) {
    00117       if (dash_count < dash && y >= 0 && y < screen_height) {
    00118         for (int x = x_low; x != x_high; x += stepx) {
    00119           if (x >= 0 && x < screen_width) this->SetPixel(video, x, y, colour);
    00120         }
    00121       }
    00122       if (frac_low >= 0) {
    00123         x_low += stepx;
    00124         frac_low -= dy;
    00125       }
    00126       if (frac_high >= 0) {
    00127         x_high += stepx;
    00128         frac_high -= dy;
    00129       }
    00130       y += stepy;
    00131       frac_low += dx;
    00132       frac_high += dx;
    00133       if (++dash_count >= dash + gap) dash_count = 0;
    00134     }
    00135   }
    00136 }