Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3584 sourcerer 1
/*
2
 * Copyright 2009 Vincent Sanders 
3
 * Copyright 2009 Michael Drake 
4
 *
5
 * This file is part of libnsfb, http://www.netsurf-browser.org/
6
 * Licenced under the MIT License,
7
 *                http://www.opensource.org/licenses/mit-license.php
8
 */
9
 
10
/** \file
11
 * generic plotter functions which are not depth dependant (implementation).
12
 */
13
 
14
#include 
15
#include 
16
#include 
17
#include 
18
 
19
#include "libnsfb.h"
20
#include "libnsfb_plot.h"
21
#include "libnsfb_plot_util.h"
22
 
23
#include "nsfb.h"
24
#include "plot.h"
25
#include "surface.h"
26
 
27
extern const nsfb_plotter_fns_t _nsfb_1bpp_plotters;
28
extern const nsfb_plotter_fns_t _nsfb_8bpp_plotters;
29
extern const nsfb_plotter_fns_t _nsfb_16bpp_plotters;
30
extern const nsfb_plotter_fns_t _nsfb_24bpp_plotters;
31
extern const nsfb_plotter_fns_t _nsfb_32bpp_xrgb8888_plotters;
32
extern const nsfb_plotter_fns_t _nsfb_32bpp_xbgr8888_plotters;
33
 
34
static bool set_clip(nsfb_t *nsfb, nsfb_bbox_t *clip)
35
{
36
    nsfb_bbox_t fbarea;
37
 
38
    /* screen area */
39
    fbarea.x0 = 0;
40
    fbarea.y0 = 0;
41
    fbarea.x1 = nsfb->width;
42
    fbarea.y1 = nsfb->height;
43
 
44
    if (clip == NULL) {
45
        nsfb->clip = fbarea;
46
    } else {
47
        if (!nsfb_plot_clip(&fbarea, clip))
48
            return false;
49
 
50
        nsfb->clip = *clip;
51
    }
52
    return true;
53
}
54
 
55
static bool get_clip(nsfb_t *nsfb, nsfb_bbox_t *clip)
56
{
57
    *clip = nsfb->clip;
58
    return true;
59
}
60
 
61
static bool clg(nsfb_t *nsfb, nsfb_colour_t c)
62
{
63
    return nsfb->plotter_fns->fill(nsfb, &nsfb->clip, c);
64
}
65
 
66
/**
67
 * Establish whether there is any value in a line's crossing.
68
 * (Helper function for find_span().)
69
 *
70
 * \param  x	 x coordinate of intersection
71
 * \param  y	 current y level
72
 * \param  x0	 line start coordinate
73
 * \param  y0	 line start coordinate
74
 * \param  x1	 line end coordinate
75
 * \param  y1	 line end coordinate
76
 * \return true	 if crossing has value
77
 *
78
 *                         +            |                             | /
79
 *                        /             |                             |/
80
 *   y level --      ----/----      ----+----      ----+----      ----+----
81
 *                      /              /              /|
82
 *                     +             /               / |
83
 *
84
 *                      (a)            (b)            (c)            (d)
85
 *
86
 *
87
 * Figure (a) values:  1     = 1  --  Odd  -- Valid crossing
88
 * Figure (b) values:  0 + 1 = 1  --  Odd  -- Valid crossing
89
 * Figure (c) values:  1 + 1 = 2  --  Even -- Not valid crossing
90
 * Figure (d) values:  0 + 0 = 0  --  Even -- Not valid crossing
91
 *
92
 * Vertices are shared between consecutive lines.  This function ensures that
93
 * the vertex point is only counted as a crossing for one of the lines by
94
 * only considering crossings of the top vertex.  This is what NetSurf's
95
 * plotter API expects.
96
 *
97
 * It's up to the client to call this function for both lines and check the
98
 * evenness of the total.
99
 */
100
static bool establish_crossing_value(int x, int y, int x0, int y0,
101
				     int x1, int y1)
102
{
103
    bool v1 = (x == x0 && y == y0); /* whether we're crossing 1st vertex */
104
    bool v2 = (x == x1 && y == y1); /* whether we're crossing 2nd vertex */
105
 
106
    if ((v1 && (y0 < y1)) || (v2 && (y1 < y0))) {
107
	/* crossing top vertex */
108
	return true;
109
    } else if (!v1 && !v2) {
110
	/* Intersection with current y level is not at a vertex.
111
	 * Normal crossing. */
112
	return true;
113
    }
114
    return false;
115
}
116
 
117
 
