1 /*
2  * Portions of this file are copyright Rebirth contributors and licensed as
3  * described in COPYING.txt.
4  * Portions of this file are copyright Parallax Software and licensed
5  * according to the Parallax license below.
6  * See COPYING.txt for license details.
7 
8 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
9 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
10 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
11 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
12 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
13 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
14 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
15 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
16 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
17 COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
18 */
19 
20 /*
21  *
22  * Graphical routines for drawing lines.
23  *
24  */
25 
26 #include <stdlib.h>
27 #include "u_mem.h"
28 #include "gr.h"
29 #include "grdef.h"
30 #include "maths.h"
31 #include "clip.h"
32 #if DXX_USE_OGL
33 #include "ogl_init.h"
34 #endif
35 
36 namespace dcx {
37 
38 namespace {
39 
40 /*
41 Symmetric Double Step Line Algorithm
42 by Brian Wyvill
43 from "Graphics Gems", Academic Press, 1990
44 */
45 
46 /* non-zero flag indicates the pixels needing EXCHG back. */
plot(grs_canvas & canvas,int x,int y,int flag,const color_palette_index color)47 static void plot(grs_canvas &canvas, int x, int y, int flag, const color_palette_index color)
48 #define plot(x,y,f)	plot(canvas,x,y,f,color)
49 {
50 	if (flag)
51 		std::swap(x, y);
52 	gr_upixel(canvas.cv_bitmap, x, y, color);
53 }
54 
gr_hline(grs_canvas & canvas,int x1,int x2,const int y,const color_palette_index color)55 static void gr_hline(grs_canvas &canvas, int x1, int x2, const int y, const color_palette_index color)
56 {
57 	using std::swap;
58 	if (x1 > x2)
59 		swap(x1,x2);
60 	for (int i=x1; i<=x2; i++ )
61 		gr_upixel(canvas.cv_bitmap, i, y, color);
62 }
63 
gr_vline(grs_canvas & canvas,int y1,int y2,const int x,const color_palette_index color)64 static void gr_vline(grs_canvas &canvas, int y1, int y2, const int x, const color_palette_index color)
65 {
66 	using std::swap;
67 	if (y1 > y2) swap(y1,y2);
68 	for (int i=y1; i<=y2; i++ )
69 		gr_upixel(canvas.cv_bitmap, x, i, color);
70 }
71 
gr_universal_uline(grs_canvas & canvas,int a1,int b1,int a2,int b2,const color_palette_index color)72 static void gr_universal_uline(grs_canvas &canvas, int a1, int b1, int a2, int b2, const color_palette_index color)
73 {
74 	int dx, dy, incr1, incr2, D, x, y, xend, c, pixels_left;
75 	int x1, y1;
76 	int sign_x = 1, sign_y = 1, step, reverse;
77 
78 	if (a1==a2) {
79 		gr_vline(canvas, b1, b2, a1, color);
80 		return;
81 	}
82 
83 	if (b1==b2) {
84 		gr_hline(canvas, a1, a2, b1, color);
85 		return;
86 	}
87 
88 	dx = a2 - a1;
89 	dy = b2 - b1;
90 
91 	if (dx < 0) {
92 		sign_x = -1;
93 		dx *= -1;
94 	}
95 	if (dy < 0) {
96 		sign_y = -1;
97 		dy *= -1;
98 	}
99 
100 	/* decide increment sign by the slope sign */
101 	if (sign_x == sign_y)
102 		step = 1;
103 	else
104 		step = -1;
105 
106 	if (dy > dx) {          /* chooses axis of greatest movement (make * dx) */
107 		using std::swap;
108 		swap(a1, b1);
109 		swap(a2, b2);
110 		swap(dx, dy);
111 		reverse = 1;
112 	} else
113 		reverse = 0;
114 	/* note error check for dx==0 should be included here */
115 	if (a1 > a2) {          /* start from the smaller coordinate */
116 		x = a2;
117 		y = b2;
118 		x1 = a1;
119 		y1 = b1;
120 	} else {
121 		x = a1;
122 		y = b1;
123 		x1 = a2;
124 		y1 = b2;
125 	}
126 
127 
128 	/* Note dx=n implies 0 - n or (dx+1) pixels to be set */
129 	/* Go round loop dx/4 times then plot last 0,1,2 or 3 pixels */
130 	/* In fact (dx-1)/4 as 2 pixels are already plottted */
131 	xend = (dx - 1) / 4;
132 	pixels_left = (dx - 1) % 4;     /* number of pixels left over at the
133 	                                 * end */
134 	plot(x, y, reverse);
135 	plot(x1, y1, reverse);  /* plot first two points */
136 	incr2 = 4 * dy - 2 * dx;
137 	if (incr2 < 0) {        /* slope less than 1/2 */
138 		c = 2 * dy;
139 		incr1 = 2 * c;
140 		D = incr1 - dx;
141 
142 		for (uint_fast32_t i = xend; i--;)
143 		{    /* plotting loop */
144 			++x;
145 			--x1;
146 			if (D < 0) {
147 					/* pattern 1 forwards */
148 				plot(x, y, reverse);
149 				plot(++x, y, reverse);
150 				/* pattern 1 backwards */
151 				plot(x1, y1, reverse);
152 				plot(--x1, y1, reverse);
153 				D += incr1;
154 			} else {
155 				if (D < c) {
156 					/* pattern 2 forwards */
157 					plot(x, y, reverse);
158 					plot(++x, y += step, reverse);
159 					/* pattern 2 backwards */
160 					plot(x1, y1, reverse);
161 					plot(--x1, y1 -= step, reverse);
162 				} else {
163 					/* pattern 3 forwards */
164 					plot(x, y += step, reverse);
165 					plot(++x, y, reverse);
166 					/* pattern 3 backwards */
167 					plot(x1, y1 -= step, reverse);
168 					plot(--x1, y1, reverse);
169 				}
170 				D += incr2;
171 			}
172 		}               /* end for */
173 
174 		/* plot last pattern */
175 		if (pixels_left) {
176 			if (D < 0) {
177 				plot(++x, y, reverse);  /* pattern 1 */
178 				if (pixels_left > 1)
179 					plot(++x, y, reverse);
180 				if (pixels_left > 2)
181 					plot(--x1, y1, reverse);
182 			} else {
183 				if (D < c) {
184 					plot(++x, y, reverse);  /* pattern 2  */
185 					if (pixels_left > 1)
186 						plot(++x, y += step, reverse);
187 					if (pixels_left > 2)
188 						plot(--x1, y1, reverse);
189 				} else {
190 				  /* pattern 3 */
191 					plot(++x, y += step, reverse);
192 					if (pixels_left > 1)
193 						plot(++x, y, reverse);
194 					if (pixels_left > 2)
195 						plot(--x1, y1 -= step, reverse);
196 				}
197 			}
198 		}               /* end if pixels_left */
199 	}
200 	/* end slope < 1/2 */
201 	else {                  /* slope greater than 1/2 */
202 		c = 2 * (dy - dx);
203 		incr1 = 2 * c;
204 		D = incr1 + dx;
205 		for (uint_fast32_t i = xend; i--;)
206 		{
207 			++x;
208 			--x1;
209 			if (D > 0) {
210 			  /* pattern 4 forwards */
211 				plot(x, y += step, reverse);
212 				plot(++x, y += step, reverse);
213 			  /* pattern 4 backwards */
214 				plot(x1, y1 -= step, reverse);
215 				plot(--x1, y1 -= step, reverse);
216 				D += incr1;
217 			} else {
218 				if (D < c) {
219 				  /* pattern 2 forwards */
220 					plot(x, y, reverse);
221 					plot(++x, y += step, reverse);
222 
223 				  /* pattern 2 backwards */
224 					plot(x1, y1, reverse);
225 					plot(--x1, y1 -= step, reverse);
226 				} else {
227 				  /* pattern 3 forwards */
228 					plot(x, y += step, reverse);
229 					plot(++x, y, reverse);
230 				  /* pattern 3 backwards */
231 					plot(x1, y1 -= step, reverse);
232 					plot(--x1, y1, reverse);
233 				}
234 				D += incr2;
235 			}
236 		}               /* end for */
237 		/* plot last pattern */
238 		if (pixels_left) {
239 			if (D > 0) {
240 				plot(++x, y += step, reverse);  /* pattern 4 */
241 				if (pixels_left > 1)
242 					plot(++x, y += step, reverse);
243 				if (pixels_left > 2)
244 					plot(--x1, y1 -= step, reverse);
245 			} else {
246 				if (D < c) {
247 					plot(++x, y, reverse);  /* pattern 2  */
248 					if (pixels_left > 1)
249 						plot(++x, y += step, reverse);
250 					if (pixels_left > 2)
251 						plot(--x1, y1, reverse);
252 				} else {
253 				  /* pattern 3 */
254 					plot(++x, y += step, reverse);
255 					if (pixels_left > 1)
256 						plot(++x, y, reverse);
257 					if (pixels_left > 2) {
258 						if (D > c) /* step 3 */
259 						   plot(--x1, y1 -= step, reverse);
260 						else /* step 2 */
261 							plot(--x1, y1, reverse);
262 					}
263 				}
264 			}
265 		}
266 	}
267 }
268 
269 }
270 
271 //unclipped version just calls clipping version for now
gr_uline(grs_canvas & canvas,const fix _a1,const fix _b1,const fix _a2,const fix _b2,const color_palette_index color)272 void gr_uline(grs_canvas &canvas, const fix _a1, const fix _b1, const fix _a2, const fix _b2, const color_palette_index color)
273 {
274 	int a1,b1,a2,b2;
275 	a1 = f2i(_a1); b1 = f2i(_b1); a2 = f2i(_a2); b2 = f2i(_b2);
276 	switch(canvas.cv_bitmap.get_type())
277 	{
278 		case bm_mode::ilbm:
279 		case bm_mode::rgb15:
280 			break;
281 #if DXX_USE_OGL
282 	case bm_mode::ogl:
283 		ogl_ulinec(canvas, a1, b1, a2, b2, color);
284 		return;
285 #endif
286 	case bm_mode::linear:
287 		gr_universal_uline(canvas, a1, b1, a2, b2, color);
288 		return;
289 	}
290 	return;
291 }
292 
293 // Returns 0 if drawn with no clipping, 1 if drawn but clipped, and
294 // 2 if not drawn at all.
295 
gr_line(grs_canvas & canvas,fix a1,fix b1,fix a2,fix b2,const color_palette_index color)296 void gr_line(grs_canvas &canvas, fix a1, fix b1, fix a2, fix b2, const color_palette_index color)
297 {
298 	int x1, y1, x2, y2;
299 	x1 = i2f(MINX);
300 	y1 = i2f(MINY);
301 	x2 = i2f(canvas.cv_bitmap.bm_w - 1);
302 	y2 = i2f(canvas.cv_bitmap.bm_h - 1);
303 
304 	CLIPLINE(a1,b1,a2,b2,x1,y1,x2,y2,return,, FIXSCALE );
305 	gr_uline(canvas, a1, b1, a2, b2, color);
306 }
307 
308 }
309