1 /* 2 3 Copyright (C) 2015-2018 Night Dive Studios, LLC. 4 5 This program is free software: you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation, either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 */ 19 /* 20 * $Source: n:/project/lib/src/2d/RCS/fl8slin.h $ 21 * $Revision: 1.1 $ 22 * $Author: lmfeeney $ 23 * $Date: 1994/06/11 00:50:38 $ 24 * 25 * Routine to draw a gouraud shaded line to a flat 8 canvas. 26 * 27 * This file is part of the 2d library. 28 * 29 * $Log: fl8slin.h $ 30 * Revision 1.1 1994/06/11 00:50:38 lmfeeney 31 * Initial revision 32 * 33 * Revision 1.4 1994/05/06 18:19:13 lmfeeney 34 * rewritten for greater accuracy and speed 35 * 36 * Revision 1.3 1993/10/19 09:50:58 kaboom 37 * Replaced #include <grd.h> with new headers split from grd.h. 38 * 39 * Revision 1.2 1993/10/01 16:01:20 kaboom 40 * Pared down includes to reduce dependencies. 41 * 42 * Revision 1.1 1993/07/01 22:12:15 spaz 43 * Initial revision 44 */ 45 46 /* Draw a goroud-shaded line, specified by indices into the palette. 47 be warned, weird precision bugs abound (check out test programs 48 in /project/lib/src/2d/test). 49 50 These have been mostly corrected. See also note.txt for correctness 51 arguement of new algorithm 52 */ 53 54 /* NB: directionality policy -- reversible 55 Lines are drawn in order of increasing x or increasing y, 56 for lines that have greater x or y extent, repsectively. 57 This is done for all lines, including horiz., vert., and 58 45' lines (increasing x). 59 */ 60 61 /* NB: endpoint policy -- inclusive The left and top endpoints are 62 'trunc'-ed. The right and bottom endpoints exclude the ceiling, 63 or equivlalently, include the pixel containing the line. This is 64 calculated by subtracting epsilon (i.e. 1/65536) from its 65 fixed-point representation, then trunc'ing. 66 67 This makes sense if you note that open interval right 68 < ceil (x) 69 is the same as 70 <= trunc (x - e) 71 */ 72 73 fix x0, y0, x1, y1; 74 fix dx, dy; /* deltas in x and y */ 75 fix t; /* temporary fix */ 76 77 fix i0, i1; 78 fix di; /* delta intensity */ 79 80 uchar *p; /* pointer into the canvas */ 81 82 x0 = v0->x; 83 y0 = v0->y; 84 x1 = v1->x; 85 y1 = v1->y; 86 87 i0 = (fix)v0->i; 88 i1 = (fix)v1->i; 89 90 /* set endpoints 91 note that this cannot go negative or change octant, since the == 92 case is excluded */ 93 94 if (x0 < x1) { 95 x1 -= 1; /* e.g. - epsilon */ 96 } else if (x0 > x1) { 97 x0 -= 1; 98 } 99 100 if (y0 < y1) { 101 y1 -= 1; 102 } else if (y0 > y1) { 103 y0 -= 1; 104 } 105 106 dx = fix_trunc(x1) - fix_trunc(x0); /* x extent in pixels, (macro is flakey) */ 107 dx = fix_abs(dx); 108 dy = fix_trunc(y1) - fix_trunc(y0); /* y extent in pixels */ 109 dy = fix_abs(dy); 110 111 if (dx == 0 && dy == 0) 112 return; 113 114 /* three cases: absolute value dx < = > dy 115 116 along the longer dimension, the fixpoint x0 (or y0) is treated 117 as an int 118 119 the points are swapped if needed and the rgb initial and deltas 120 are calculated accordingly 121 122 there are two or three sub-cases - a horizontal or vertical line, 123 and the dx or dy being added or subtracted. dx and dy 124 are kept as absolute values and +/- is managed in the 125 two separate inner loops if it's a dy, since you also have to 126 manage the canvas pointer 127 128 if y is being changed by 'dy' and x is being incremented, do a 129 FunkyBitCheck (TM) to see whether the integer part of y has changed 130 and if it has, resetting the the canvas pointer to the next row 131 132 if x is being changed by 'dx' and y is being incremented, just 133 add or subtract row to increment y in the canvas 134 135 the endpoints are walked inclusively in all cases, see above 136 137 45' degree lines are explicitly special cased -- because it 138 all runs as integers, but it's probably not frequent enough 139 to justify the check 140 141 */ 142 143 if (dx > dy) { 144 145 x0 = fix_int(x0); 146 x1 = fix_int(x1); 147 148 if (x0 > x1) { 149 t = x0; 150 x0 = x1; 151 x1 = t; 152 t = y0; 153 y0 = y1; 154 y1 = t; 155 t = i0; 156 i0 = i1; 157 i1 = t; 158 } 159 160 p = grd_bm.bits + grd_bm.row * (fix_int(y0)); 161 di = fix_div((i1 - i0), dx); 162 163 if ((fix_int(y0)) == (fix_int(y1))) { 164 while (x0 <= x1) { 165 macro_plot_i(x0, p, fix_fint(i0)); 166 x0++; 167 i0 += di; 168 } 169 } else if (y0 < y1) { 170 dy = fix_div((y1 - y0), dx); 171 while (x0 <= x1) { 172 macro_plot_i(x0, p, fix_fint(i0)); 173 x0++; 174 y0 += dy; 175 p += (grd_bm.row & (-(fix_frac(y0) < dy))); 176 i0 += di; 177 } 178 } else { 179 dy = fix_div((y0 - y1), dx); 180 while (x0 <= x1) { 181 macro_plot_i(x0, p, fix_fint(i0)); 182 x0++; 183 p -= (grd_bm.row & (-(fix_frac(y0) < dy))); 184 y0 -= dy; 185 i0 += di; 186 } 187 } 188 } else if (dy > dx) { 189 190 y0 = fix_int(y0); 191 y1 = fix_int(y1); 192 193 if (y0 > y1) { 194 t = x0; 195 x0 = x1; 196 x1 = t; 197 t = y0; 198 y0 = y1; 199 y1 = t; 200 t = i0; 201 i0 = i1; 202 i1 = t; 203 } 204 205 p = grd_bm.bits + grd_bm.row * y0; 206 di = fix_div((i1 - i0), dy); 207 208 if ((fix_int(x0)) == (fix_int(x1))) { 209 x0 = fix_int(x0); 210 while (y0 <= y1) { 211 macro_plot_i(x0, p, fix_fint(i0)); 212 y0++; 213 p += grd_bm.row; 214 i0 += di; 215 } 216 } else { 217 dx = fix_div((x1 - x0), dy); 218 while (y0 <= y1) { 219 macro_plot_i(fix_fint(x0), p, fix_fint(i0)); 220 x0 += dx; 221 y0++; 222 p += grd_bm.row; 223 i0 += di; 224 } 225 } 226 } else { /* dy == dx, walk the x axis, all integers */ 227 228 x0 = fix_int(x0); 229 x1 = fix_int(x1); 230 y0 = fix_int(y0); 231 y1 = fix_int(y1); 232 233 if (x0 > x1) { 234 t = x0; 235 x0 = x1; 236 x1 = t; 237 t = y0; 238 y0 = y1; 239 y1 = t; 240 t = i0; 241 i0 = i1; 242 i1 = t; 243 } 244 245 p = grd_bm.bits + grd_bm.row * y0; /* set canvas ptr */ 246 di = fix_div((i1 - i0), dx); 247 248 if (y0 < y1) { 249 while (y0 <= y1) { 250 macro_plot_i(x0, p, fix_fint(i0)); 251 x0++; 252 y0++; 253 p += grd_bm.row; 254 i0 += di; 255 } 256 } else { 257 while (y0 >= y1) { 258 macro_plot_i(x0, p, fix_fint(i0)); 259 x0++; 260 y0--; 261 p -= grd_bm.row; 262 i0 += di; 263 } 264 } 265 } 266