1 /*
2  * PROJECT:         ReactOS VGA display driver
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            win32ss/drivers/displays/vga/objects/lineto.c
5  * PURPOSE:
6  * PROGRAMMERS:     Copyright (C) 1998-2003 ReactOS Team
7  */
8 
9 #include <vgaddi.h>
10 
11 /*
12  * Draw a line from top-left to bottom-right
13  */
14 static void FASTCALL
15 vgaNWtoSE(
16     IN CLIPOBJ* Clip,
17     IN BRUSHOBJ* Brush,
18     IN LONG x,
19     IN LONG y,
20     IN LONG deltax,
21     IN LONG deltay)
22 {
23     int i;
24     int error;
25     BOOLEAN EnumMore;
26     PRECTL ClipRect;
27     RECT_ENUM RectEnum;
28     ULONG Pixel = Brush->iSolidColor;
29     LONG delta;
30 
31     CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
32     EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
33     ClipRect = RectEnum.arcl;
34     delta = max(deltax, deltay);
35     i = 0;
36     error = delta / 2;
37     while (i < delta && (ClipRect < RectEnum.arcl + RectEnum.c || EnumMore))
38     {
39         while ((ClipRect < RectEnum.arcl + RectEnum.c /* there's still a current clip rect */
40                 && (ClipRect->bottom <= y             /* but it's above us */
41                     || (ClipRect->top <= y && ClipRect->right <= x))) /* or to the left of us */
42                || EnumMore)                           /* no current clip rect, but rects left */
43         {
44             /* Skip to the next clip rect */
45             if (RectEnum.arcl + RectEnum.c <= ClipRect)
46             {
47                 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
48                 ClipRect = RectEnum.arcl;
49             }
50             else
51             {
52                 ClipRect++;
53             }
54         }
55         if ( ClipRect < RectEnum.arcl + RectEnum.c ) /* If there's no current clip rect we're done */
56         {
57             if (ClipRect->left <= x && ClipRect->top <= y)
58                 vgaPutPixel ( x, y, Pixel );
59             if ( deltax < deltay )
60             {
61                 y++;
62                 error += deltax;
63                 if ( error >= deltay )
64                 {
65                     x++;
66                     error -= deltay;
67                 }
68             }
69             else
70             {
71                 x++;
72                 error += deltay;
73                 if ( error >= deltax )
74                 {
75                     y++;
76                     error -= deltax;
77                 }
78             }
79             i++;
80         }
81     }
82 }
83 
84 static void FASTCALL
85 vgaSWtoNE(
86     IN CLIPOBJ* Clip,
87     IN BRUSHOBJ* Brush,
88     IN LONG x,
89     IN LONG y,
90     IN LONG deltax,
91     IN LONG deltay)
92 {
93     int i;
94     int error;
95     BOOLEAN EnumMore;
96     PRECTL ClipRect;
97     RECT_ENUM RectEnum;
98     ULONG Pixel = Brush->iSolidColor;
99     LONG delta;
100 
101     CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_RIGHTUP, 0);
102     EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
103     ClipRect = RectEnum.arcl;
104     delta = max(deltax, deltay);
105     i = 0;
106     error = delta / 2;
107     while (i < delta && (ClipRect < RectEnum.arcl + RectEnum.c || EnumMore))
108     {
109         while ((ClipRect < RectEnum.arcl + RectEnum.c
110                 && (y < ClipRect->top
111                     || (y < ClipRect->bottom && ClipRect->right <= x)))
112                || EnumMore)
113         {
114             if (RectEnum.arcl + RectEnum.c <= ClipRect)
115             {
116                 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
117                 ClipRect = RectEnum.arcl;
118             }
119             else
120             {
121                 ClipRect++;
122             }
123         }
124         if (ClipRect < RectEnum.arcl + RectEnum.c)
125         {
126             if (ClipRect->left <= x && y < ClipRect->bottom)
127                 vgaPutPixel(x, y, Pixel);
128             if (deltax < deltay)
129             {
130                 y--;
131                 error = error + deltax;
132                 if (deltay <= error)
133                 {
134                     x++;
135                     error = error - deltay;
136                 }
137             }
138             else
139             {
140                 x++;
141                 error = error + deltay;
142                 if (deltax <= error)
143                 {
144                     y--;
145                     error = error - deltax;
146                 }
147             }
148             i++;
149         }
150     }
151 }
152 
153 static void FASTCALL
154 vgaNEtoSW(
155     IN CLIPOBJ* Clip,
156     IN BRUSHOBJ* Brush,
157     IN LONG x,
158     IN LONG y,
159     IN LONG deltax,
160     IN LONG deltay)
161 {
162     int i;
163     int error;
164     BOOLEAN EnumMore;
165     PRECTL ClipRect;
166     RECT_ENUM RectEnum;
167     ULONG Pixel = Brush->iSolidColor;
168     LONG delta;
169 
170     CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_LEFTDOWN, 0);
171     EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
172     ClipRect = RectEnum.arcl;
173     delta = max(deltax, deltay);
174     i = 0;
175     error = delta / 2;
176     while (i < delta && (ClipRect < RectEnum.arcl + RectEnum.c || EnumMore))
177     {
178         while ((ClipRect < RectEnum.arcl + RectEnum.c
179                 && (ClipRect->bottom <= y
180                     || (ClipRect->top <= y && x < ClipRect->left)))
181                || EnumMore)
182         {
183             if (RectEnum.arcl + RectEnum.c <= ClipRect)
184             {
185                 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
186                 ClipRect = RectEnum.arcl;
187             }
188             else
189             {
190                 ClipRect++;
191             }
192         }
193         if (ClipRect < RectEnum.arcl + RectEnum.c)
194         {
195             if (x < ClipRect->right && ClipRect->top <= y)
196                 vgaPutPixel(x, y, Pixel);
197             if (deltax < deltay)
198             {
199                 y++;
200                 error = error + deltax;
201                 if (deltay <= error)
202                 {
203                     x--;
204                     error = error - deltay;
205                 }
206             }
207             else
208             {
209                 x--;
210                 error = error + deltay;
211                 if (deltax <= error)
212                 {
213                     y++;
214                     error = error - deltax;
215                 }
216             }
217             i++;
218         }
219     }
220 }
221 
222 static void FASTCALL
223 vgaSEtoNW(
224     IN CLIPOBJ* Clip,
225     IN BRUSHOBJ* Brush,
226     IN LONG x,
227     IN LONG y,
228     IN LONG deltax,
229     IN LONG deltay)
230 {
231     int i;
232     int error;
233     BOOLEAN EnumMore;
234     PRECTL ClipRect;
235     RECT_ENUM RectEnum;
236     ULONG Pixel = Brush->iSolidColor;
237     LONG delta;
238 
239     CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_LEFTUP, 0);
240     EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
241     ClipRect = RectEnum.arcl;
242     delta = max(deltax, deltay);
243     i = 0;
244     error = delta / 2;
245     while (i < delta && (ClipRect < RectEnum.arcl + RectEnum.c || EnumMore))
246     {
247         while ((ClipRect < RectEnum.arcl + RectEnum.c
248                 && (y < ClipRect->top
249                     || (y < ClipRect->bottom && x < ClipRect->left)))
250                || EnumMore)
251         {
252             if (RectEnum.arcl + RectEnum.c <= ClipRect)
253             {
254                 EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
255                 ClipRect = RectEnum.arcl;
256             }
257             else
258             {
259                 ClipRect++;
260             }
261         }
262         if (ClipRect < RectEnum.arcl + RectEnum.c)
263         {
264             if (x < ClipRect->right && y < ClipRect->bottom)
265                 vgaPutPixel(x, y, Pixel);
266             if (deltax < deltay)
267             {
268                 y--;
269                 error = error + deltax;
270                 if (deltay <= error)
271                 {
272                     x--;
273                     error = error - deltay;
274                 }
275             }
276             else
277             {
278                 x--;
279                 error = error + deltay;
280                 if (deltax <= error)
281                 {
282                     y--;
283                     error = error - deltax;
284                 }
285             }
286             i++;
287         }
288     }
289 }
290 
291 /*
292  * FIXME: Use Mix to perform ROPs
293  * FIXME: Non-solid Brush
294  */
295 BOOL APIENTRY
296 DrvLineTo(
297     IN SURFOBJ *DestObj,
298     IN CLIPOBJ *Clip,
299     IN BRUSHOBJ *Brush,
300     IN LONG x1,
301     IN LONG y1,
302     IN LONG x2,
303     IN LONG y2,
304     IN RECTL *RectBounds,
305     IN MIX mix)
306 {
307     LONG x, y, deltax, deltay, xchange, ychange, hx, vy;
308     ULONG i;
309     ULONG Pixel = Brush->iSolidColor;
310     RECT_ENUM RectEnum;
311     BOOL EnumMore;
312 
313     x = x1;
314     y = y1;
315     deltax = x2 - x1;
316     deltay = y2 - y1;
317 
318     if (deltax < 0)
319     {
320         xchange = -1;
321         deltax = - deltax;
322         hx = x2+1;
323         //x--;
324     }
325     else
326     {
327         xchange = 1;
328         hx = x1;
329     }
330 
331     if (deltay < 0)
332     {
333         ychange = -1;
334         deltay = - deltay;
335         vy = y2+1;
336         //y--;
337     }
338     else
339     {
340         ychange = 1;
341         vy = y1;
342     }
343 
344     if (y1 == y2)
345     {
346         CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
347         do
348         {
349             EnumMore = CLIPOBJ_bEnum(Clip, sizeof(RectEnum), (PVOID) &RectEnum);
350             for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top <= y1; i++)
351             {
352                 if (y1 < RectEnum.arcl[i].bottom &&
353                     RectEnum.arcl[i].left <= hx + deltax &&
354                     hx < RectEnum.arcl[i].right)
355                 {
356                     vgaHLine(max(hx, RectEnum.arcl[i].left), y1,
357                              min(hx + deltax, RectEnum.arcl[i].right)
358                              -max(hx, RectEnum.arcl[i].left), Pixel);
359                 }
360             }
361         } while (EnumMore);
362     }
363     else if (x1 == x2)
364     {
365         CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
366         do
367         {
368             EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
369             for (i = 0; i < RectEnum.c; i++)
370             {
371                 if (RectEnum.arcl[i].left <= x1 &&
372                     x1 < RectEnum.arcl[i].right &&
373                     RectEnum.arcl[i].top <= vy + deltay &&
374                     vy < RectEnum.arcl[i].bottom)
375                 {
376                     vgaVLine(x1,
377                         max(vy, RectEnum.arcl[i].top),
378                         min(vy + deltay, RectEnum.arcl[i].bottom)
379                         - max(vy, RectEnum.arcl[i].top),
380                         Pixel);
381                 }
382             }
383         } while (EnumMore);
384     }
385     else
386     {
387         if (0 < xchange)
388         {
389             if (0 < ychange)
390                 vgaNWtoSE(Clip, Brush, x, y, deltax, deltay);
391             else
392                 vgaSWtoNE(Clip, Brush, x, y, deltax, deltay);
393         }
394         else
395         {
396             if (0 < ychange)
397                 vgaNEtoSW(Clip, Brush, x, y, deltax, deltay);
398             else
399                 vgaSEtoNW(Clip, Brush, x, y, deltax, deltay);
400         }
401     }
402 
403     return TRUE;
404 }
405 
406 /* EOF */
407