OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [services/] [gfx/] [mw/] [v2_0/] [src/] [engine/] [devarc.c] - Blame information for rev 27

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
/*
2
 * Copyright (c) 2000-2001 Greg Haerr <greg@censoft.com>
3
 *
4
 * Device-independent arc, pie and ellipse routines.
5
 * GdArc is integer only and requires start/end points.
6
 * GdArcAngle requires floating point and uses angles.
7
 * GdArcAngle uses qsin() and qcos() instead of sin() / cos()
8
 * so no math lib needed.
9
 *
10
 * Portions Copyright (c) 1991 David I. Bell
11
 * Permission is granted to use, distribute, or modify this source,
12
 * provided that this copyright notice remains intact.
13
 *
14
 * Arc line clipping and integer qsin/qcos routines used by permission:
15
 * Copyright (C) 1997-1998 by Eero Tamminen
16
 * Bugfixed by Greg Haerr
17
 */
18
 
19
#include <stdio.h>
20
#include "device.h"
21
 
22
#if HAVEFLOAT                   /* =1 compiles in GdArcAngle*/
23
#define HIGHPRECISION   0        /* =1 for high precision angles, uses mathlib*/
24
 
25
#if !HIGHPRECISION
26
typedef float   FLOAT;
27
/*
28
 * qsin/qcos - calculate sin() and cos() approximations from a lookup table
29
 *
30
 * This uses a cosine lookup table of 0-90 degrees at one degree steps
31
 * with the difference between successive values used for interpolation.
32
 * The achieved accuracy should be about +/-0.0001.  If you want more
33
 * accuracy, use doubles and smaller steps.  If you want more speed, use
34
 * fixed point arithmetics.
35
 */
36
static float cosine[91][2] = {
37
        { 1.000000, -1.523048e-04 },
38
        { 0.999848, -4.568681e-04 },
39
        { 0.999391, -7.612923e-04 },
40
        { 0.998630, -1.065484e-03 },
41
        { 0.997564, -1.369352e-03 },
42
        { 0.996195, -1.672803e-03 },
43
        { 0.994522, -1.975744e-03 },
44
        { 0.992546, -2.278083e-03 },
45
        { 0.990268, -2.579728e-03 },
46
        { 0.987688, -2.880588e-03 },
47
        { 0.984808, -3.180570e-03 },
48
        { 0.981627, -3.479583e-03 },
49
        { 0.978148, -3.777536e-03 },
50
        { 0.974370, -4.074339e-03 },
51
        { 0.970296, -4.369900e-03 },
52
        { 0.965926, -4.664130e-03 },
53
        { 0.961262, -4.956940e-03 },
54
        { 0.956305, -5.248240e-03 },
55
        { 0.951057, -5.537941e-03 },
56
        { 0.945519, -5.825955e-03 },
57
        { 0.939693, -6.112194e-03 },
58
        { 0.933580, -6.396572e-03 },
59
        { 0.927184, -6.679001e-03 },
60
        { 0.920505, -6.959396e-03 },
61
        { 0.913545, -7.237671e-03 },
62
        { 0.906308, -7.513741e-03 },
63
        { 0.898794, -7.787522e-03 },
64
        { 0.891007, -8.058931e-03 },
65
        { 0.882948, -8.327886e-03 },
66
        { 0.874620, -8.594303e-03 },
67
        { 0.866025, -8.858103e-03 },
68
        { 0.857167, -9.119205e-03 },
69
        { 0.848048, -9.377528e-03 },
70
        { 0.838671, -9.632995e-03 },
71
        { 0.829038, -9.885528e-03 },
72
        { 0.819152, -1.013505e-02 },
73
        { 0.809017, -1.038148e-02 },
74
        { 0.798636, -1.062476e-02 },
75
        { 0.788011, -1.086479e-02 },
76
        { 0.777146, -1.110152e-02 },
77
        { 0.766044, -1.133486e-02 },
78
        { 0.754710, -1.156475e-02 },
79
        { 0.743145, -1.179112e-02 },
80
        { 0.731354, -1.201390e-02 },
81
        { 0.719340, -1.223302e-02 },
82
        { 0.707107, -1.244841e-02 },
83
        { 0.694658, -1.266001e-02 },
84
        { 0.681998, -1.286775e-02 },
85
        { 0.669131, -1.307158e-02 },
86
        { 0.656059, -1.327142e-02 },
87
        { 0.642788, -1.346722e-02 },
88
        { 0.629320, -1.365892e-02 },
89
        { 0.615661, -1.384645e-02 },
90
        { 0.601815, -1.402977e-02 },
91
        { 0.587785, -1.420882e-02 },
92
        { 0.573576, -1.438353e-02 },
93
        { 0.559193, -1.455387e-02 },
94
        { 0.544639, -1.471977e-02 },
95
        { 0.529919, -1.488119e-02 },
96
        { 0.515038, -1.503807e-02 },
97
        { 0.500000, -1.519038e-02 },
98
        { 0.484810, -1.533806e-02 },
99
        { 0.469472, -1.548106e-02 },
100
        { 0.453990, -1.561935e-02 },
101
        { 0.438371, -1.575289e-02 },
102
        { 0.422618, -1.588162e-02 },
103
        { 0.406737, -1.600551e-02 },
104
        { 0.390731, -1.612454e-02 },
105
        { 0.374607, -1.623864e-02 },
106
        { 0.358368, -1.634781e-02 },
107
        { 0.342020, -1.645199e-02 },
108
        { 0.325568, -1.655116e-02 },
109
        { 0.309017, -1.664529e-02 },
110
        { 0.292372, -1.673435e-02 },
111
        { 0.275637, -1.681831e-02 },
112
        { 0.258819, -1.689715e-02 },
113
        { 0.241922, -1.697084e-02 },
114
        { 0.224951, -1.703936e-02 },
115
        { 0.207912, -1.710270e-02 },
116
        { 0.190809, -1.716082e-02 },
117
        { 0.173648, -1.721371e-02 },
118
        { 0.156434, -1.726136e-02 },
119
        { 0.139173, -1.730376e-02 },
120
        { 0.121869, -1.734088e-02 },
121
        { 0.104528, -1.737272e-02 },
122
        { 0.087156, -1.739927e-02 },
123
        { 0.069756, -1.742052e-02 },
124
        { 0.052336, -1.743646e-02 },
125
        { 0.034899, -1.744709e-02 },
126
        { 0.017452, -1.745241e-02 },
127
        { 0.000000, -1.745241e-02 }
128
};
129
 
