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/fl8clin.h $ 21 * $Revision: 1.1 $ 22 * $Author: lmfeeney $ 23 * $Date: 1994/06/11 00:49:17 $ 24 */ 25 26 /* This file is an UNCOMPILABLE code fragment */ 27 28 /* Draw a gouraud-shaded line as specified by endpoint rgb value... 29 weird precision bugs abound due to precision errors 30 31 5/94 These have been (completely?) corrected. See test/clintest.c 32 33 See also note.txt for argument for correctness and precision safety 34 of current algorithm. 35 */ 36 37 /* NB: directionality policy -- reversible 38 Lines are drawn in order of increasing x or increasing y, 39 for lines that have greater x or y extent, repsectively. 40 This is done for all lines, including horiz., vert., and 41 45' lines (increasing x). 42 */ 43 44 /* NB: endpoint policy -- inclusive 45 46 The left and top endpoints are inclusive, i.e. 'trunc'-ed. The 47 right and bottom endpoints exclude the ceiling. This is 48 calculated by subtracting epsilon (i.e. 1/65536) from its 49 fixed-point representation, then trunc'ing. 50 51 This makes sense if you note that open interval on right 52 < ceil (x) 53 is the same as 54 <= trunc (x - e) 55 56 This means that it might not be necessary to go through the ugliness 57 of swapping endpoints, but I'm not convinced that there aren't 58 precision problems involved. Since wire-poly's overdraw, it's 59 really necessary to ensure that the same points are always drawn. 60 */ 61 62 fix x0, y0, x1, y1; 63 fix dx, dy; /* deltas in x and y */ 64 fix t; /* tmp */ 65 66 uchar r0, g0, b0, r1, g1, b1; /* rgb values of endpt colors */ 67 fix r, g, b; /* current intensities */ 68 fix dr, dg, db; /* deltas for each of rgb */ 69 long i; /* color index */ 70 71 uchar *p; /* ptr into canvas */ 72 73 x0 = v0->x; 74 y0 = v0->y; 75 x1 = v1->x; 76 y1 = v1->y; 77 78 r0 = (uchar)(v0->u); 79 g0 = (uchar)(v0->v); 80 b0 = (uchar)(v0->w); 81 r1 = (uchar)(v1->u); 82 g1 = (uchar)(v1->v); 83 b1 = (uchar)(v1->w); 84 85 /* set endpoints 86 note that this cannot go negative or change octant, since the == 87 case is excluded */ 88 89 if (x0 < x1) { 90 x1 -= 1; /* e.g. - epsilon */ 91 } else if (x0 > x1) { 92 x0 -= 1; 93 } 94 95 if (y0 < y1) { 96 y1 -= 1; 97 } else if (y0 > y1) { 98 y0 -= 1; 99 } 100 101 dx = fix_trunc(x1) - fix_trunc(x0); /* x extent in pixels, (macro is flakey) */ 102 dx = fix_abs(dx); 103 dy = fix_trunc(y1) - fix_trunc(y0); /* y extent in pixels */ 104 dy = fix_abs(dy); 105 106 if (dx == 0 && dy == 0) 107 return; 108 109 /* three cases: absolute value dx < = > dy 110 111 along the longer dimension, the fixpoint x0 (or y0) is treated 112 as an int 113 114 the points are swapped if needed and the rgb initial and deltas 115 are calculated accordingly 116 117 there are two or three sub-cases - a horizontal or vertical line, 118 and the dx or dy being added or subtracted. dx and dy 119 are kept as absolute values and +/- is managed in 120 two separate inner loops if it is a y change, since you need to 121 manage the canvas pointer 122 123 if y is being changed by 'dy' and x is being incremented, do a 124 FunkyBitCheck (TM) to see whether the integer part of y has changed 125 and if it has, resetting the the canvas pointer to the next row 126 127 if x is being changed by 'dx' and y is being incremented, just 128 add or subtract row to increment y in the canvas 129 130 the endpoints are walked inclusively in all cases, see above 131 132 45' degree lines are explicitly special cased -- because it 133 all runs as integers, but it's probably not frequent enough 134 to justify the check 135 136 */ 137 138 if (dx > dy) { 139 140 x0 = fix_int(x0); 141 x1 = fix_int(x1); 142 143 if (x0 < x1) { 144 r = fix_make(r0, 0); 145 g = fix_make(g0, 0); 146 b = fix_make(b0, 0); 147 dr = fix_div(fix_make_nof(r1 - r0), dx); 148 dg = fix_div(fix_make_nof(g1 - g0), dx); 149 db = fix_div(fix_make_nof(b1 - b0), dx); 150 151 p = grd_bm.bits + grd_bm.row * (fix_int(y0)); /* set canvas ptr */ 152 153 } else { 154 t = x0; 155 x0 = x1; 156 x1 = t; 157 t = y0; 158 y0 = y1; 159 y1 = t; 160 161 r = fix_make(r1, 0); 162 g = fix_make(g1, 0); 163 b = fix_make(b1, 0); 164 dr = fix_div(fix_make_nof(r0 - r1), dx); 165 dg = fix_div(fix_make_nof(g0 - g1), dx); 166 db = fix_div(fix_make_nof(b0 - b1), dx); 167 168 p = grd_bm.bits + grd_bm.row * (fix_int(y0)); 169 } 170 171 if ((fix_int(y0)) == (fix_int(y1))) { 172 while (x0 <= x1) { 173 i = macro_get_ipal(r, g, b); 174 macro_plot_rgb(x0, p, i); 175 x0++; 176 r += dr; 177 g += dg; 178 b += db; 179 } 180 } else if (y0 < y1) { 181 dy = fix_div((y1 - y0), dx); 182 while (x0 <= x1) { 183 i = macro_get_ipal(r, g, b); 184 macro_plot_rgb(x0, p, i); 185 x0++; 186 y0 += dy; 187 p += (grd_bm.row & (-(fix_frac(y0) < dy))); 188 r += dr; 189 g += dg; 190 b += db; 191 } 192 } else { 193 dy = fix_div((y0 - y1), dx); 194 while (x0 <= x1) { 195 i = macro_get_ipal(r, g, b); 196 macro_plot_rgb(x0, p, i); 197 x0++; 198 p -= (grd_bm.row & (-(fix_frac(y0) < dy))); 199 y0 -= dy; 200 r += dr; 201 g += dg; 202 b += db; 203 } 204 } 205 } 206 207 else if (dy > dx) { 208 209 y0 = fix_int(y0); 210 y1 = fix_int(y1); 211 212 if (y0 < y1) { 213 r = fix_make(r0, 0); 214 g = fix_make(g0, 0); 215 b = fix_make(b0, 0); 216 dr = fix_div(fix_make_nof(r1 - r0), dy); 217 dg = fix_div(fix_make_nof(g1 - g0), dy); 218 db = fix_div(fix_make_nof(b1 - b0), dy); 219 220 p = grd_bm.bits + grd_bm.row * y0; 221 222 } else { 223 t = x0; 224 x0 = x1; 225 x1 = t; 226 t = y0; 227 y0 = y1; 228 y1 = t; 229 230 r = fix_make(r1, 0); 231 g = fix_make(g1, 0); 232 b = fix_make(b1, 0); 233 dr = fix_div(fix_make_nof(r0 - r1), dy); 234 dg = fix_div(fix_make_nof(g0 - g1), dy); 235 db = fix_div(fix_make_nof(b0 - b1), dy); 236 237 p = grd_bm.bits + grd_bm.row * y0; 238 } 239 240 if ((fix_int(x0)) == (fix_int(x1))) { 241 x0 = fix_int(x0); 242 while (y0 <= y1) { 243 i = macro_get_ipal(r, g, b); 244 macro_plot_rgb(x0, p, i); 245 y0++; 246 p += grd_bm.row; 247 r += dr; 248 g += dg; 249 b += db; 250 } 251 } else { 252 dx = fix_div((x1 - x0), dy); 253 while (y0 <= y1) { 254 i = macro_get_ipal(r, g, b); 255 macro_plot_rgb(fix_fint(x0), p, i); 256 x0 += dx; 257 y0++; 258 p += grd_bm.row; 259 r += dr; 260 g += dg; 261 b += db; 262 } 263 } 264 } else { /* dy == dx, walk the x axis, all integers */ 265 266 x0 = fix_int(x0); 267 x1 = fix_int(x1); 268 y0 = fix_int(y0); 269 y1 = fix_int(y1); 270 271 if (x0 < x1) { 272 r = fix_make(r0, 0); 273 g = fix_make(g0, 0); 274 b = fix_make(b0, 0); 275 dr = fix_div(fix_make_nof(r1 - r0), dx); 276 dg = fix_div(fix_make_nof(g1 - g0), dx); 277 db = fix_div(fix_make_nof(b1 - b0), dx); 278 279 p = grd_bm.bits + grd_bm.row * y0; /* set canvas ptr */ 280 281 } else { 282 t = x0; 283 x0 = x1; 284 x1 = t; 285 t = y0; 286 y0 = y1; 287 y1 = t; 288 289 r = fix_make(r1, 0); 290 g = fix_make(g1, 0); 291 b = fix_make(b1, 0); 292 dr = fix_div(fix_make_nof(r0 - r1), dx); 293 dg = fix_div(fix_make_nof(g0 - g1), dx); 294 db = fix_div(fix_make_nof(b0 - b1), dx); 295 296 p = grd_bm.bits + grd_bm.row * y0; 297 } 298 299 if (y0 < y1) { 300 while (y0 <= y1) { 301 i = macro_get_ipal(r, g, b); 302 macro_plot_rgb(x0, p, i); 303 x0++; 304 y0++; 305 p += grd_bm.row; 306 r += dr; 307 g += dg; 308 b += db; 309 } 310 } else { 311 while (y0 >= y1) { 312 i = macro_get_ipal(r, g, b); 313 macro_plot_rgb(x0, p, i); 314 x0++; 315 y0--; 316 p -= grd_bm.row; 317 r += dr; 318 g += dg; 319 b += db; 320 } 321 } 322 } 323