118
/**
119
 * Find first filled span along horizontal line at given coordinate
120
 *
121
 * \param  p	 array of polygon vertices (x1, y1, x2, y2, ... , xN, yN)
122
 * \param  n	 number of polygon vertex values (N * 2)
123
 * \param  x	 current position along current scan line
124
 * \param  y	 position of current scan line
125
 * \param  x0	 updated to start of filled area
126
 * \param  x1	 updated to end of filled area
127
 * \return true	 if an intersection was found
128
 */
129
static bool find_span(const int *p, int n, int x, int y, int *x0, int *x1)
130
{
131
    int i;
132
    int p_x0, p_y0;
133
    int p_x1, p_y1;
134
    int x0_min, x1_min;
135
    int x_new;
136
    unsigned int x0c, x1c; /* counters for crossings at span end points */
137
    bool crossing_value;
138
    bool found_span_start = false;
139
 
140
    x0_min = x1_min = INT_MIN;
141
    x0c = x1c = 0;
142
    *x0 = *x1 = INT_MAX;
143
 
144
    /* search row for next span, returning it if one exists */
145
    do {
146
	/* reset endpoint info, if valid span endpoints not found */
147
	if (!found_span_start)
148
	    *x0 = INT_MAX;
149
	*x1 = INT_MAX;
150
 
151
	/* search all lines in polygon */
152
	for (i = 0; i < n; i = i + 2) {
153
	    /* get line endpoints */
154
	    if (i != n - 2) {
155
		/* not the last line */
156
		p_x0 = p[i];		p_y0 = p[i + 1];
157
		p_x1 = p[i + 2];	p_y1 = p[i + 3];
158
	    } else {
159
		/* last line; 2nd endpoint is first vertex */
160
		p_x0 = p[i];		p_y0 = p[i + 1];
161
		p_x1 = p[0];		p_y1 = p[1];
162
	    }
163
	    /* ignore horizontal lines */
164
	    if (p_y0 == p_y1)
165
		continue;
166
 
167
	    /* ignore lines that don't cross this y level */
168
	    if ((y < p_y0 && y < p_y1) || (y > p_y0 && y > p_y1))
169
		continue;
170
 
171
	    if (p_x0 == p_x1) {
172
		/* vertical line, x is constant */
173
		x_new = p_x0;
174
	    } else {
175
		/* find crossing (intersection of this line and
176
		 * current y level) */
177
		int num = (y - p_y0) * (p_x1 - p_x0);
178
		int den = (p_y1 - p_y0);
179
 
180
		/* To round to nearest (rather than down)
181
		 * half the denominator is either added to
182
		 * or subtracted from the numerator,
183
		 * depending on whether the numerator and
184
		 * denominator have the same sign. */
185
		num = ((num < 0) == (den < 0)) ?
186
		    num + (den / 2) :
187
		    num - (den / 2);
188
		x_new = p_x0 + num / den;
189
	    }
190
 
191
	    /* ignore crossings before current x */
192
	    if (x_new < x ||
193
		(!found_span_start && x_new < x0_min) ||
194
		(found_span_start && x_new < x1_min))
195
		continue;
196
 
197
	    crossing_value = establish_crossing_value(x_new, y,
198
						      p_x0, p_y0, p_x1, p_y1);
199
 
200
 
201
	    /* set nearest intersections as filled area endpoints */
202
	    if (!found_span_start &&
203
		x_new < *x0 && crossing_value) {
204
		/* nearer than first endpoint */
205
		*x1 = *x0;
206
		x1c = x0c;
207
		*x0 = x_new;
208
		x0c = 1;
209
	    } else if (!found_span_start &&
210
		       x_new == *x0 && crossing_value) {
211
		/* same as first endpoint */
212
		x0c++;
213
	    } else if (x_new < *x1 && crossing_value) {
214
		/* nearer than second endpoint */
215
		*x1 = x_new;
216
		x1c = 1;
217
	    } else if (x_new == *x1 && crossing_value) {
218
		/* same as second endpoint */
219
		x1c++;
220
	    }
221
	}
222
	/* check whether the span endpoints have been found */
223
	if (!found_span_start && x0c % 2 == 1) {
224
	    /* valid fill start found */
225
	    found_span_start = true;
226
 
227
	}
228
	if (x1c % 2 == 1) {
229
	    /* valid fill endpoint found */
230
	    if (!found_span_start) {
231
		/* not got a start yet; use this as start */
232
		found_span_start = true;
233
		x0c = x1c;
234
		*x0 = *x1;
235
	    } else {
236
		/* got valid end of span */
237
		return true;
238
	    }
239
	}
240
	/* if current positions aren't valid endpoints, set new
241
	 * minimums after current positions */
242
	if (!found_span_start)
243
	    x0_min = *x0 + 1;
244
	x1_min = *x1 + 1;
245
 
246
    } while (*x1 != INT_MAX);
247
 
248
    /* no spans found */
249
    return false;
250
}
251
 