130
static float
131
qcos(FLOAT angle)
132
{
133
        short a, b, c;
134
 
135
        a = angle;
136
        if (a < 0) {
137
                angle = a - angle;
138
                a = -a;
139
        } else {
140
                angle = angle - a;
141
        }
142
        b = a / 90;
143
        c = a - b * 90;
144
 
145
        /* interpolate according to angle */
146
        switch(b&3) {
147
                case 3:
148
                        c = 90 - c;
149
                        return cosine[c][0] - cosine[c-1][1] * angle;
150
                case 2:
151
                        return -(cosine[c][0] + cosine[c][1] * angle);
152
                case 1:
153
                        c = 90 - c;
154
                        return cosine[c-1][1] * angle - cosine[c][0];
155
                default:
156
                        return cosine[c][0] + cosine[c][1] * angle;
157
        }
158
}
159
 
160
static float
161
qsin(FLOAT angle)
162
{
163
        short a, b, c;
164
 
165
        /* change to cosine by subtracting 90 */
166
        a = (int)angle - 90;
167
        if (a < 0) {
168
                angle = (a + 90) - angle;
169
                a = -a;
170
        } else {
171
                angle = angle - (a + 90);
172
        }
173
        b = a / 90;
174
        c = a - b * 90;
175
 
176
        /* interpolate according to angle */
177
        switch(b&3) {
178
                case 3:
179
                        c = 90 - c;
180
                        return cosine[c][0] - cosine[c-1][1] * angle;
181
                case 2:
182
                        return -(cosine[c][0] + cosine[c][1] * angle);
183
                case 1:
184
                        c = 90 - c;
185
                        return cosine[c-1][1] * angle - cosine[c][0];
186
                default:
187
                        return cosine[c][0] + cosine[c][1] * angle;
188
        }
189
}
190
#else /* HIGHPRECISION*/
191
 
192
#include <math.h>
193
#define qcos    QCOS
194
#define qsin    QSIN
195
typedef double  FLOAT;
196
 
197
FLOAT QCOS(FLOAT a)
198
{
199
        return cos(a * M_PI / 180.);
200
}
201
 
202
FLOAT QSIN(FLOAT a)
203
{
204
        return sin(a * M_PI / 180.);
205
}
206
#endif /* HIGHPRECISION*/
207
#endif /* HAVEFLOAT*/
208
 
209
/*
210
 * Draw an arc or pie, angles are specified in 64th's of a degree.
211
 * This function requires floating point, use GdArc for integer only.
212
 */
