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