252
 
253
/**
254
 * Plot a polygon
255
 *
256
 * \param  nsfb	 framebuffer context
257
 * \param  p	 array of polygon vertices (x1, y1, x2, y2, ... , xN, yN)
258
 * \param  n	 number of polygon vertices (N)
259
 * \param  c	 fill colour
260
 * \return true	 if no errors
261
 */
262
static bool polygon(nsfb_t *nsfb, const int *p, unsigned int n, nsfb_colour_t c)
263
{
264
    int poly_x0, poly_y0; /* Bounding box top left corner */
265
    int poly_x1, poly_y1; /* Bounding box bottom right corner */
266
    int i, j; /* indexes */
267
    int x0, x1; /* filled span extents */
268
    int y; /* current y coordinate */
269
    int y_max; /* bottom of plot area */
270
    nsfb_bbox_t fline;
271
    nsfb_plot_pen_t pen;
272
 
273
    /* find no. of vertex values */
274
    int v = n * 2;
275
 
276
    /* Can't plot polygons with 2 or fewer vertices */
277
    if (n <= 2)
278
	return true;
279
 
280
    pen.stroke_colour = c;
281
 
282
    /* Find polygon bounding box */
283
    poly_x0 = poly_x1 = *p;
284
    poly_y0 = poly_y1 = p[1];
285
    for (i = 2; i < v; i = i + 2) {
286
	j = i + 1;
287
	if (p[i] < poly_x0)
288
	    poly_x0 = p[i];
289
	else if (p[i] > poly_x1)
290
	    poly_x1 = p[i];
291
	if (p[j] < poly_y0)
292
	    poly_y0 = p[j];
293
	else if (p[j] > poly_y1)
294
	    poly_y1 = p[j];
295
    }
296
 
297
    /* Don't try to plot it if it's outside the clip rectangle */
298
    if (nsfb->clip.y1 < poly_y0 ||
299
	nsfb->clip.y0 > poly_y1 ||
300
	nsfb->clip.x1 < poly_x0 ||
301
	nsfb->clip.x0 > poly_x1)
302
	return true;
303
 
304
    /* Find the top of the important area */
305
    if (poly_y0 > nsfb->clip.y0)
306
	y = poly_y0;
307
    else
308
	y = nsfb->clip.y0;
309
 
310
    /* Find the bottom of the important area */
311
    if (poly_y1 < nsfb->clip.y1)
312
	y_max = poly_y1;
313
    else
314
	y_max = nsfb->clip.y1;
315
 
316
    for (; y < y_max; y++) {
317
	x1 = poly_x0 - 1;
318
	/* For each row */
319
	while (find_span(p, v, x1 + 1, y, &x0, &x1)) {
320
	    /* don't draw anything outside clip region */
321
	    if (x1 < nsfb->clip.x0)
322
		continue;
323
	    else if (x0 < nsfb->clip.x0)
324
		x0 = nsfb->clip.x0;
325
	    if (x0 > nsfb->clip.x1)
326
		break;
327
	    else if (x1 > nsfb->clip.x1)
328
		x1 = nsfb->clip.x1;
329
 
330
	    fline.x0 = x0;
331
	    fline.y0 = y;
332
	    fline.x1 = x1;
333
	    fline.y1 = y;
334
 
335
	    /* draw this filled span on current row */
336
	    nsfb->plotter_fns->line(nsfb, 1, &fline, &pen);
337
 
338
	    /* don't look for more spans if already at end of clip
339
	     * region or polygon */
340
	    if (x1 == nsfb->clip.x1 || x1 == poly_x1)
341
		break;
342
	}
343
    }
344
    return true;
345
}
346
 
347
static bool
348
rectangle(nsfb_t *nsfb, nsfb_bbox_t *rect,
349
	  int line_width, nsfb_colour_t c,
350
	  bool dotted, bool dashed)
