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/
53 #define _USE_MATH_DEFINES
60 #define DEGREES_TO_RADIANS(deg) ((deg)*2*M_PI/360)
64 int x
, y
; /* top-left point inside rect */
65 int width
, height
; /* width and height of rect */
68 int FASTCALL
IntFillRect(DC
*dc
, INT XLeft
, INT YLeft
, INT Width
, INT Height
, PBRUSH pbrush
, BOOL Pen
);
69 //int FASTCALL app_fill_rect(DC *dc, Rect r, PBRUSH pbrush, BOOL Pen);
74 app_new_point(int x
, int y
)
81 #define pt(x,y) app_new_point((x),(y))
86 rect(int x
, int y
, int width
, int height
)
98 * app_window_fill_rect:
100 * Fill a rectangle with colour, in a window.
102 * This function implements client-side clipping, so that
103 * we never rely on the GDI system to do clipping, except if
104 * the destination is a window which is partially obscured.
105 * In that situation we must rely on the GDI system because there
106 * is no way for the program to know which portions of the
107 * window are currently obscured.
109 #define app_fill_rect( dc, r, BrushObj, Pen) \
110 IntFillRect(dc, r.x, r.y, r.width, r.height, BrushObj, Pen)
113 * Drawing an ellipse with a certain line thickness.
114 * Use an inner and and outer ellipse and fill the spaces between.
115 * The inner ellipse uses all UPPERCASE letters, the outer lowercase.
117 * This algorithm is based on the fill_ellipse algorithm presented
118 * above, but uses two ellipse calculations, and some fix-up code
119 * to avoid pathological cases where the inner ellipse is almost
120 * the same size as the outer (in which case the border of the
121 * elliptical curve might otherwise have appeared broken).
126 app_draw_ellipse(DC
*g
, Rect r
, PBRUSH pbrush
)
128 /* Outer ellipse: e(x,y) = b*b*x*x + a*a*y*y - a*a*b*b */
131 int b
= r
.height
/ 2;
136 long xcrit
= (3 * a2
/ 4) + 1;
137 long ycrit
= (3 * b2
/ 4) + 1;
138 long t
= b2
+ a2
- 2*a2
*b
; /* t = e(x+1,y-1) */
139 long dxt
= b2
*(3+x
+x
);
140 long dyt
= a2
*(3-y
-y
);
144 int w
= pbrush
->ptPenWidth
.x
;
146 /* Inner ellipse: E(X,Y) = B*B*X*X + A*A*Y*Y - A*A*B*B */
148 int A
= a
-w
> 0 ? a
-w
: 0;
149 int B
= b
-w
> 0 ? b
-w
: 0;
154 long XCRIT
= (3 * A2
/ 4) + 1;
155 long YCRIT
= (3 * B2
/ 4) + 1;
156 long T
= B2
+ A2
- 2*A2
*B
; /* T = E(X+1,Y-1) */
157 long DXT
= B2
*(3+X
+X
);
158 long DYT
= A2
*(3-Y
-Y
);
162 int movedown
, moveout
;
163 int innerX
= 0, prevx
, prevy
, W
;
169 if ((r
.width
<= 2) || (r
.height
<= 2))
170 return app_fill_rect(g
, r
, pbrush
, TRUE
);
174 r1
.width
= r
.width
& 1; /* i.e. if width is odd */
178 r2
.y
= r
.y
+ r
.height
- 1;
189 if (T
+ A2
*Y
< XCRIT
) /* E(X+1,Y-1/2) <= 0 */
191 /* move outwards to encounter edge */
196 else if (T
- B2
*X
>= YCRIT
) /* e(x+1/2,y-1) > 0 */
198 /* drop down one line */
204 /* drop diagonally down and out */
213 movedown
= moveout
= 0;
216 if (r1
.x
+ W
< prevx
)
221 if (t
+ a2
*y
< xcrit
) /* e(x+1,y-1/2) <= 0 */
223 /* move outwards to encounter edge */
230 else if (t
- b2
*x
>= ycrit
) /* e(x+1/2,y-1) > 0 */
232 /* drop down one line */
240 /* drop diagonally down and out */
253 r1
.x
-= 1; r1
.width
+= 2;
254 r2
.x
-= 1; r2
.width
+= 2;
260 if (r1
.width
> r
.width
)
261 r1
.width
= r2
.width
= r
.width
;
262 if (r1
.y
== r2
.y
-1) {
264 r1
.width
= r2
.width
= r
.width
;
267 if ((r1
.y
< r
.y
+w
) || (r1
.x
+W
>= r1
.x
+r1
.width
-W
))
269 result
&= app_fill_rect(g
, r1
, pbrush
, TRUE
);
270 result
&= app_fill_rect(g
, r2
, pbrush
, TRUE
);
275 else if (r1
.y
+r1
.height
< r2
.y
)
277 /* draw distinct rectangles */
278 result
&= app_fill_rect(g
, rect(r1
.x
,r1
.y
,
280 result
&= app_fill_rect(g
, rect(
281 r1
.x
+r1
.width
-W
,r1
.y
,W
,1), pbrush
, TRUE
);
282 result
&= app_fill_rect(g
, rect(r2
.x
,
283 r2
.y
,W
,1), pbrush
, TRUE
);
284 result
&= app_fill_rect(g
, rect(
285 r2
.x
+r2
.width
-W
,r2
.y
,W
,1), pbrush
, TRUE
);
298 r1
.x
-= 1; r1
.width
+= 2;
299 r2
.x
-= 1; r2
.width
+= 2;
302 if ((x
<= a
) && (prevy
< r2
.y
)) {
303 /* draw final line */
304 r1
.height
= r1
.y
+r1
.height
-r2
.y
;
308 if (r
.x
+ W
!= prevx
)
313 if (W
+W
>= r
.width
) {
314 result
&= app_fill_rect(g
, rect(r
.x
, r1
.y
,
315 r
.width
, r1
.height
), pbrush
, TRUE
);
319 result
&= app_fill_rect(g
, rect(r
.x
, r1
.y
, W
, r1
.height
), pbrush
, TRUE
);
320 result
&= app_fill_rect(g
, rect(r
.x
+r
.width
-W
, r1
.y
,
321 W
, r1
.height
), pbrush
, TRUE
);
327 * Draw an arc of an ellipse from start_angle anti-clockwise to
328 * end_angle. If the angles coincide, draw nothing; if they
329 * differ by 360 degrees or more, draw a full ellipse.
330 * The shape is drawn with the current line thickness,
331 * completely within the bounding rectangle. The shape is also
332 * axis-aligned, so that the ellipse would be horizontally and
333 * vertically symmetric is it was complete.
335 * The draw_arc algorithm is based on draw_ellipse, but unlike
336 * that algorithm is not symmetric in the general case, since
337 * an angular portion is clipped from the shape.
338 * This clipping is performed by keeping track of two hypothetical
339 * lines joining the centre point to the enclosing rectangle,
340 * at the angles start_angle and end_angle, using a line-intersection
341 * algorithm. Essentially the algorithm just fills the spaces
342 * which are within the arc and also between the angles, going
343 * in an anti-clockwise direction from start_angle to end_angle.
344 * In the top half of the ellipse, this amounts to drawing
345 * to the left of the start_angle line and to the right of
346 * the end_angle line, while in the bottom half of the ellipse,
347 * it involves drawing to the right of the start_angle and to
348 * the left of the end_angle.
352 * Fill a rectangle within an arc, given the centre point p0,
353 * and the two end points of the lines corresponding to the
354 * start_angle and the end_angle. This function takes care of
355 * the logic needed to swap the fill direction below
356 * the central point, and also performs the calculations
357 * needed to intersect the current Y value with each line.
362 app_fill_arc_rect(DC
*g
,
363 Rect r
, // top, left, width, height
373 int start_above
, end_above
;
374 long rise1
, run1
, rise2
, run2
;
383 /* in top half of arc ellipse */
387 /* start_line is in the top half and is */
388 /* intersected by the current Y scan line */
392 x1
= p0
.x
+ (r
.y
-p0
.y
)*run1
/rise1
;
395 else if ((start_angle
>= 0) && (start_angle
<= 180))
397 /* start_line is above middle */
403 /* start_line is below middle */
409 if (x1
> r
.x
+r
.width
)
414 /* end_line is in the top half and is */
415 /* intersected by the current Y scan line */
419 x2
= p0
.x
+ (r
.y
-p0
.y
)*run2
/rise2
;
422 else if ((end_angle
>= 0) && (end_angle
<= 180))
424 /* end_line is above middle */
430 /* end_line is below middle */
435 if (x2
< r
.x
) x2
= r
.x
;
437 if (x2
> r
.x
+r
.width
) x2
= r
.x
+r
.width
;
439 if (start_above
&& end_above
)
441 if (start_angle
> end_angle
)
443 /* fill outsides of wedge */
444 if (! app_fill_rect(g
, rect(r
.x
, r
.y
,
445 x1
-r
.x
, r
.height
), pbrush
, Pen
))
447 return app_fill_rect(g
, rect(x2
, r
.y
,
448 r
.x
+r
.width
-x2
, r
.height
), pbrush
, Pen
);
452 /* fill inside of wedge */
455 return app_fill_rect(g
, r
, pbrush
, Pen
);
458 else if (start_above
)
460 /* fill to the left of the start_line */
462 return app_fill_rect(g
, r
, pbrush
, Pen
);
466 /* fill right of end_line */
467 r
.width
= r
.x
+r
.width
-x2
;
469 return app_fill_rect(g
, r
, pbrush
, Pen
);
473 if (start_angle
> end_angle
)
474 return app_fill_rect(g
,r
, pbrush
, Pen
);
481 /* in lower half of arc ellipse */
485 /* start_line is in the lower half and is */
486 /* intersected by the current Y scan line */
490 x1
= p0
.x
+ (r
.y
-p0
.y
)*run1
/rise1
;
493 else if ((start_angle
>= 180) && (start_angle
<= 360))
495 /* start_line is below middle */
501 /* start_line is above middle */
507 if (x1
> r
.x
+r
.width
)
512 /* end_line is in the lower half and is */
513 /* intersected by the current Y scan line */
517 x2
= p0
.x
+ (r
.y
-p0
.y
)*run2
/rise2
;
520 else if ((end_angle
>= 180) && (end_angle
<= 360))
522 /* end_line is below middle */
528 /* end_line is above middle */
534 if (x2
> r
.x
+r
.width
)
537 if (start_above
&& end_above
)
539 if (start_angle
> end_angle
)
540 return app_fill_rect(g
,r
, pbrush
, Pen
);
544 else if (start_above
)
546 /* fill to the left of end_line */
548 return app_fill_rect(g
,r
, pbrush
, Pen
);
552 /* fill right of start_line */
553 r
.width
= r
.x
+r
.width
-x1
;
555 return app_fill_rect(g
,r
, pbrush
, Pen
);
559 if (start_angle
> end_angle
)
561 /* fill outsides of wedge */
562 if (! app_fill_rect(g
, rect(r
.x
, r
.y
,
563 x2
-r
.x
, r
.height
), pbrush
, Pen
))
565 return app_fill_rect(g
, rect(x1
, r
.y
,
566 r
.x
+r
.width
-x1
, r
.height
), pbrush
, Pen
);
570 /* fill inside of wedge */
573 return app_fill_rect(g
, r
, pbrush
, Pen
);
580 * To fill an axis-aligned ellipse, we use a scan-line algorithm.
581 * We walk downwards from the top Y co-ordinate, calculating
582 * the width of the ellipse using incremental integer arithmetic.
583 * To save calculation, we observe that the top and bottom halves
584 * of the ellipsoid are mirror-images, therefore we can draw the
585 * top and bottom halves by reflection. As a result, this algorithm
586 * draws rectangles inwards from the top and bottom edges of the
587 * bounding rectangle.
589 * To save rendering time, draw as few rectangles as possible.
590 * Other ellipse-drawing algorithms assume we want to draw each
591 * line, using a draw_pixel operation, or a draw_horizontal_line
592 * operation. This approach is slower than it needs to be in
593 * circumstances where a fill_rect operation is more efficient
594 * (such as in X-Windows, where there is a communication overhead
595 * to the X-Server). For this reason, the algorithm accumulates
596 * rectangles on adjacent lines which have the same width into a
597 * single larger rectangle.
599 * This algorithm forms the basis of the later, more complex,
600 * draw_ellipse algorithm, which renders the rectangular spaces
601 * between an outer and inner ellipse, and also the draw_arc and
602 * fill_arc operations which additionally clip drawing between
603 * a start_angle and an end_angle.
609 app_fill_ellipse(DC
*g
, Rect r
, PBRUSH pbrush
)
611 /* e(x,y) = b*b*x*x + a*a*y*y - a*a*b*b */
614 int b
= r
.height
/ 2;
619 long xcrit
= (3 * a2
/ 4) + 1;
620 long ycrit
= (3 * b2
/ 4) + 1;
621 long t
= b2
+ a2
- 2*a2
*b
; /* t = e(x+1,y-1) */
622 long dxt
= b2
*(3+x
+x
);
623 long dyt
= a2
*(3-y
-y
);
631 if ((r
.width
<= 2) || (r
.height
<= 2))
632 return app_fill_rect(g
, r
, pbrush
, FALSE
);
636 r1
.width
= r
.width
& 1; /* i.e. if width is odd */
640 r2
.y
= r
.y
+ r
.height
- 1;
644 if (t
+ a2
*y
< xcrit
) { /* e(x+1,y-1/2) <= 0 */
645 /* move outwards to encounter edge */
651 r1
.x
-= 1; r1
.width
+= 2;
652 r2
.x
-= 1; r2
.width
+= 2;
654 else if (t
- b2
*x
>= ycrit
) { /* e(x+1/2,y-1) > 0 */
655 /* drop down one line */
660 /* enlarge rectangles */
662 r2
.height
+= 1; r2
.y
-= 1;
665 /* drop diagonally down and out */
672 if ((r1
.width
> 0) && (r1
.height
> 0))
674 /* draw rectangles first */
676 if (r1
.y
+r1
.height
< r2
.y
) {
677 /* distinct rectangles */
678 result
&= app_fill_rect(g
, r1
, pbrush
, FALSE
);
679 result
&= app_fill_rect(g
, r2
, pbrush
, FALSE
);
683 r1
.y
+= r1
.height
; r1
.height
= 1;
684 r2
.y
-= 1; r2
.height
= 1;
687 /* skipped pixels on initial diagonal */
689 /* enlarge, rather than moving down */
691 r2
.height
+= 1; r2
.y
-= 1;
695 r1
.x
-= 1; r1
.width
+= 2;
696 r2
.x
-= 1; r2
.width
+= 2;
703 r1
.height
= r2
.y
+r2
.height
-r1
.y
;
704 result
&= app_fill_rect(g
, r1
, pbrush
, FALSE
);
707 /* crossover, draw final line */
710 r1
.height
= r1
.y
+r1
.height
-r2
.y
;
712 result
&= app_fill_rect(g
, r1
, pbrush
, FALSE
);
720 app_boundary_point(Rect r
, int angle
)
734 return pt(r
.x
+r
.width
, cy
);
735 else if (angle
== 45)
736 return pt(r
.x
+r
.width
, r
.y
);
737 else if (angle
== 90)
739 else if (angle
== 135)
741 else if (angle
== 180)
743 else if (angle
== 225)
744 return pt(r
.x
, r
.y
+r
.height
);
745 else if (angle
== 270)
746 return pt(cx
, r
.y
+r
.height
);
747 else if (angle
== 315)
748 return pt(r
.x
+r
.width
, r
.y
+r
.height
);
750 tangent
= tan(DEGREES_TO_RADIANS(angle
));
752 if ((angle
> 45) && (angle
< 135))
753 return pt((int)(cx
+r
.height
/tangent
/2), r
.y
);
754 else if ((angle
> 225) && (angle
< 315))
755 return pt((int)(cx
-r
.height
/tangent
/2), r
.y
+r
.height
);
756 else if ((angle
> 135) && (angle
< 225))
757 return pt(r
.x
, (int)(cy
+r
.width
*tangent
/2));
759 return pt(r
.x
+r
.width
, (int)(cy
-r
.width
*tangent
/2));
764 app_fill_arc(DC
*g
, Rect r
, int start_angle
, int end_angle
, PBRUSH pbrush
, BOOL Chord
)
766 /* e(x,y) = b*b*x*x + a*a*y*y - a*a*b*b */
769 int b
= r
.height
/ 2;
774 long xcrit
= (3 * a2
/ 4) + 1;
775 long ycrit
= (3 * b2
/ 4) + 1;
776 long t
= b2
+ a2
- 2*a2
*b
; /* t = e(x+1,y-1) */
777 long dxt
= b2
*(3+x
+x
);
778 long dyt
= a2
*(3-y
-y
);
782 int movedown
, moveout
;
785 /* line descriptions */
790 /* if angles differ by 360 degrees or more, close the shape */
791 if ((start_angle
+ 360 <= end_angle
) ||
792 (start_angle
- 360 >= end_angle
))
794 return app_fill_ellipse(g
, r
, pbrush
);
797 /* make start_angle >= 0 and <= 360 */
798 while (start_angle
< 0)
802 /* make end_angle >= 0 and <= 360 */
803 while (end_angle
< 0)
807 /* draw nothing if the angles are equal */
808 if (start_angle
== end_angle
)
811 /* find arc wedge line end points */
812 p1
= app_boundary_point(r
, start_angle
);
813 p2
= app_boundary_point(r
, end_angle
);
815 p0
= pt((p1
.x
+p2
.x
)/2,(p1
.y
+p2
.y
)/2);
817 p0
= pt(r
.x
+ r
.width
/2, r
.y
+ r
.height
/2);
819 /* initialise rectangles to be drawn */
822 r1
.width
= r
.width
& 1; /* i.e. if width is odd */
826 r2
.y
= r
.y
+ r
.height
- 1;
830 moveout
= movedown
= 0;
832 if (t
+ a2
*y
< xcrit
) { /* e(x+1,y-1/2) <= 0 */
833 /* move outwards to encounter edge */
840 else if (t
- b2
*x
>= ycrit
) { /* e(x+1/2,y-1) > 0 */
841 /* drop down one line */
849 /* drop diagonally down and out */
862 r1
.x
-= 1; r1
.width
+= 2;
863 r2
.x
-= 1; r2
.width
+= 2;
869 if (r1
.width
> r
.width
)
870 r1
.width
= r2
.width
= r
.width
;
871 if (r1
.y
== r2
.y
-1) {
873 r1
.width
= r2
.width
= r
.width
;
876 if ((r1
.width
> 0) && (r1
.y
+r1
.height
< r2
.y
)) {
877 /* distinct rectangles */
878 result
&= app_fill_arc_rect(g
, r1
,
880 start_angle
, end_angle
, pbrush
, FALSE
);
881 result
&= app_fill_arc_rect(g
, r2
,
883 start_angle
, end_angle
, pbrush
, FALSE
);
893 r1
.x
-= 1; r1
.width
+= 2;
894 r2
.x
-= 1; r2
.width
+= 2;
901 r1
.height
= r2
.y
+r2
.height
-r1
.y
;
902 while (r1
.height
> 0) {
903 result
&= app_fill_arc_rect(g
,
904 rect(r1
.x
, r1
.y
, r1
.width
, 1),
905 p0
, p1
, p2
, start_angle
, end_angle
, pbrush
, FALSE
);
911 /* crossover, draw final line */
914 r1
.height
= r1
.y
+r1
.height
-r2
.y
;
916 while (r1
.height
> 0) {
917 result
&= app_fill_arc_rect(g
,
918 rect(r1
.x
, r1
.y
, r1
.width
, 1),
919 p0
, p1
, p2
, start_angle
, end_angle
, pbrush
, FALSE
);
927 int app_draw_arc(DC
*g
, Rect r
, int start_angle
, int end_angle
, PBRUSH pbrushPen
, BOOL Chord
)
929 /* Outer ellipse: e(x,y) = b*b*x*x + a*a*y*y - a*a*b*b */
932 int b
= r
.height
/ 2;
937 long xcrit
= (3 * a2
/ 4) + 1;
938 long ycrit
= (3 * b2
/ 4) + 1;
939 long t
= b2
+ a2
- 2*a2
*b
; /* t = e(x+1,y-1) */
940 long dxt
= b2
*(3+x
+x
);
941 long dyt
= a2
*(3-y
-y
);
945 int w
= pbrushPen
->ptPenWidth
.x
;
947 /* Inner ellipse: E(X,Y) = B*B*X*X + A*A*Y*Y - A*A*B*B */
949 int A
= a
-w
> 0 ? a
-w
: 0;
950 int B
= b
-w
> 0 ? b
-w
: 0;
955 long XCRIT
= (3 * A2
/ 4) + 1;
956 long YCRIT
= (3 * B2
/ 4) + 1;
957 long T
= B2
+ A2
- 2*A2
*B
; /* T = E(X+1,Y-1) */
958 long DXT
= B2
*(3+X
+X
);
959 long DYT
= A2
*(3-Y
-Y
);
963 /* arc rectangle calculations */
964 int movedown
, moveout
;
965 int innerX
= 0, prevx
, prevy
, W
;
969 /* line descriptions */
974 /* if angles differ by 360 degrees or more, close the shape */
975 if ((start_angle
+ 360 <= end_angle
) ||
976 (start_angle
- 360 >= end_angle
))
978 return app_draw_ellipse(g
, r
, pbrushPen
);
981 /* make start_angle >= 0 and <= 360 */
982 while (start_angle
< 0)
986 /* make end_angle >= 0 and <= 360 */
987 while (end_angle
< 0)
991 /* draw nothing if the angles are equal */
992 if (start_angle
== end_angle
)
995 /* find arc wedge line end points */
996 p1
= app_boundary_point(r
, start_angle
);
997 p2
= app_boundary_point(r
, end_angle
);
999 p0
= pt((p1
.x
+p2
.x
)/2,(p1
.y
+p2
.y
)/2);
1001 p0
= pt(r
.x
+ r
.width
/2, r
.y
+ r
.height
/2);
1003 /* determine ellipse rectangles */
1006 r1
.width
= r
.width
& 1; /* i.e. if width is odd */
1010 r2
.y
= r
.y
+ r
.height
- 1;
1021 if (T
+ A2
*Y
< XCRIT
) /* E(X+1,Y-1/2) <= 0 */
1023 /* move outwards to encounter edge */
1028 else if (T
- B2
*X
>= YCRIT
) /* e(x+1/2,y-1) > 0 */
1030 /* drop down one line */
1036 /* drop diagonally down and out */
1045 movedown
= moveout
= 0;
1048 if (r1
.x
+ W
< prevx
)
1053 if (t
+ a2
*y
< xcrit
) /* e(x+1,y-1/2) <= 0 */
1055 /* move outwards to encounter edge */
1062 else if (t
- b2
*x
>= ycrit
) /* e(x+1/2,y-1) > 0 */
1064 /* drop down one line */
1072 /* drop diagonally down and out */
1084 if (r1
.width
== 0) {
1085 r1
.x
-= 1; r1
.width
+= 2;
1086 r2
.x
-= 1; r2
.width
+= 2;
1092 if (r1
.width
> r
.width
)
1093 r1
.width
= r2
.width
= r
.width
;
1094 if (r1
.y
== r2
.y
-1) {
1096 r1
.width
= r2
.width
= r
.width
;
1099 if ((r1
.y
< r
.y
+w
) || (r1
.x
+W
>= r1
.x
+r1
.width
-W
))
1101 result
&= app_fill_arc_rect(g
, r1
,
1103 start_angle
, end_angle
, pbrushPen
, TRUE
);
1104 result
&= app_fill_arc_rect(g
, r2
,
1106 start_angle
, end_angle
, pbrushPen
, TRUE
);
1111 else if (r1
.y
+r1
.height
< r2
.y
)
1113 /* draw distinct rectangles */
1114 result
&= app_fill_arc_rect(g
, rect(
1117 start_angle
, end_angle
, pbrushPen
, TRUE
);
1118 result
&= app_fill_arc_rect(g
, rect(
1119 r1
.x
+r1
.width
-W
,r1
.y
,W
,1),
1121 start_angle
, end_angle
, pbrushPen
, TRUE
);
1122 result
&= app_fill_arc_rect(g
, rect(
1125 start_angle
, end_angle
, pbrushPen
, TRUE
);
1126 result
&= app_fill_arc_rect(g
, rect(
1127 r2
.x
+r2
.width
-W
,r2
.y
,W
,1),
1129 start_angle
, end_angle
, pbrushPen
, TRUE
);
1142 r1
.x
-= 1; r1
.width
+= 2;
1143 r2
.x
-= 1; r2
.width
+= 2;
1146 if ((x
<= a
) && (prevy
< r2
.y
)) {
1147 /* draw final lines */
1148 r1
.height
= r1
.y
+r1
.height
-r2
.y
;
1152 if (r
.x
+ W
!= prevx
)
1157 if (W
+W
>= r
.width
) {
1158 while (r1
.height
> 0) {
1159 result
&= app_fill_arc_rect(g
, rect(r
.x
,
1160 r1
.y
, r
.width
, 1), p0
, p1
, p2
,
1161 start_angle
, end_angle
, pbrushPen
, TRUE
);
1168 while (r1
.height
> 0) {
1169 result
&= app_fill_arc_rect(g
, rect(r
.x
, r1
.y
,
1171 start_angle
, end_angle
, pbrushPen
, TRUE
);
1172 result
&= app_fill_arc_rect(g
, rect(r
.x
+r
.width
-W
,
1173 r1
.y
, W
, 1), p0
, p1
, p2
,
1174 start_angle
, end_angle
, pbrushPen
, TRUE
);
1183 /* ReactOS Interface *********************************************************/
1187 IntFillRect( DC
*dc
,
1195 DWORD ROP
= PATCOPY
;
1204 psurf
= dc
->dclevel
.pSurface
;
1207 EngSetLastError(ERROR_INVALID_HANDLE
);
1211 if (!(pbrush
->flAttrs
& GDIBRUSH_IS_NULL
))
1213 pdcattr
= dc
->pdcattr
;
1215 /* fix negative spaces */
1224 Height
= 0 - Height
;
1227 DestRect
.left
= XLeft
;
1228 DestRect
.right
= XLeft
+ Width
;
1230 DestRect
.top
= YLeft
;
1231 DestRect
.bottom
= YLeft
+ Height
;
1233 BrushOrigin
.x
= pbrush
->ptOrigin
.x
;
1234 BrushOrigin
.y
= pbrush
->ptOrigin
.y
;
1236 if (pdcattr
->jROP2
== R2_XORPEN
)
1245 dc
->rosdc
.CombinedClip
,
1250 Pen
? &dc
->eboLine
.BrushObject
: &dc
->eboFill
.BrushObject
,
1271 int Start
= ceil(StartArc
);
1272 int End
= ceil(EndArc
);
1273 BOOL Chord
= (arctype
== GdiTypeChord
), ret
;
1275 pdcattr
= dc
->pdcattr
;
1277 pbrush
= BRUSH_LockBrush(pdcattr
->hbrush
);
1280 DPRINT1("FillArc Fail\n");
1281 EngSetLastError(ERROR_INTERNAL_ERROR
);
1284 // Sort out alignment here.
1285 ret
= app_fill_arc(dc
, rect( XLeft
, YLeft
, Width
, Height
),
1286 (dc
->dclevel
.flPath
& DCPATH_CLOCKWISE
) ? -End
: -Start
,
1287 (dc
->dclevel
.flPath
& DCPATH_CLOCKWISE
) ? -Start
: -End
,
1290 BRUSH_UnlockBrush(pbrush
);
1306 int Start
= ceil(StartArc
);
1307 int End
= ceil(EndArc
);
1308 BOOL Chord
= (arctype
== GdiTypeChord
);
1309 // Sort out alignment here.
1310 return app_draw_arc(dc
, rect( XLeft
, YLeft
, Width
, Height
),
1311 (dc
->dclevel
.flPath
& DCPATH_CLOCKWISE
) ? -End
: -Start
,
1312 (dc
->dclevel
.flPath
& DCPATH_CLOCKWISE
) ? -Start
: -End
,
1318 IntDrawEllipse( PDC dc
,
1325 return (BOOL
)app_draw_ellipse(dc
, rect( XLeft
, YLeft
, Width
, Height
), pbrush
);
1330 IntFillEllipse( PDC dc
,
1337 return (BOOL
)app_fill_ellipse(dc
, rect( XLeft
, YLeft
, Width
, Height
), pbrush
);
1342 IntFillRoundRect( PDC dc
,
1352 int rx
, ry
; /* radius in x and y directions */
1355 r
= rect( Left
, Top
, abs(Right
-Left
), abs(Bottom
-Top
));
1359 if (Wellipse
> r
.width
)
1361 if (Hellipse
> r
.height
) // > W > H
1362 app_fill_ellipse(dc
, r
, pbrush
);
1365 app_fill_arc(dc
, rect( r
.x
, r
.y
, r
.width
- 1, Hellipse
),
1366 0, 180, pbrush
,FALSE
);
1367 app_fill_arc(dc
, rect(r
.x
, Bottom
- Hellipse
- 1, r
.width
- 1, Hellipse
),
1368 180, 360, pbrush
, FALSE
);
1371 else if(Hellipse
> r
.height
) // < W > H
1373 app_fill_arc(dc
, rect(r
.x
, r
.y
, Wellipse
, r
.height
- 1),
1374 90, 270, pbrush
, FALSE
);
1375 app_fill_arc(dc
, rect(Right
- Wellipse
- 1, r
.y
, Wellipse
, r
.height
- 1),
1376 270, 90, pbrush
,FALSE
);
1380 app_fill_arc(dc
, rect(r
.x
, r
.y
, rx
+rx
, ry
+ry
),
1381 90, 180, pbrush
, FALSE
);
1383 app_fill_arc(dc
, rect(r
.x
, r
.y
+r
.height
-ry
-ry
, rx
+rx
, ry
+ry
),
1384 180, 270, pbrush
, FALSE
);
1386 app_fill_arc(dc
, rect(r
.x
+r
.width
-rx
-rx
, r
.y
+r
.height
-ry
-ry
, rx
+rx
, ry
+ry
),
1387 270, 360, pbrush
,FALSE
);
1389 app_fill_arc(dc
, rect(r
.x
+r
.width
-rx
-rx
, r
.y
, rx
+rx
, ry
+ry
),
1390 0, 90, pbrush
,FALSE
);
1392 if (Wellipse
< r
.width
)
1394 app_fill_rect(dc
, rect(r
.x
+rx
, r
.y
, r
.width
-rx
-rx
, ry
+1), pbrush
, FALSE
);
1395 app_fill_rect(dc
, rect(r
.x
+rx
, r
.y
+r
.height
-ry
+1, r
.width
-rx
-rx
, ry
-1), pbrush
, FALSE
);
1397 if (Hellipse
< r
.height
)
1399 app_fill_rect(dc
, rect(r
.x
, r
.y
+ry
+1, r
.width
, r
.height
-ry
-ry
), pbrush
, FALSE
);
1408 IntDrawRoundRect( PDC dc
,
1418 int rx
, ry
; /* radius in x and y directions */
1419 int w
= pbrushPen
->ptPenWidth
.x
;
1421 r
= rect( Left
, Top
, abs(Right
-Left
), abs(Bottom
-Top
));
1425 if (Wellipse
> r
.width
)
1427 if (Hellipse
> r
.height
) // > W > H
1428 app_draw_ellipse(dc
, r
, pbrushPen
);
1431 app_draw_arc(dc
, rect( r
.x
, r
.y
, r
.width
- 1, Hellipse
- 1),
1432 0, 180, pbrushPen
, FALSE
);
1433 app_draw_arc(dc
, rect(r
.x
, Bottom
- Hellipse
, r
.width
- 1, Hellipse
- 1),
1434 180, 360, pbrushPen
, FALSE
);
1437 else if(Hellipse
> r
.height
) // < W > H
1439 app_draw_arc(dc
, rect(r
.x
, r
.y
, Wellipse
- 1, r
.height
- 1),
1440 90, 270, pbrushPen
, FALSE
);
1441 app_draw_arc(dc
, rect(Right
- Wellipse
, r
.y
, Wellipse
- 1, r
.height
- 1),
1442 270, 90, pbrushPen
, FALSE
);
1446 app_draw_arc(dc
, rect(r
.x
, r
.y
, rx
+rx
, ry
+ry
),
1447 90, 180, pbrushPen
, FALSE
);
1449 app_draw_arc(dc
, rect(r
.x
,r
.y
+r
.height
-ry
-ry
,rx
+rx
,ry
+ry
),
1450 180, 270, pbrushPen
, FALSE
);
1452 app_draw_arc(dc
, rect(r
.x
+r
.width
-rx
-rx
, r
.y
+r
.height
-ry
-ry
, rx
+rx
, ry
+ry
),
1453 270, 360, pbrushPen
, FALSE
);
1455 app_draw_arc(dc
, rect(r
.x
+r
.width
-rx
-rx
,r
.y
,rx
+rx
,ry
+ry
),
1456 0, 90, pbrushPen
, FALSE
);
1458 if ( Hellipse
< r
.height
)
1460 app_fill_rect(dc
, rect(r
.x
, r
.y
+ry
+1, w
, r
.height
-ry
-ry
), pbrushPen
, TRUE
);
1463 app_fill_rect(dc
, rect(r
.x
+r
.width
-w
, r
.y
+ry
+1, w
, r
.height
-ry
-ry
),
1466 if ( Wellipse
< r
.width
)
1468 app_fill_rect(dc
, rect(r
.x
+rx
, r
.y
+r
.height
-w
, r
.width
-rx
-rx
, w
),
1471 app_fill_rect(dc
, rect(r
.x
+rx
, r
.y
, r
.width
-rx
-rx
, w
), pbrushPen
, TRUE
);