213
void
214
GdArcAngle(PSD psd, MWCOORD x0, MWCOORD y0, MWCOORD rx, MWCOORD ry,
215
        MWCOORD angle1, MWCOORD angle2, int type)
216
{
217
#if HAVEFLOAT
218
        MWCOORD ax, ay, bx, by;
219
        FLOAT   a, b;
220
 
221
        /* calculate pie edge offsets from center to the ellipse rim */
222
        ax = qcos(angle1/64.) * rx;
223
        bx = qcos(angle2/64.) * rx;
224
 
225
        a = -qsin(angle1/64.);
226
        b = -qsin(angle2/64.);
227
        ay = a * ry;
228
        by = b * ry;
229
 
230
        /* call integer routine*/
231
        GdArc(psd, x0, y0, rx, ry, ax, ay, bx, by, type);
232
#endif /* HAVEFLOAT*/
233
}
234
 
235
/* argument holder for pie, arc and ellipse functions*/
236
typedef struct {
237
        PSD     psd;
238
        MWCOORD x0, y0;
239
        MWCOORD rx, ry;
240
        MWCOORD ax, ay;
241
        MWCOORD bx, by;
242
        int     adir, bdir;
243
        int     type;
244
} SLICE;
245
 
246
extern void drawpoint(PSD psd, MWCOORD x, MWCOORD y);
247
extern void drawrow(PSD psd, MWCOORD x1, MWCOORD x2, MWCOORD y);
248
 
249
/*
250
 * Clip a line segment for arc or pie drawing.
251
 * Returns 0 if line is clipped or on acceptable side, 1 if it's vertically
252
 * on other side, otherwise 3.
253
 */
254
static int
255
clip_line(SLICE *slice, MWCOORD xe, MWCOORD ye, int dir, MWCOORD y, MWCOORD *x0,
256
        MWCOORD *x1)
257
{
258
#if 0
259
        /*
260
         * kluge: handle 180 degree case
261
         */
262
        if (y >= 0 && ye == 0) {
263
/*printf("cl %d,%d %d,%d %d,%d %d,%d %d,%d\n", xe, ye, y, dir,
264
slice->ax, slice->ay, slice->bx, slice->by, slice->adir, slice->bdir);*/
265
                /* bottom 180*/
266
                if (slice->adir < 0) {
267
                        if (slice->ay || slice->by)
268
                                return 1;
269
                        if (slice->ax == -slice->bx)
270
                                return 0;
271
                }
272
                return 3;
273
        }
274
#endif
275
        /* hline on the same vertical side with the given edge? */
276
        if ((y >= 0 && ye >= 0) || (y < 0 && ye < 0)) {
277
                MWCOORD x;
278
 
279
                if (ye == 0) x = xe; else
280
                x = (MWCOORD)(long)xe * y / ye;
281
 
282
                if (x >= *x0 && x <= *x1) {
283
                        if (dir > 0)
284
                                *x0 = x;
285
                        else
286
                                *x1 = x;
287
                        return 0;
288
                } else {
289
                        if (dir > 0) {
290
                                if (x <= *x0)
291
                                        return 0;
292
                        } else {
293
                                if (x >= *x1)
294
                                        return 0;
295
                        }
296
                }
297
                return 3;
298
        }
299
        return 1;
300
}
301
 
302
/* relative offsets, direction from left to right. */
303
static void
304
draw_line(SLICE *slice, MWCOORD x0, MWCOORD y, MWCOORD x1)
305
{
306
        int     dbl = (slice->adir > 0 && slice->bdir < 0);
307
        int     discard, ret;
308
        MWCOORD x2 = x0, x3 = x1;
309
 
310
        if (y == 0) {
311
                if (slice->type != MWPIE)
312
                        return;
313
                /* edges on different sides */
314
                if ((slice->ay <= 0 && slice->by >= 0) ||
315
                    (slice->ay >= 0 && slice->by <= 0)) {
316
                        if (slice->adir < 0)  {
317
                                if (x1 > 0)
318
                                        x1 = 0;
319
                        }
320
                        if (slice->bdir > 0) {
321
                                if (x0 < 0)
322
                                        x0 = 0;
323
                        }
324
                } else {
325
                        if (!dbl) {
326
                                /* FIXME leaving in draws dot in center*/
327
                                drawpoint(slice->psd, slice->x0, slice->y0);
328
                                return;
329
                        }
330
                }
331
                drawrow(slice->psd, slice->x0 + x0, slice->x0 + x1, slice->y0);
332
                return;
333
        }
334
 
335
        /* clip left edge / line */
336
        ret = clip_line(slice, slice->ax, slice->ay, slice->adir, y, &x0, &x1);
337
 
338
        if (dbl) {
339
                if (!ret) {
340
                        /* edges separate line to two parts */
341
                        drawrow(slice->psd, slice->x0 + x0, slice->x0 + x1,
342
                                slice->y0 + y);
343
                        x0 = x2;
344
                        x1 = x3;
345
                }
346
        } else {
347
                if (ret > 1) {
348
                        return;
349
                }
350
        }
351
 
352
        discard = ret;
353
        ret = clip_line(slice, slice->bx, slice->by, slice->bdir, y, &x0, &x1);
354
 
355
        discard += ret;
356
        if (discard > 2 && !(dbl && ret == 0 && discard == 3)) {
357
                return;
358
        }
359
        if (discard == 2) {
360
                /* line on other side than slice */
361
                if (slice->adir < 0 || slice->bdir > 0) {
362
                        return;
363
                }
364
        }
365
        drawrow(slice->psd, slice->x0 + x0, slice->x0 + x1, slice->y0 + y);
366
}
367
 