351
{
352
    nsfb_bbox_t side[4];
353
    nsfb_plot_pen_t pen;
354
 
355
    pen.stroke_colour = c;
356
    pen.stroke_width = line_width;
357
    if (dotted || dashed) {
358
	pen.stroke_type = NFSB_PLOT_OPTYPE_PATTERN;
359
    } else {
360
	pen.stroke_type = NFSB_PLOT_OPTYPE_SOLID;
361
    }
362
 
363
    side[0] = *rect;
364
    side[1] = *rect;
365
    side[2] = *rect;
366
    side[3] = *rect;
367
 
368
    side[0].y1 = side[0].y0;
369
    side[1].y0 = side[1].y1;
370
    side[2].x1 = side[2].x0;
371
    side[3].x0 = side[3].x1;
372
 
373
    return nsfb->plotter_fns->line(nsfb, 4, side, &pen);
374
}
375
 
376
/* plotter routine for ellipse points */
377
static void
378
ellipsepoints(nsfb_t *nsfb, int cx, int cy, int x, int y, nsfb_colour_t c)
379
{
380
    nsfb->plotter_fns->point(nsfb, cx + x, cy + y, c);
381
    nsfb->plotter_fns->point(nsfb, cx - x, cy + y, c);
382
    nsfb->plotter_fns->point(nsfb, cx + x, cy - y, c);
383
    nsfb->plotter_fns->point(nsfb, cx - x, cy - y, c);
384
}
385
 
386
static void
387
ellipsefill(nsfb_t *nsfb, int cx, int cy, int x, int y, nsfb_colour_t c)
388
{
389
    nsfb_bbox_t fline[2];
390
    nsfb_plot_pen_t pen;
391
 
392
    pen.stroke_colour = c;
393
 
394
    fline[0].x0 = fline[1].x0 = cx - x;
395
    fline[0].x1 = fline[1].x1 = cx + x;
396
    fline[0].y0 = fline[0].y1 = cy + y;
397
    fline[1].y0 = fline[1].y1 = cy - y;
398
 
399
    nsfb->plotter_fns->line(nsfb, 2, fline, &pen);
400
 
401
}
402
 
403
#define ROUND(a) ((int)(a+0.5))
404
 
405
static bool
406
ellipse_midpoint(nsfb_t *nsfb,
407
		 int cx,
408
		 int cy,
409
		 int rx,
410
		 int ry,
411
		 nsfb_colour_t c,
412
		 void (ellipsefn)(nsfb_t *nsfb, int cx, int cy, int x, int y, nsfb_colour_t c))
413
{
414
    int rx2 = rx * rx;
415
    int ry2 = ry * ry;
416
    int tworx2 = 2 * rx2;
417
    int twory2 = 2 * ry2;
418
    int p;
419
    int x = 0;
420
    int y = ry;
421
    int px = 0;
422
    int py = tworx2 * y;
423
 
424
    ellipsefn(nsfb, cx, cy, x, y, c);
425
 
426
    /* region 1 */
427
    p = ROUND(ry2 - (rx2 * ry) + (0.25 * rx2));
428
    while (px < py) {
429
        x++;
430
        px += twory2;
431
        if (p <0) {
432
            p+=ry2 + px;
433
        } else {
434
            y--;
435
            py -= tworx2;
436
            p+=ry2 + px - py;
437
        }
438
        ellipsefn(nsfb, cx, cy, x, y, c);
439
    }
440
 
441
    /* region 2 */
442
    p = ROUND(ry2*(x+0.5)*(x+0.5) + rx2*(y-1)*(y-1) - rx2*ry2);
443
    while (y > 0) {
444
        y--;
445
        py -= tworx2;
446
        if (p > 0) {
447
            p+=rx2 - py;
448
        } else {
449
            x++;
450
            px += twory2;
451
            p+=rx2 - py + px;
452
        }
453
        ellipsefn(nsfb, cx, cy, x, y, c);
454
    }
455
    return true;
456
}
457
 
458
 
459
/* plotter routine for 8way circle symetry */
460
static void
461
circlepoints(nsfb_t *nsfb, int cx, int cy, int x, int y, nsfb_colour_t c)
462
{
463
    nsfb->plotter_fns->point(nsfb, cx + x, cy + y, c);
464
    nsfb->plotter_fns->point(nsfb, cx - x, cy + y, c);
465
    nsfb->plotter_fns->point(nsfb, cx + x, cy - y, c);
466
    nsfb->plotter_fns->point(nsfb, cx - x, cy - y, c);
467
    nsfb->plotter_fns->point(nsfb, cx + y, cy + x, c);
468
    nsfb->plotter_fns->point(nsfb, cx - y, cy + x, c);
469
    nsfb->plotter_fns->point(nsfb, cx + y, cy - x, c);
470
    nsfb->plotter_fns->point(nsfb, cx - y, cy - x, c);
471
}
472
 
