4 This package includes software which is copyright (c) L. Patrick.
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution.
16 3. You may not sell this software package.
17 4. You may include this software in a distribution of other software,
18 and you may charge a nominal fee for the media used.
19 5. You may sell derivative programs, providing that such programs
20 simply use this software in a compiled form.
21 6. You may sell derivative programs which use a compiled, modified
22 version of this software, provided that you have attempted as
23 best as you can to propagate all modifications made to the source
24 code files of this software package back to the original author(s)
27 THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS AS IS, AND
28 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
31 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 /* Copyright (c) L. Patrick
41 This file is part of the App cross-platform programming package.
42 You may redistribute it and/or modify it under the terms of the
43 App Software License. See the file LICENSE.TXT for details.
45 http://enchantia.com/software/graphapp/
46 http://www.it.usyd.edu.au/~graphapp/
58 #define DEGREES_TO_RADIANS(deg) ((deg)*2*M_PI/360)
62 int x
, y
; /* top-left point inside rect */
63 int width
, height
; /* width and height of rect */
66 int FASTCALL
IntFillRect(DC
*dc
, INT XLeft
, INT YLeft
, INT Width
, INT Height
, PGDIBRUSHOBJ BrushObj
, BOOL Pen
);
67 int FASTCALL
app_fill_rect(DC
*dc
, Rect r
, PGDIBRUSHOBJ BrushObj
, BOOL Pen
);
72 app_new_point(int x
, int y
)
79 #define pt(x,y) app_new_point((x),(y))
84 rect(int x
, int y
, int width
, int height
)
96 * app_window_fill_rect:
98 * Fill a rectangle with colour, in a window.
100 * This function implements client-side clipping, so that
101 * we never rely on the GDI system to do clipping, except if
102 * the destination is a window which is partially obscured.
103 * In that situation we must rely on the GDI system because there
104 * is no way for the program to know which portions of the
105 * window are currently obscured.
107 #define app_fill_rect( dc, r, BrushObj, Pen) \
108 IntFillRect(dc, r.x, r.y, r.width, r.height, BrushObj, Pen)
111 * Drawing an ellipse with a certain line thickness.
112 * Use an inner and and outer ellipse and fill the spaces between.
113 * The inner ellipse uses all UPPERCASE letters, the outer lowercase.
115 * This algorithm is based on the fill_ellipse algorithm presented
116 * above, but uses two ellipse calculations, and some fix-up code
117 * to avoid pathological cases where the inner ellipse is almost
118 * the same size as the outer (in which case the border of the
119 * elliptical curve might otherwise have appeared broken).
124 app_draw_ellipse(DC
*g
, Rect r
, PGDIBRUSHOBJ BrushObj
)
126 /* Outer ellipse: e(x,y) = b*b*x*x + a*a*y*y - a*a*b*b */
129 int b
= r
.height
/ 2;
134 long xcrit
= (3 * a2
/ 4) + 1;
135 long ycrit
= (3 * b2
/ 4) + 1;
136 long t
= b2
+ a2
- 2*a2
*b
; /* t = e(x+1,y-1) */
137 long dxt
= b2
*(3+x
+x
);
138 long dyt
= a2
*(3-y
-y
);
142 int w
= BrushObj
->ptPenWidth
.x
;
144 /* Inner ellipse: E(X,Y) = B*B*X*X + A*A*Y*Y - A*A*B*B */
146 int A
= a
-w
> 0 ? a
-w
: 0;
147 int B
= b
-w
> 0 ? b
-w
: 0;
152 long XCRIT
= (3 * A2
/ 4) + 1;
153 long YCRIT
= (3 * B2
/ 4) + 1;
154 long T
= B2
+ A2
- 2*A2
*B
; /* T = E(X+1,Y-1) */
155 long DXT
= B2
*(3+X
+X
);
156 long DYT
= A2
*(3-Y
-Y
);
160 int movedown
, moveout
;
161 int innerX
= 0, prevx
, prevy
, W
;
167 if ((r
.width
<= 2) || (r
.height
<= 2))
168 return app_fill_rect(g
, r
, BrushObj
, TRUE
);
172 r1
.width
= r
.width
& 1; /* i.e. if width is odd */
176 r2
.y
= r
.y
+ r
.height
- 1;
187 if (T
+ A2
*Y
< XCRIT
) /* E(X+1,Y-1/2) <= 0 */
189 /* move outwards to encounter edge */
194 else if (T
- B2
*X
>= YCRIT
) /* e(x+1/2,y-1) > 0 */
196 /* drop down one line */
202 /* drop diagonally down and out */
211 movedown
= moveout
= 0;
214 if (r1
.x
+ W
< prevx
)
219 if (t
+ a2
*y
< xcrit
) /* e(x+1,y-1/2) <= 0 */
221 /* move outwards to encounter edge */
228 else if (t
- b2
*x
>= ycrit
) /* e(x+1/2,y-1) > 0 */
230 /* drop down one line */
238 /* drop diagonally down and out */
251 r1
.x
-= 1; r1
.width
+= 2;
252 r2
.x
-= 1; r2
.width
+= 2;
258 if (r1
.width
> r
.width
)
259 r1
.width
= r2
.width
= r
.width
;
260 if (r1
.y
== r2
.y
-1) {
262 r1
.width
= r2
.width
= r
.width
;
265 if ((r1
.y
< r
.y
+w
) || (r1
.x
+W
>= r1
.x
+r1
.width
-W
))
267 result
&= app_fill_rect(g
, r1
, BrushObj
, TRUE
);
268 result
&= app_fill_rect(g
, r2
, BrushObj
, TRUE
);
273 else if (r1
.y
+r1
.height
< r2
.y
)
275 /* draw distinct rectangles */
276 result
&= app_fill_rect(g
, rect(r1
.x
,r1
.y
,
277 W
,1), BrushObj
, TRUE
);
278 result
&= app_fill_rect(g
, rect(
279 r1
.x
+r1
.width
-W
,r1
.y
,W
,1), BrushObj
, TRUE
);
280 result
&= app_fill_rect(g
, rect(r2
.x
,
281 r2
.y
,W
,1), BrushObj
, TRUE
);
282 result
&= app_fill_rect(g
, rect(
283 r2
.x
+r2
.width
-W
,r2
.y
,W
,1), BrushObj
, TRUE
);
296 r1
.x
-= 1; r1
.width
+= 2;
297 r2
.x
-= 1; r2
.width
+= 2;
300 if ((x
<= a
) && (prevy
< r2
.y
)) {
301 /* draw final line */
302 r1
.height
= r1
.y
+r1
.height
-r2
.y
;
306 if (r
.x
+ W
!= prevx
)
311 if (W
+W
>= r
.width
) {
312 result
&= app_fill_rect(g
, rect(r
.x
, r1
.y
,
313 r
.width
, r1
.height
), BrushObj
, TRUE
);
317 result
&= app_fill_rect(g
, rect(r
.x
, r1
.y
, W
, r1
.height
), BrushObj
, TRUE
);
318 result
&= app_fill_rect(g
, rect(r
.x
+r
.width
-W
, r1
.y
,
319 W
, r1
.height
), BrushObj
, TRUE
);
325 * Draw an arc of an ellipse from start_angle anti-clockwise to
326 * end_angle. If the angles coincide, draw nothing; if they
327 * differ by 360 degrees or more, draw a full ellipse.
328 * The shape is drawn with the current line thickness,
329 * completely within the bounding rectangle. The shape is also
330 * axis-aligned, so that the ellipse would be horizontally and
331 * vertically symmetric is it was complete.
333 * The draw_arc algorithm is based on draw_ellipse, but unlike
334 * that algorithm is not symmetric in the general case, since
335 * an angular portion is clipped from the shape.
336 * This clipping is performed by keeping track of two hypothetical
337 * lines joining the centre point to the enclosing rectangle,
338 * at the angles start_angle and end_angle, using a line-intersection
339 * algorithm. Essentially the algorithm just fills the spaces
340 * which are within the arc and also between the angles, going
341 * in an anti-clockwise direction from start_angle to end_angle.
342 * In the top half of the ellipse, this amounts to drawing
343 * to the left of the start_angle line and to the right of
344 * the end_angle line, while in the bottom half of the ellipse,
345 * it involves drawing to the right of the start_angle and to
346 * the left of the end_angle.
350 * Fill a rectangle within an arc, given the centre point p0,
351 * and the two end points of the lines corresponding to the
352 * start_angle and the end_angle. This function takes care of
353 * the logic needed to swap the fill direction below
354 * the central point, and also performs the calculations
355 * needed to intersect the current Y value with each line.
360 app_fill_arc_rect(DC
*g
,
361 Rect r
, // top, left, width, height
367 PGDIBRUSHOBJ BrushObj
,
371 int start_above
, end_above
;
372 long rise1
, run1
, rise2
, run2
;
381 /* in top half of arc ellipse */
385 /* start_line is in the top half and is */
386 /* intersected by the current Y scan line */
390 x1
= p0
.x
+ (r
.y
-p0
.y
)*run1
/rise1
;
393 else if ((start_angle
>= 0) && (start_angle
<= 180))
395 /* start_line is above middle */
401 /* start_line is below middle */
407 if (x1
> r
.x
+r
.width
)
412 /* end_line is in the top half and is */
413 /* intersected by the current Y scan line */
417 x2
= p0
.x
+ (r
.y
-p0
.y
)*run2
/rise2
;
420 else if ((end_angle
>= 0) && (end_angle
<= 180))
422 /* end_line is above middle */
428 /* end_line is below middle */
433 if (x2
< r
.x
) x2
= r
.x
;
435 if (x2
> r
.x
+r
.width
) x2
= r
.x
+r
.width
;
437 if (start_above
&& end_above
)
439 if (start_angle
> end_angle
)
441 /* fill outsides of wedge */
442 if (! app_fill_rect(g
, rect(r
.x
, r
.y
,
443 x1
-r
.x
, r
.height
), BrushObj
, Pen
))
445 return app_fill_rect(g
, rect(x2
, r
.y
,
446 r
.x
+r
.width
-x2
, r
.height
), BrushObj
, Pen
);
450 /* fill inside of wedge */
453 return app_fill_rect(g
, r
, BrushObj
, Pen
);
456 else if (start_above
)
458 /* fill to the left of the start_line */
460 return app_fill_rect(g
, r
, BrushObj
, Pen
);
464 /* fill right of end_line */
465 r
.width
= r
.x
+r
.width
-x2
;
467 return app_fill_rect(g
, r
, BrushObj
, Pen
);
471 if (start_angle
> end_angle
)
472 return app_fill_rect(g
,r
, BrushObj
, Pen
);
479 /* in lower half of arc ellipse */
483 /* start_line is in the lower half and is */
484 /* intersected by the current Y scan line */
488 x1
= p0
.x
+ (r
.y
-p0
.y
)*run1
/rise1
;
491 else if ((start_angle
>= 180) && (start_angle
<= 360))
493 /* start_line is below middle */
499 /* start_line is above middle */
505 if (x1
> r
.x
+r
.width
)
510 /* end_line is in the lower half and is */
511 /* intersected by the current Y scan line */
515 x2
= p0
.x
+ (r
.y
-p0
.y
)*run2
/rise2
;
518 else if ((end_angle
>= 180) && (end_angle
<= 360))
520 /* end_line is below middle */
526 /* end_line is above middle */
532 if (x2
> r
.x
+r
.width
)
535 if (start_above
&& end_above
)
537 if (start_angle
> end_angle
)
538 return app_fill_rect(g
,r
, BrushObj
, Pen
);
542 else if (start_above
)
544 /* fill to the left of end_line */
546 return app_fill_rect(g
,r
, BrushObj
, Pen
);
550 /* fill right of start_line */
551 r
.width
= r
.x
+r
.width
-x1
;
553 return app_fill_rect(g
,r
, BrushObj
, Pen
);
557 if (start_angle
> end_angle
)
559 /* fill outsides of wedge */
560 if (! app_fill_rect(g
, rect(r
.x
, r
.y
,
561 x2
-r
.x
, r
.height
), BrushObj
, Pen
))
563 return app_fill_rect(g
, rect(x1
, r
.y
,
564 r
.x
+r
.width
-x1
, r
.height
), BrushObj
, Pen
);
568 /* fill inside of wedge */
571 return app_fill_rect(g
, r
, BrushObj
, Pen
);
578 * To fill an axis-aligned ellipse, we use a scan-line algorithm.
579 * We walk downwards from the top Y co-ordinate, calculating
580 * the width of the ellipse using incremental integer arithmetic.
581 * To save calculation, we observe that the top and bottom halves
582 * of the ellipsoid are mirror-images, therefore we can draw the
583 * top and bottom halves by reflection. As a result, this algorithm
584 * draws rectangles inwards from the top and bottom edges of the
585 * bounding rectangle.
587 * To save rendering time, draw as few rectangles as possible.
588 * Other ellipse-drawing algorithms assume we want to draw each
589 * line, using a draw_pixel operation, or a draw_horizontal_line
590 * operation. This approach is slower than it needs to be in
591 * circumstances where a fill_rect operation is more efficient
592 * (such as in X-Windows, where there is a communication overhead
593 * to the X-Server). For this reason, the algorithm accumulates
594 * rectangles on adjacent lines which have the same width into a
595 * single larger rectangle.
597 * This algorithm forms the basis of the later, more complex,
598 * draw_ellipse algorithm, which renders the rectangular spaces
599 * between an outer and inner ellipse, and also the draw_arc and
600 * fill_arc operations which additionally clip drawing between
601 * a start_angle and an end_angle.
607 app_fill_ellipse(DC
*g
, Rect r
, PGDIBRUSHOBJ BrushObj
)
609 /* e(x,y) = b*b*x*x + a*a*y*y - a*a*b*b */
612 int b
= r
.height
/ 2;
617 long xcrit
= (3 * a2
/ 4) + 1;
618 long ycrit
= (3 * b2
/ 4) + 1;
619 long t
= b2
+ a2
- 2*a2
*b
; /* t = e(x+1,y-1) */
620 long dxt
= b2
*(3+x
+x
);
621 long dyt
= a2
*(3-y
-y
);
629 if ((r
.width
<= 2) || (r
.height
<= 2))
630 return app_fill_rect(g
, r
, BrushObj
, FALSE
);
634 r1
.width
= r
.width
& 1; /* i.e. if width is odd */
638 r2
.y
= r
.y
+ r
.height
- 1;
642 if (t
+ a2
*y
< xcrit
) { /* e(x+1,y-1/2) <= 0 */
643 /* move outwards to encounter edge */
649 r1
.x
-= 1; r1
.width
+= 2;
650 r2
.x
-= 1; r2
.width
+= 2;
652 else if (t
- b2
*x
>= ycrit
) { /* e(x+1/2,y-1) > 0 */
653 /* drop down one line */
658 /* enlarge rectangles */
660 r2
.height
+= 1; r2
.y
-= 1;
663 /* drop diagonally down and out */
670 if ((r1
.width
> 0) && (r1
.height
> 0))
672 /* draw rectangles first */
674 if (r1
.y
+r1
.height
< r2
.y
) {
675 /* distinct rectangles */
676 result
&= app_fill_rect(g
, r1
, BrushObj
, FALSE
);
677 result
&= app_fill_rect(g
, r2
, BrushObj
, FALSE
);
681 r1
.y
+= r1
.height
; r1
.height
= 1;
682 r2
.y
-= 1; r2
.height
= 1;
685 /* skipped pixels on initial diagonal */
687 /* enlarge, rather than moving down */
689 r2
.height
+= 1; r2
.y
-= 1;
693 r1
.x
-= 1; r1
.width
+= 2;
694 r2
.x
-= 1; r2
.width
+= 2;
701 r1
.height
= r2
.y
+r2
.height
-r1
.y
;
702 result
&= app_fill_rect(g
, r1
, BrushObj
, FALSE
);
705 /* crossover, draw final line */
708 r1
.height
= r1
.y
+r1
.height
-r2
.y
;
710 result
&= app_fill_rect(g
, r1
, BrushObj
, FALSE
);
717 POINT
app_boundary_point(Rect r
, int angle
)
731 return pt(r
.x
+r
.width
, cy
);
732 else if (angle
== 45)
733 return pt(r
.x
+r
.width
, r
.y
);
734 else if (angle
== 90)
736 else if (angle
== 135)
738 else if (angle
== 180)
740 else if (angle
== 225)
741 return pt(r
.x
, r
.y
+r
.height
);
742 else if (angle
== 270)
743 return pt(cx
, r
.y
+r
.height
);
744 else if (angle
== 315)
745 return pt(r
.x
+r
.width
, r
.y
+r
.height
);
747 tangent
= tan(DEGREES_TO_RADIANS(angle
));
749 if ((angle
> 45) && (angle
< 135))
750 return pt((int)(cx
+r
.height
/tangent
/2), r
.y
);
751 else if ((angle
> 225) && (angle
< 315))
752 return pt((int)(cx
-r
.height
/tangent
/2), r
.y
+r
.height
);
753 else if ((angle
> 135) && (angle
< 225))
754 return pt(r
.x
, (int)(cy
+r
.width
*tangent
/2));
756 return pt(r
.x
+r
.width
, (int)(cy
-r
.width
*tangent
/2));
761 app_fill_arc(DC
*g
, Rect r
, int start_angle
, int end_angle
, PGDIBRUSHOBJ BrushObj
, BOOL Chord
)
763 /* e(x,y) = b*b*x*x + a*a*y*y - a*a*b*b */
766 int b
= r
.height
/ 2;
771 long xcrit
= (3 * a2
/ 4) + 1;
772 long ycrit
= (3 * b2
/ 4) + 1;
773 long t
= b2
+ a2
- 2*a2
*b
; /* t = e(x+1,y-1) */
774 long dxt
= b2
*(3+x
+x
);
775 long dyt
= a2
*(3-y
-y
);
779 int movedown
, moveout
;
782 /* line descriptions */
787 /* if angles differ by 360 degrees or more, close the shape */
788 if ((start_angle
+ 360 <= end_angle
) ||
789 (start_angle
- 360 >= end_angle
))
791 return app_fill_ellipse(g
, r
, BrushObj
);
794 /* make start_angle >= 0 and <= 360 */
795 while (start_angle
< 0)
799 /* make end_angle >= 0 and <= 360 */
800 while (end_angle
< 0)
804 /* draw nothing if the angles are equal */
805 if (start_angle
== end_angle
)
808 /* find arc wedge line end points */
809 p1
= app_boundary_point(r
, start_angle
);
810 p2
= app_boundary_point(r
, end_angle
);
812 p0
= pt((p1
.x
+p2
.x
)/2,(p1
.y
+p2
.y
)/2);
814 p0
= pt(r
.x
+ r
.width
/2, r
.y
+ r
.height
/2);
816 /* initialise rectangles to be drawn */
819 r1
.width
= r
.width
& 1; /* i.e. if width is odd */
823 r2
.y
= r
.y
+ r
.height
- 1;
827 moveout
= movedown
= 0;
829 if (t
+ a2
*y
< xcrit
) { /* e(x+1,y-1/2) <= 0 */
830 /* move outwards to encounter edge */
837 else if (t
- b2
*x
>= ycrit
) { /* e(x+1/2,y-1) > 0 */
838 /* drop down one line */
846 /* drop diagonally down and out */
859 r1
.x
-= 1; r1
.width
+= 2;
860 r2
.x
-= 1; r2
.width
+= 2;
866 if (r1
.width
> r
.width
)
867 r1
.width
= r2
.width
= r
.width
;
868 if (r1
.y
== r2
.y
-1) {
870 r1
.width
= r2
.width
= r
.width
;
873 if ((r1
.width
> 0) && (r1
.y
+r1
.height
< r2
.y
)) {
874 /* distinct rectangles */
875 result
&= app_fill_arc_rect(g
, r1
,
877 start_angle
, end_angle
, BrushObj
, FALSE
);
878 result
&= app_fill_arc_rect(g
, r2
,
880 start_angle
, end_angle
, BrushObj
, FALSE
);
890 r1
.x
-= 1; r1
.width
+= 2;
891 r2
.x
-= 1; r2
.width
+= 2;
898 r1
.height
= r2
.y
+r2
.height
-r1
.y
;
899 while (r1
.height
> 0) {
900 result
&= app_fill_arc_rect(g
,
901 rect(r1
.x
, r1
.y
, r1
.width
, 1),
902 p0
, p1
, p2
, start_angle
, end_angle
, BrushObj
, FALSE
);
908 /* crossover, draw final line */
911 r1
.height
= r1
.y
+r1
.height
-r2
.y
;
913 while (r1
.height
> 0) {
914 result
&= app_fill_arc_rect(g
,
915 rect(r1
.x
, r1
.y
, r1
.width
, 1),
916 p0
, p1
, p2
, start_angle
, end_angle
, BrushObj
, FALSE
);
924 int app_draw_arc(DC
*g
, Rect r
, int start_angle
, int end_angle
, PGDIBRUSHOBJ PenBrushObj
, BOOL Chord
)
926 /* Outer ellipse: e(x,y) = b*b*x*x + a*a*y*y - a*a*b*b */
929 int b
= r
.height
/ 2;
934 long xcrit
= (3 * a2
/ 4) + 1;
935 long ycrit
= (3 * b2
/ 4) + 1;
936 long t
= b2
+ a2
- 2*a2
*b
; /* t = e(x+1,y-1) */
937 long dxt
= b2
*(3+x
+x
);
938 long dyt
= a2
*(3-y
-y
);
942 int w
= PenBrushObj
->ptPenWidth
.x
;
944 /* Inner ellipse: E(X,Y) = B*B*X*X + A*A*Y*Y - A*A*B*B */
946 int A
= a
-w
> 0 ? a
-w
: 0;
947 int B
= b
-w
> 0 ? b
-w
: 0;
952 long XCRIT
= (3 * A2
/ 4) + 1;
953 long YCRIT
= (3 * B2
/ 4) + 1;
954 long T
= B2
+ A2
- 2*A2
*B
; /* T = E(X+1,Y-1) */
955 long DXT
= B2
*(3+X
+X
);
956 long DYT
= A2
*(3-Y
-Y
);
960 /* arc rectangle calculations */
961 int movedown
, moveout
;
962 int innerX
= 0, prevx
, prevy
, W
;
966 /* line descriptions */
971 /* if angles differ by 360 degrees or more, close the shape */
972 if ((start_angle
+ 360 <= end_angle
) ||
973 (start_angle
- 360 >= end_angle
))
975 return app_draw_ellipse(g
, r
, PenBrushObj
);
978 /* make start_angle >= 0 and <= 360 */
979 while (start_angle
< 0)
983 /* make end_angle >= 0 and <= 360 */
984 while (end_angle
< 0)
988 /* draw nothing if the angles are equal */
989 if (start_angle
== end_angle
)
992 /* find arc wedge line end points */
993 p1
= app_boundary_point(r
, start_angle
);
994 p2
= app_boundary_point(r
, end_angle
);
996 p0
= pt((p1
.x
+p2
.x
)/2,(p1
.y
+p2
.y
)/2);
998 p0
= pt(r
.x
+ r
.width
/2, r
.y
+ r
.height
/2);
1000 /* determine ellipse rectangles */
1003 r1
.width
= r
.width
& 1; /* i.e. if width is odd */
1007 r2
.y
= r
.y
+ r
.height
- 1;
1018 if (T
+ A2
*Y
< XCRIT
) /* E(X+1,Y-1/2) <= 0 */
1020 /* move outwards to encounter edge */
1025 else if (T
- B2
*X
>= YCRIT
) /* e(x+1/2,y-1) > 0 */
1027 /* drop down one line */
1033 /* drop diagonally down and out */
1042 movedown
= moveout
= 0;
1045 if (r1
.x
+ W
< prevx
)
1050 if (t
+ a2
*y
< xcrit
) /* e(x+1,y-1/2) <= 0 */
1052 /* move outwards to encounter edge */
1059 else if (t
- b2
*x
>= ycrit
) /* e(x+1/2,y-1) > 0 */
1061 /* drop down one line */
1069 /* drop diagonally down and out */
1081 if (r1
.width
== 0) {
1082 r1
.x
-= 1; r1
.width
+= 2;
1083 r2
.x
-= 1; r2
.width
+= 2;
1089 if (r1
.width
> r
.width
)
1090 r1
.width
= r2
.width
= r
.width
;
1091 if (r1
.y
== r2
.y
-1) {
1093 r1
.width
= r2
.width
= r
.width
;
1096 if ((r1
.y
< r
.y
+w
) || (r1
.x
+W
>= r1
.x
+r1
.width
-W
))
1098 result
&= app_fill_arc_rect(g
, r1
,
1100 start_angle
, end_angle
, PenBrushObj
, TRUE
);
1101 result
&= app_fill_arc_rect(g
, r2
,
1103 start_angle
, end_angle
, PenBrushObj
, TRUE
);
1108 else if (r1
.y
+r1
.height
< r2
.y
)
1110 /* draw distinct rectangles */
1111 result
&= app_fill_arc_rect(g
, rect(
1114 start_angle
, end_angle
, PenBrushObj
, TRUE
);
1115 result
&= app_fill_arc_rect(g
, rect(
1116 r1
.x
+r1
.width
-W
,r1
.y
,W
,1),
1118 start_angle
, end_angle
, PenBrushObj
, TRUE
);
1119 result
&= app_fill_arc_rect(g
, rect(
1122 start_angle
, end_angle
, PenBrushObj
, TRUE
);
1123 result
&= app_fill_arc_rect(g
, rect(
1124 r2
.x
+r2
.width
-W
,r2
.y
,W
,1),
1126 start_angle
, end_angle
, PenBrushObj
, TRUE
);
1139 r1
.x
-= 1; r1
.width
+= 2;
1140 r2
.x
-= 1; r2
.width
+= 2;
1143 if ((x
<= a
) && (prevy
< r2
.y
)) {
1144 /* draw final lines */
1145 r1
.height
= r1
.y
+r1
.height
-r2
.y
;
1149 if (r
.x
+ W
!= prevx
)
1154 if (W
+W
>= r
.width
) {
1155 while (r1
.height
> 0) {
1156 result
&= app_fill_arc_rect(g
, rect(r
.x
,
1157 r1
.y
, r
.width
, 1), p0
, p1
, p2
,
1158 start_angle
, end_angle
, PenBrushObj
, TRUE
);
1165 while (r1
.height
> 0) {
1166 result
&= app_fill_arc_rect(g
, rect(r
.x
, r1
.y
,
1168 start_angle
, end_angle
, PenBrushObj
, TRUE
);
1169 result
&= app_fill_arc_rect(g
, rect(r
.x
+r
.width
-W
,
1170 r1
.y
, W
, 1), p0
, p1
, p2
,
1171 start_angle
, end_angle
, PenBrushObj
, TRUE
);
1180 /* ReactOS Interface *********************************************************/
1184 IntFillRect( DC
*dc
,
1189 PGDIBRUSHOBJ BrushObj
,
1192 DWORD ROP
= PATCOPY
;
1194 BITMAPOBJ
*BitmapObj
;
1195 GDIBRUSHINST BrushInst
;
1198 PDC_ATTR Dc_Attr
= NULL
;
1202 BitmapObj
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
1203 if (BitmapObj
== NULL
)
1205 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1209 if (!(BrushObj
->flAttrs
& GDIBRUSH_IS_NULL
))
1211 Dc_Attr
= dc
->pDc_Attr
;
1212 if (!Dc_Attr
) Dc_Attr
= &dc
->Dc_Attr
;
1214 /* fix negative spaces */
1223 Height
= 0 - Height
;
1226 DestRect
.left
= XLeft
;
1227 DestRect
.right
= XLeft
+ Width
;
1229 DestRect
.top
= YLeft
;
1230 DestRect
.bottom
= YLeft
+ Height
;
1232 BrushOrigin
.x
= BrushObj
->ptOrigin
.x
;
1233 BrushOrigin
.y
= BrushObj
->ptOrigin
.y
;
1235 if (Dc_Attr
->jROP2
== R2_XORPEN
)
1241 IntGdiInitBrushInstance(&BrushInst
, BrushObj
, dc
->XlatePen
);
1243 IntGdiInitBrushInstance(&BrushInst
, BrushObj
, dc
->XlateBrush
);
1246 &BitmapObj
->SurfObj
,
1254 &BrushInst
.BrushObject
, // use pDC->eboFill
1259 BITMAPOBJ_UnlockBitmap(BitmapObj
);
1275 PGDIBRUSHOBJ FillBrushObj
;
1276 int Start
= ceill(StartArc
);
1277 int End
= ceill(EndArc
);
1278 BOOL Chord
= (arctype
== GdiTypeChord
), ret
;
1280 Dc_Attr
= dc
->pDc_Attr
;
1281 if(!Dc_Attr
) Dc_Attr
= &dc
->Dc_Attr
;
1283 FillBrushObj
= BRUSHOBJ_LockBrush(Dc_Attr
->hbrush
);
1284 if (NULL
== FillBrushObj
)
1286 DPRINT1("FillArc Fail\n");
1287 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
1290 // Sort out alignment here.
1291 ret
= app_fill_arc(dc
, rect( XLeft
, YLeft
, Width
, Height
),
1292 (dc
->DcLevel
.flPath
& DCPATH_CLOCKWISE
) ? -End
: -Start
,
1293 (dc
->DcLevel
.flPath
& DCPATH_CLOCKWISE
) ? -Start
: -End
,
1294 FillBrushObj
, Chord
);
1296 BRUSHOBJ_UnlockBrush(FillBrushObj
);
1310 PGDIBRUSHOBJ PenBrushObj
)
1312 int Start
= ceill(StartArc
);
1313 int End
= ceill(EndArc
);
1314 BOOL Chord
= (arctype
== GdiTypeChord
);
1315 // Sort out alignment here.
1316 return app_draw_arc(dc
, rect( XLeft
, YLeft
, Width
, Height
),
1317 (dc
->DcLevel
.flPath
& DCPATH_CLOCKWISE
) ? -End
: -Start
,
1318 (dc
->DcLevel
.flPath
& DCPATH_CLOCKWISE
) ? -Start
: -End
,
1319 PenBrushObj
, Chord
);
1324 IntDrawEllipse( PDC dc
,
1329 PGDIBRUSHOBJ PenBrushObj
)
1331 return (BOOL
)app_draw_ellipse(dc
, rect( XLeft
, YLeft
, Width
, Height
), PenBrushObj
);
1336 IntFillEllipse( PDC dc
,
1344 PGDIBRUSHOBJ FillBrushObj
;
1346 Dc_Attr
= dc
->pDc_Attr
;
1347 if(!Dc_Attr
) Dc_Attr
= &dc
->Dc_Attr
;
1349 FillBrushObj
= BRUSHOBJ_LockBrush(Dc_Attr
->hbrush
);
1350 if (NULL
== FillBrushObj
)
1352 DPRINT1("FillEllipse Fail\n");
1353 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
1356 ret
= (BOOL
)app_fill_ellipse(dc
, rect( XLeft
, YLeft
, Width
, Height
), FillBrushObj
);
1358 BRUSHOBJ_UnlockBrush(FillBrushObj
);
1364 IntFillRoundRect( PDC dc
,
1373 PGDIBRUSHOBJ FillBrushObj
;
1375 int rx
, ry
; /* radius in x and y directions */
1377 Dc_Attr
= dc
->pDc_Attr
;
1378 if(!Dc_Attr
) Dc_Attr
= &dc
->Dc_Attr
;
1380 FillBrushObj
= BRUSHOBJ_LockBrush(Dc_Attr
->hbrush
);
1381 if (NULL
== FillBrushObj
)
1383 DPRINT1("FillEllipse Fail\n");
1384 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
1388 r
= rect( Left
, Top
, abs(Right
-Left
), abs(Bottom
-Top
));
1392 if (Wellipse
> r
.width
)
1394 if (Hellipse
> r
.height
) // > W > H
1395 app_fill_ellipse(dc
, r
, FillBrushObj
);
1398 app_fill_arc(dc
, rect( r
.x
, r
.y
, r
.width
- 1, Hellipse
),
1399 0, 180, FillBrushObj
,FALSE
);
1400 app_fill_arc(dc
, rect(r
.x
, Bottom
- Hellipse
- 1, r
.width
- 1, Hellipse
),
1401 180, 360, FillBrushObj
, FALSE
);
1404 else if(Hellipse
> r
.height
) // < W > H
1406 app_fill_arc(dc
, rect(r
.x
, r
.y
, Wellipse
, r
.height
- 1),
1407 90, 270, FillBrushObj
, FALSE
);
1408 app_fill_arc(dc
, rect(Right
- Wellipse
- 1, r
.y
, Wellipse
, r
.height
- 1),
1409 270, 90, FillBrushObj
,FALSE
);
1413 app_fill_arc(dc
, rect(r
.x
, r
.y
, rx
+rx
, ry
+ry
),
1414 90, 180, FillBrushObj
, FALSE
);
1416 app_fill_arc(dc
, rect(r
.x
, r
.y
+r
.height
-ry
-ry
, rx
+rx
, ry
+ry
),
1417 180, 270, FillBrushObj
, FALSE
);
1419 app_fill_arc(dc
, rect(r
.x
+r
.width
-rx
-rx
, r
.y
+r
.height
-ry
-ry
, rx
+rx
, ry
+ry
),
1420 270, 360, FillBrushObj
,FALSE
);
1422 app_fill_arc(dc
, rect(r
.x
+r
.width
-rx
-rx
, r
.y
, rx
+rx
, ry
+ry
),
1423 0, 90, FillBrushObj
,FALSE
);
1425 if (Wellipse
< r
.width
)
1427 app_fill_rect(dc
, rect(r
.x
+rx
, r
.y
, r
.width
-rx
-rx
, ry
+1), FillBrushObj
, FALSE
);
1428 app_fill_rect(dc
, rect(r
.x
+rx
, r
.y
+r
.height
-ry
+1, r
.width
-rx
-rx
, ry
-1), FillBrushObj
, FALSE
);
1430 if (Hellipse
< r
.height
)
1432 app_fill_rect(dc
, rect(r
.x
, r
.y
+ry
+1, r
.width
, r
.height
-ry
-ry
), FillBrushObj
, FALSE
);
1435 BRUSHOBJ_UnlockBrush(FillBrushObj
);
1442 IntDrawRoundRect( PDC dc
,
1449 PGDIBRUSHOBJ PenBrushObj
)
1452 int rx
, ry
; /* radius in x and y directions */
1453 int w
= PenBrushObj
->ptPenWidth
.x
;
1455 r
= rect( Left
, Top
, abs(Right
-Left
), abs(Bottom
-Top
));
1459 if (Wellipse
> r
.width
)
1461 if (Hellipse
> r
.height
) // > W > H
1462 app_draw_ellipse(dc
, r
, PenBrushObj
);
1465 app_draw_arc(dc
, rect( r
.x
, r
.y
, r
.width
- 1, Hellipse
- 1),
1466 0, 180, PenBrushObj
, FALSE
);
1467 app_draw_arc(dc
, rect(r
.x
, Bottom
- Hellipse
, r
.width
- 1, Hellipse
- 1),
1468 180, 360, PenBrushObj
, FALSE
);
1471 else if(Hellipse
> r
.height
) // < W > H
1473 app_draw_arc(dc
, rect(r
.x
, r
.y
, Wellipse
- 1, r
.height
- 1),
1474 90, 270, PenBrushObj
, FALSE
);
1475 app_draw_arc(dc
, rect(Right
- Wellipse
, r
.y
, Wellipse
- 1, r
.height
- 1),
1476 270, 90, PenBrushObj
, FALSE
);
1480 app_draw_arc(dc
, rect(r
.x
, r
.y
, rx
+rx
, ry
+ry
),
1481 90, 180, PenBrushObj
, FALSE
);
1483 app_draw_arc(dc
, rect(r
.x
,r
.y
+r
.height
-ry
-ry
,rx
+rx
,ry
+ry
),
1484 180, 270, PenBrushObj
, FALSE
);
1486 app_draw_arc(dc
, rect(r
.x
+r
.width
-rx
-rx
, r
.y
+r
.height
-ry
-ry
, rx
+rx
, ry
+ry
),
1487 270, 360, PenBrushObj
, FALSE
);
1489 app_draw_arc(dc
, rect(r
.x
+r
.width
-rx
-rx
,r
.y
,rx
+rx
,ry
+ry
),
1490 0, 90, PenBrushObj
, FALSE
);
1492 if ( Hellipse
< r
.height
)
1494 app_fill_rect(dc
, rect(r
.x
, r
.y
+ry
+1, w
, r
.height
-ry
-ry
), PenBrushObj
, TRUE
);
1497 app_fill_rect(dc
, rect(r
.x
+r
.width
-w
, r
.y
+ry
+1, w
, r
.height
-ry
-ry
),
1500 if ( Wellipse
< r
.width
)
1502 app_fill_rect(dc
, rect(r
.x
+rx
, r
.y
+r
.height
-w
, r
.width
-rx
-rx
, w
),
1505 app_fill_rect(dc
, rect(r
.x
+rx
, r
.y
, r
.width
-rx
-rx
, w
), PenBrushObj
, TRUE
);