368
/* draw one line segment or set of points, called from drawarc routine*/
369
static void
370
drawarcsegment(SLICE *slice, MWCOORD xp, MWCOORD yp)
371
{
372
        switch (slice->type) {
373
        case MWELLIPSEFILL:
374
                /* draw ellipse fill segment*/
375
                drawrow(slice->psd, slice->x0-xp, slice->x0+xp, slice->y0-yp);
376
                drawrow(slice->psd, slice->x0-xp, slice->x0+xp, slice->y0+yp);
377
                return;
378
 
379
        case MWELLIPSE:
380
                /* set four points symmetrically situated around a point*/
381
                drawpoint(slice->psd, slice->x0 + xp, slice->y0 + yp);
382
                drawpoint(slice->psd, slice->x0 - xp, slice->y0 + yp);
383
                drawpoint(slice->psd, slice->x0 + xp, slice->y0 - yp);
384
                drawpoint(slice->psd, slice->x0 - xp, slice->y0 - yp);
385
                return;
386
 
387
        case MWPIE:
388
                /* draw top and bottom halfs of pie*/
389
                draw_line(slice, -xp, -yp, +xp);
390
                draw_line(slice, -xp, +yp, +xp);
391
                return;
392
 
393
        default:        /* MWARC, MWARCOUTLINE*/
394
                /* set four points symmetrically around a point and clip*/
395
                draw_line(slice, +xp, +yp, +xp);
396
                draw_line(slice, -xp, +yp, -xp);
397
                draw_line(slice, +xp, -yp, +xp);
398
                draw_line(slice, -xp, -yp, -xp);
399
                return;
400
        }
401
}
402
 
403
/* General routine to plot points on an arc.  Used by arc, pie and ellipse*/
404
static void
405
drawarc(SLICE *slice)
406
{
407
        MWCOORD xp, yp;         /* current point (based on center) */
408
        MWCOORD rx, ry;
409
        long Asquared;          /* square of x semi axis */
410
        long TwoAsquared;
411
        long Bsquared;          /* square of y semi axis */
412
        long TwoBsquared;
413
        long d;
414
        long dx, dy;
415
 
416
        rx = slice->rx;
417
        ry = slice->ry;
418
 
419
        xp = 0;
420
        yp = ry;
421
        Asquared = rx * rx;
422
        TwoAsquared = 2 * Asquared;
423
        Bsquared = ry * ry;
424
        TwoBsquared = 2 * Bsquared;
425
        d = Bsquared - Asquared * ry + (Asquared >> 2);
426
        dx = 0;
427
        dy = TwoAsquared * ry;
428
 
429
        while (dx < dy) {
430
                drawarcsegment(slice, xp, yp);
431
                if (d > 0) {
432
                        yp--;
433
                        dy -= TwoAsquared;
434
                        d -= dy;
435
                }
436
                xp++;
437
                dx += TwoBsquared;
438
                d += (Bsquared + dx);
439
        }
440
 
441
        d += ((3L * (Asquared - Bsquared) / 2L - (dx + dy)) >> 1);
442
 
443
        while (yp >= 0) {
444
                drawarcsegment(slice, xp, yp);
445
                if (d < 0) {
446
                        xp++;
447
                        dx += TwoBsquared;
448
                        d += dx;
449
                }
450
                yp--;
451
                dy -= TwoAsquared;
452
                d += (Asquared - dy);
453
        }
454
 
455
}
456
 