473
static void
474
circlefill(nsfb_t *nsfb, int cx, int cy, int x, int y, nsfb_colour_t c)
475
{
476
    nsfb_bbox_t fline[4];
477
    nsfb_plot_pen_t pen;
478
 
479
    pen.stroke_colour = c;
480
 
481
    fline[0].x0 = fline[1].x0 = cx - x;
482
    fline[0].x1 = fline[1].x1 = cx + x;
483
    fline[0].y0 = fline[0].y1 = cy + y;
484
    fline[1].y0 = fline[1].y1 = cy - y;
485
 
486
    fline[2].x0 = fline[3].x0 = cx - y;
487
    fline[2].x1 = fline[3].x1 = cx + y;
488
    fline[2].y0 = fline[2].y1 = cy + x;
489
    fline[3].y0 = fline[3].y1 = cy - x;
490
 
491
    nsfb->plotter_fns->line(nsfb, 4, fline, &pen);
492
}
493
 
494
static bool circle_midpoint(nsfb_t *nsfb,
495
                            int cx,
496
                            int cy,
497
                            int r,
498
                            nsfb_colour_t c,
499
                            void (circfn)(nsfb_t *nsfb, int cx, int cy, int x, int y, nsfb_colour_t c))
500
{
501
    int x = 0;
502
    int y = r;
503
    int p = 1 - r;
504
 
505
    circfn(nsfb, cx, cy, x, y, c);
506
    while (x < y) {
507
        x++;
508
        if (p < 0) {
509
            p += 2 * x + 1;
510
        } else {
511
            y--;
512
            p += 2 * (x - y) + 1;
513
        }
514
        circfn(nsfb, cx, cy, x, y, c);
515
    }
516
    return true;
517
}
518
 
519
static bool ellipse(nsfb_t *nsfb, nsfb_bbox_t *ellipse, nsfb_colour_t c)
520
{
521
    int width = (ellipse->x1 - ellipse->x0)>>1;
522
    int height = (ellipse->y1 - ellipse->y0)>>1;
523
 
524
    if (width == height) {
525
        /* circle */
526
        return circle_midpoint(nsfb, ellipse->x0 + width, ellipse->y0 + height, width, c, circlepoints);
527
    } else {
528
        return ellipse_midpoint(nsfb, ellipse->x0 + width, ellipse->y0 + height, width, height, c, ellipsepoints);
529
    }
530
}
531
 
532
static bool ellipse_fill(nsfb_t *nsfb, nsfb_bbox_t *ellipse, nsfb_colour_t c)
533
{
534
    int width = (ellipse->x1 - ellipse->x0) >> 1;
535
    int height = (ellipse->y1 - ellipse->y0) >> 1;
536
 
537
    if (width == height) {
538
        /* circle */
539
        return circle_midpoint(nsfb, ellipse->x0 + width, ellipse->y0 + height, width, c, circlefill);
540
    } else {
541
        return ellipse_midpoint(nsfb, ellipse->x0 + width, ellipse->y0 + height, width, height, c, ellipsefill);
542
    }
543
}
544
 
545
 
546
 
547
/* copy an area of surface from one location to another.
548
 *
549
 * @warning This implementation is woefully incomplete!
550
 */
551
static bool
552
copy(nsfb_t *nsfb, nsfb_bbox_t *srcbox, nsfb_bbox_t *dstbox)
553
{
554
    int srcx = srcbox->x0;
555
    int srcy = srcbox->y0;
556
    int dstx = dstbox->x0;
557
    int dsty = dstbox->y0;
558
    int width = dstbox->x1 - dstbox->x0;
559
    int height = dstbox->y1 - dstbox->y0;
560
    uint8_t *srcptr;
561
    uint8_t *dstptr;
562
    int hloop;
563
    nsfb_bbox_t allbox;
564
 
565
    nsfb_plot_add_rect(srcbox, dstbox, &allbox);
566
 
567
    nsfb->surface_rtns->claim(nsfb, &allbox);
568
 
569
    srcptr = (nsfb->ptr +
570
              (srcy * nsfb->linelen) +
571
              ((srcx * nsfb->bpp) / 8));
572
 
573
    dstptr = (nsfb->ptr +
574
              (dsty * nsfb->linelen) +
575
              ((dstx * nsfb->bpp) / 8));
576
 
577
 
578
    if (width == nsfb->width) {
579
        /* take shortcut and use memmove */
580
        memmove(dstptr, srcptr, (width * height * nsfb->bpp) / 8);
581
    } else {
582
        if (srcy > dsty) {
583
            for (hloop = height; hloop > 0; hloop--) {
584
                memmove(dstptr, srcptr, (width * nsfb->bpp) / 8);
585
                srcptr += nsfb->linelen;
586
                dstptr += nsfb->linelen;
587
            }
588
        } else {
589
            srcptr += height * nsfb->linelen;
590
            dstptr += height * nsfb->linelen;
591
            for (hloop = height; hloop > 0; hloop--) {
592
                srcptr -= nsfb->linelen;
593
                dstptr -= nsfb->linelen;
594
                memmove(dstptr, srcptr, (width * nsfb->bpp) / 8);
595
            }
596
        }
597
    }
598
 
599
    nsfb->surface_rtns->update(nsfb, dstbox);
600
 
601
    return true;
602
}
603
 