457
/*
458
 * Draw an arc or pie using start/end points.
459
 * Integer only routine.  To specify start/end angles,
460
 * use GdArcAngle, which requires floating point.
461
 */
462
void
463
GdArc(PSD psd, MWCOORD x0, MWCOORD y0, MWCOORD rx, MWCOORD ry,
464
        MWCOORD ax, MWCOORD ay, MWCOORD bx, MWCOORD by, int type)
465
{
466
        MWCOORD adir, bdir;
467
        SLICE   slice;
468
 
469
        if (rx <= 0 || ry <= 0)
470
                return;
471
 
472
        /*
473
         * Calculate right/left side clipping, based on quadrant.
474
         * dir is positive when right side is filled and negative when
475
         * left side is to be filled.
476
         *
477
         * >= 0 is bottom half
478
         */
479
        if (ay >= 0)
480
                adir = 1;
481
        else
482
                adir = -1;
483
 
484
        if (by >= 0)
485
                bdir = -1;
486
        else
487
                bdir = 1;
488
 
489
        /*
490
         * The clip_line routine has problems around the 0 and
491
         * 180 degree axes.
492
         * This <fix> is required to make the clip_line algorithm
493
         * work.  Getting these routines to work for all angles is
494
         * a bitch.  And they're still buggy.  Doing this causes
495
         * half circles to be outlined with a slightly bent line
496
         * on the x axis. FIXME
497
         */
498
        if (ay == 0) ++ay;
499
        if (by == 0) ++by;
500
 
501
        /* swap rightmost edge first */
502
        if (bx > ax) {
503
                MWCOORD swap;
504
 
505
                swap = ax;
506
                ax = bx;
507
                bx = swap;
508
 
509
                swap = ay;
510
                ay = by;
511
                by = swap;
512
 
513
                swap = adir;
514
                adir = bdir;
515
                bdir = swap;
516
        }
517
 
518
        /* check for entire area clipped, draw with per-point clipping*/
519
        if (GdClipArea(psd, x0-rx, y0-ry, x0+rx, y0+ry) == CLIP_INVISIBLE)
520
                return;
521
 
522
        slice.psd = psd;
523
        slice.x0 = x0;
524
        slice.y0 = y0;
525
        slice.rx = rx;
526
        slice.ry = ry;
527
        slice.ax = ax;
528
        slice.ay = ay;
529
        slice.bx = bx;
530
        slice.by = by;
531
        slice.adir = adir;
532
        slice.bdir = bdir;
533
        slice.type = type;
534
 
535
        drawarc(&slice);
536
 
537
        if (type & MWOUTLINE) {
538
                /* draw two lines from rx,ry to arc endpoints*/
539
                GdLine(psd, x0, y0, x0+ax, y0+ay, TRUE);
540
                GdLine(psd, x0, y0, x0+bx, y0+by, TRUE);
541
        }
542
 
543
        GdFixCursor(psd);
544
}
545
 
546
/*
547
 * Draw an ellipse using the current clipping region and foreground color.
548
 * This draws in the outline of the ellipse, or fills it.
549
 * Integer only routine.
550
 */
551
void
552
GdEllipse(PSD psd, MWCOORD x, MWCOORD y, MWCOORD rx, MWCOORD ry, MWBOOL fill)
553
{
554
        SLICE   slice;
555
 
556
        if (rx < 0 || ry < 0)
557
                return;
558
 
559
        /* Check if the ellipse bounding box is either totally visible
560
         * or totally invisible.  Draw with per-point clipping.
561
         */
562
        switch (GdClipArea(psd, x - rx, y - ry, x + rx, y + ry)) {
563
        case CLIP_VISIBLE:
564
                /*
565
                 * For size considerations, there's no low-level ellipse
566
                 * draw, so we've got to draw all ellipses
567
                 * with per-point clipping for the time being
568
                psd->DrawEllipse(psd, x, y, rx, ry, fill, gr_foreground);
569
                GdFixCursor(psd);
570
                return;
571
                 */
572
                break;
573
 
574
        case CLIP_INVISIBLE:
575
                return;
576
        }
577
 
578
        slice.psd = psd;
579
        slice.x0 = x;
580
        slice.y0 = y;
581
        slice.rx = rx;
582
        slice.ry = ry;
583
        slice.type = fill? MWELLIPSEFILL: MWELLIPSE;
584
        /* other elements unused*/
585
 
586
        drawarc(&slice);
587
 
588
        GdFixCursor(psd);
589
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.