604
 
605
 
606
static bool arc(nsfb_t *nsfb, int x, int y, int radius, int angle1, int angle2, nsfb_colour_t c)
607
{
608
    nsfb=nsfb;
609
    x = x;
610
    y = y;
611
    radius = radius;
612
    c = c;
613
    angle1=angle1;
614
    angle2=angle2;
615
    return true;
616
}
617
 
618
#define N_SEG 30
619
 
620
static int
621
cubic_points(unsigned int pointc,
622
             nsfb_point_t *point,
623
             nsfb_bbox_t *curve,
624
             nsfb_point_t *ctrla,
625
             nsfb_point_t *ctrlb)
626
{
627
    unsigned int seg_loop;
628
    double t;
629
    double one_minus_t;
630
    double a;
631
    double b;
632
    double c;
633
    double d;
634
    double x;
635
    double y;
636
    int cur_point;
637
 
638
    point[0].x = curve->x0;
639
    point[0].y = curve->y0;
640
    cur_point = 1;
641
    pointc--;
642
 
643
    for (seg_loop = 1; seg_loop < pointc; ++seg_loop) {
644
        t = (double)seg_loop / (double)pointc;
645
 
646
        one_minus_t = 1.0 - t;
647
 
648
        a = one_minus_t * one_minus_t * one_minus_t;
649
        b = 3.0 * t * one_minus_t * one_minus_t;
650
        c = 3.0 * t * t * one_minus_t;
651
        d = t * t * t;
652
 
653
        x = a * curve->x0 + b * ctrla->x + c * ctrlb->x + d * curve->x1;
654
        y = a * curve->y0 + b * ctrla->y + c * ctrlb->y + d * curve->y1;
655
 
656
        point[cur_point].x = x;
657
        point[cur_point].y = y;
658
        if ((point[cur_point].x != point[cur_point - 1].x) ||
659
            (point[cur_point].y != point[cur_point - 1].y))
660
	    cur_point++;
661
    }
662
 
663
    point[cur_point].x = curve->x1;
664
    point[cur_point].y = curve->y1;
665
    if ((point[cur_point].x != point[cur_point - 1].x) ||
666
        (point[cur_point].y != point[cur_point - 1].y))
667
	cur_point++;
668
 
669
    return cur_point;
670
}
671
 
672
/* calculate a series of points which describe a quadratic bezier spline.
673
 *
674
 * fills an array of points with values describing a quadratic curve. Both the
675
 * start and end points are included as the first and last points
676
 * respectively. Only if the next point on the curve is different from its
677
 * predecessor is the point added which ensures points for the same position
678
 * are not repeated.
679
 */
680
static int
681
quadratic_points(unsigned int pointc,
682
                 nsfb_point_t *point,
683
                 nsfb_bbox_t *curve,
684
                 nsfb_point_t *ctrla)
685
{
686
    unsigned int seg_loop;
687
    double t;
688
    double one_minus_t;
689
    double a;
690
    double b;
691
    double c;
692
    double x;
693
    double y;
694
    int cur_point;
695
 
696
    point[0].x = curve->x0;
697
    point[0].y = curve->y0;
698
    cur_point = 1;
699
    pointc--; /* we have added the start point, one less point in the curve */
700
 
701
    for (seg_loop = 1; seg_loop < pointc; ++seg_loop) {
702
        t = (double)seg_loop / (double)pointc;
703
 
704
        one_minus_t = 1.0 - t;
705
 
706
        a = one_minus_t * one_minus_t;
707
        b = 2.0 * t * one_minus_t;
708
        c = t * t;
709
 
710
        x = a * curve->x0 + b * ctrla->x + c * curve->x1;
711
        y = a * curve->y0 + b * ctrla->y + c * curve->y1;
712
 
713
        point[cur_point].x = x;
714
        point[cur_point].y = y;
715
        if ((point[cur_point].x != point[cur_point - 1].x) ||
716
            (point[cur_point].y != point[cur_point - 1].y))
717
	    cur_point++;
718
    }
719
 
720
    point[cur_point].x = curve->x1;
721
    point[cur_point].y = curve->y1;
722
    if ((point[cur_point].x != point[cur_point - 1].x) ||
723
        (point[cur_point].y != point[cur_point - 1].y))
724
	cur_point++;
725
 
726
    return cur_point;
727
}
728
 
729
static bool
730
polylines(nsfb_t *nsfb,
731
          int pointc,
732
          const nsfb_point_t *points,
733
          nsfb_plot_pen_t *pen)
734
{
735
    int point_loop;
736
    nsfb_bbox_t line;
737
 
738
    if (pen->stroke_type != NFSB_PLOT_OPTYPE_NONE) {
739
        for (point_loop = 0; point_loop < (pointc - 1); point_loop++) {
740
            line = *(nsfb_bbox_t *)&points[point_loop];
741
            nsfb->plotter_fns->line(nsfb, 1, &line, pen);
742
	}
743
    }
744
    return true;
745
}
746
 
747
 
748
 
749
static bool
750
quadratic(nsfb_t *nsfb,
751
          nsfb_bbox_t *curve,
752
          nsfb_point_t *ctrla,
753
          nsfb_plot_pen_t *pen)
754
{
755
    nsfb_point_t points[N_SEG];
756
 
757
    if (pen->stroke_type == NFSB_PLOT_OPTYPE_NONE)
758
        return false;
759
 
760
    return polylines(nsfb, quadratic_points(N_SEG, points, curve, ctrla), points, pen);
761
}
762
 
763
static bool
764
cubic(nsfb_t *nsfb,
765
      nsfb_bbox_t *curve,
766
      nsfb_point_t *ctrla,
767
      nsfb_point_t *ctrlb,
768
      nsfb_plot_pen_t *pen)
769
{
770
    nsfb_point_t points[N_SEG];
771
 
772
    if (pen->stroke_type == NFSB_PLOT_OPTYPE_NONE)
773
        return false;
774
 
775
    return polylines(nsfb, cubic_points(N_SEG, points, curve, ctrla,ctrlb), points, pen);
776
}
777
 
778
 
779
static bool
780
path(nsfb_t *nsfb, int pathc, nsfb_plot_pathop_t *pathop, nsfb_plot_pen_t *pen)
781
{
782
    int path_loop;
783
    nsfb_point_t *pts;
784
    nsfb_point_t *curpt;
785
    int ptc = 0;
786
    nsfb_bbox_t curve;
787
    nsfb_point_t ctrla;
788
    nsfb_point_t ctrlb;
789
    int added_count = 0;
790
    int bpts;
791
 
792
    /* count the verticies in the path and add N_SEG extra for curves */
793
    for (path_loop = 0; path_loop < pathc; path_loop++) {
794
        ptc++;
795
        if ((pathop[path_loop].operation == NFSB_PLOT_PATHOP_QUAD) ||
796
            (pathop[path_loop].operation == NFSB_PLOT_PATHOP_CUBIC))
797
            ptc += N_SEG;
798
    }
799
 
800
    /* allocate storage for the vertexes */
801
    curpt = pts = malloc(ptc * sizeof(nsfb_point_t));
802
 
803
    for (path_loop = 0; path_loop < pathc; path_loop++) {
804
        switch (pathop[path_loop].operation) {
805
        case NFSB_PLOT_PATHOP_QUAD:
806
            curpt-=2;
807
            added_count -= 2;
808
            curve.x0 = pathop[path_loop - 2].point.x;
809
            curve.y0 = pathop[path_loop - 2].point.y;
810
            ctrla.x = pathop[path_loop - 1].point.x;
811
            ctrla.y = pathop[path_loop - 1].point.y;
812
            curve.x1 = pathop[path_loop].point.x;
813
            curve.y1 = pathop[path_loop].point.y;
814
            bpts = quadratic_points(N_SEG, curpt, &curve, &ctrla);
815
            curpt += bpts;
816
            added_count += bpts;
817
            break;
818
 
819
        case NFSB_PLOT_PATHOP_CUBIC:
820
            curpt-=3;
821
            added_count -=3;
822
            curve.x0 = pathop[path_loop - 3].point.x;
823
            curve.y0 = pathop[path_loop - 3].point.y;
824
            ctrla.x = pathop[path_loop - 2].point.x;
825
            ctrla.y = pathop[path_loop - 2].point.y;
826
            ctrlb.x = pathop[path_loop - 1].point.x;
827
            ctrlb.y = pathop[path_loop - 1].point.y;
828
            curve.x1 = pathop[path_loop].point.x;
829
            curve.y1 = pathop[path_loop].point.y;
830
            bpts = cubic_points(N_SEG, curpt, &curve, &ctrla, &ctrlb);
831
            curpt += bpts;
832
            added_count += bpts;
833
            break;
834
 
835
        default:
836
            *curpt = pathop[path_loop].point;
837
            curpt++;
838
            added_count ++;
839
            break;
840
        }
841
    }
842
 
843
    if (pen->fill_type != NFSB_PLOT_OPTYPE_NONE) {
844
        polygon(nsfb, (int *)pts, added_count, pen->fill_colour);
845
    }
846
 
847
    if (pen->stroke_type != NFSB_PLOT_OPTYPE_NONE) {
848
        polylines(nsfb, added_count, pts, pen);
849
    }
850
 
851
    free(pts);
852
 
853
    return true;
854
}
855
 
856
bool select_plotters(nsfb_t *nsfb)
857
{
858
    const nsfb_plotter_fns_t *table = NULL;
859
 
860
    switch (nsfb->format) {
861
 
862
    case NSFB_FMT_XBGR8888: /* 32bpp Unused Blue Green Red */
863
    case NSFB_FMT_ABGR8888: /* 32bpp Alpha Blue Green Red */
864
	table = &_nsfb_32bpp_xbgr8888_plotters;
865
	nsfb->bpp = 32;
866
	break;
867
 
868
    case NSFB_FMT_XRGB8888: /* 32bpp Unused Red Green Blue */
869
    case NSFB_FMT_ARGB8888: /* 32bpp Alpha Red Green Blue */
870
	table = &_nsfb_32bpp_xrgb8888_plotters;
871
	nsfb->bpp = 32;
872
	break;
873
 
874
 
875
    case NSFB_FMT_RGB888: /* 24 bpp Alpha Red Green Blue */
876
#ifdef ENABLE_24_BPP
877
	table = &_nsfb_24bpp_plotters;
878
	nsfb->bpp = 24;
879
	break;
880
#else
881
	return false;
882
#endif
883
 
884
    case NSFB_FMT_ARGB1555: /* 16 bpp 555 */
885
    case NSFB_FMT_RGB565: /* 16 bpp 565 */
886
	table = &_nsfb_16bpp_plotters;
887
	nsfb->bpp = 16;
888
	break;
889
 
890
    case NSFB_FMT_I8: /* 8bpp indexed */
891
	table = &_nsfb_8bpp_plotters;
892
	nsfb->bpp = 8;
893
	break;
894
 
895
    case NSFB_FMT_I1: /* black and white */
896
#ifdef ENABLE_1_BPP
897
	table = &_nsfb_1bpp_plotters;
898
	nsfb->bpp = 1
899
	break;
900
#else
901
	return false;
902
#endif
903
 
904
    case NSFB_FMT_ANY: /* No specific format - use surface default */
905
    default:
906
	return false;
907
    }
908
 
909
    if (nsfb->plotter_fns != NULL)
910
	free(nsfb->plotter_fns);
911
 
912
    nsfb->plotter_fns = calloc(1, sizeof(nsfb_plotter_fns_t));
913
    memcpy(nsfb->plotter_fns, table, sizeof(nsfb_plotter_fns_t));
914
 
915
    /* set the generics */
916
    nsfb->plotter_fns->clg = clg;
917
    nsfb->plotter_fns->set_clip = set_clip;
918
    nsfb->plotter_fns->get_clip = get_clip;
919
    nsfb->plotter_fns->polygon = polygon;
920
    nsfb->plotter_fns->rectangle = rectangle;
921
    nsfb->plotter_fns->ellipse = ellipse;
922
    nsfb->plotter_fns->ellipse_fill = ellipse_fill;
923
    nsfb->plotter_fns->copy = copy;
924
    nsfb->plotter_fns->arc = arc;
925
    nsfb->plotter_fns->quadratic = quadratic;
926
    nsfb->plotter_fns->cubic = cubic;
927
    nsfb->plotter_fns->path = path;
928
    nsfb->plotter_fns->polylines = polylines;
929
 
930
    /* set default clip rectangle to size of framebuffer */
931
    nsfb->clip.x0 = 0;
932
    nsfb->clip.y0 = 0;
933
    nsfb->clip.x1 = nsfb->width;
934
    nsfb->clip.y1 = nsfb->height;
935
 
936
    return true;
937
}
938
 
939
/*
940
 * Local variables:
941
 *  c-basic-offset: 4
942
 *  tab-width: 8
943
 * End:
944
 */