Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
4680 right-hear 1
#include "fitz.h"
2
 
3
/*
4
 * polygon clipping
5
 */
6
 
7
enum { IN, OUT, ENTER, LEAVE };
8
enum { MAXV = 3 + 4 };
9
enum { MAXN = 2 + FZ_MAX_COLORS };
10
 
11
static int clipx(float val, int ismax, float *v1, float *v2, int n)
12
{
13
	float t;
14
	int i;
15
	int v1o = ismax ? v1[0] > val : v1[0] < val;
16
	int v2o = ismax ? v2[0] > val : v2[0] < val;
17
	if (v1o + v2o == 0)
18
		return IN;
19
	if (v1o + v2o == 2)
20
		return OUT;
21
	if (v2o)
22
	{
23
		t = (val - v1[0]) / (v2[0] - v1[0]);
24
		v2[0] = val;
25
		v2[1] = v1[1] + t * (v2[1] - v1[1]);
26
		for (i = 2; i < n; i++)
27
			v2[i] = v1[i] + t * (v2[i] - v1[i]);
28
		return LEAVE;
29
	}
30
	else
31
	{
32
		t = (val - v2[0]) / (v1[0] - v2[0]);
33
		v1[0] = val;
34
		v1[1] = v2[1] + t * (v1[1] - v2[1]);
35
		for (i = 2; i < n; i++)
36
			v1[i] = v2[i] + t * (v1[i] - v2[i]);
37
		return ENTER;
38
	}
39
}
40
 
41
static int clipy(float val, int ismax, float *v1, float *v2, int n)
42
{
43
	float t;
44
	int i;
45
	int v1o = ismax ? v1[1] > val : v1[1] < val;
46
	int v2o = ismax ? v2[1] > val : v2[1] < val;
47
	if (v1o + v2o == 0)
48
		return IN;
49
	if (v1o + v2o == 2)
50
		return OUT;
51
	if (v2o)
52
	{
53
		t = (val - v1[1]) / (v2[1] - v1[1]);
54
		v2[0] = v1[0] + t * (v2[0] - v1[0]);
55
		v2[1] = val;
56
		for (i = 2; i < n; i++)
57
			v2[i] = v1[i] + t * (v2[i] - v1[i]);
58
		return LEAVE;
59
	}
60
	else
61
	{
62
		t = (val - v2[1]) / (v1[1] - v2[1]);
63
		v1[0] = v2[0] + t * (v1[0] - v2[0]);
64
		v1[1] = val;
65
		for (i = 2; i < n; i++)
66
			v1[i] = v2[i] + t * (v1[i] - v2[i]);
67
		return ENTER;
68
	}
69
}
70
 
71
static inline void copy_vert(float *dst, float *src, int n)
72
{
73
	while (n--)
74
		*dst++ = *src++;
75
}
76
 
77
static int clip_poly(float src[MAXV][MAXN],
78
	float dst[MAXV][MAXN], int len, int n,
79
	float val, int isy, int ismax)
80
{
81
	float cv1[MAXN];
82
	float cv2[MAXN];
83
	int v1, v2, cp;
84
	int r;
85
 
86
	v1 = len - 1;
87
	cp = 0;
88
 
89
	for (v2 = 0; v2 < len; v2++)
90
	{
91
		copy_vert(cv1, src[v1], n);
92
		copy_vert(cv2, src[v2], n);
93
 
94
		if (isy)
95
			r = clipy(val, ismax, cv1, cv2, n);
96
		else
97
			r = clipx(val, ismax, cv1, cv2, n);
98
 
99
		switch (r)
100
		{
101
		case IN:
102
			copy_vert(dst[cp++], cv2, n);
103
			break;
104
		case OUT:
105
			break;
106
		case LEAVE:
107
			copy_vert(dst[cp++], cv2, n);
108
			break;
109
		case ENTER:
110
			copy_vert(dst[cp++], cv1, n);
111
			copy_vert(dst[cp++], cv2, n);
112
			break;
113
		}
114
		v1 = v2;
115
	}
116
 
117
	return cp;
118
}
119
 
120
/*
121
 * gouraud shaded polygon scan conversion
122
 */
123
 
124
static void paint_scan(fz_pixmap *pix, int y, int x1, int x2, int *v1, int *v2, int n)
125
{
126
	unsigned char *p = pix->samples + ((y - pix->y) * pix->w + (x1 - pix->x)) * pix->n;
127
	int v[FZ_MAX_COLORS];
128
	int dv[FZ_MAX_COLORS];
129
	int w = x2 - x1;
130
	int k;
131
 
132
	assert(w >= 0);
133
	assert(y >= pix->y);
134
	assert(y < pix->y + pix->h);
135
	assert(x1 >= pix->x);
136
	assert(x2 <= pix->x + pix->w);
137
 
138
	if (w == 0)
139
		return;
140
 
141
	for (k = 0; k < n; k++)
142
	{
143
		v[k] = v1[k];
144
		dv[k] = (v2[k] - v1[k]) / w;
145
	}
146
 
147
	while (w--)
148
	{
149
		for (k = 0; k < n; k++)
150
		{
151
			*p++ = v[k] >> 16;
152
			v[k] += dv[k];
153
		}
154
		*p++ = 255;
155
	}
156
}
157
 
158
static int find_next(int gel[MAXV][MAXN], int len, int a, int *s, int *e, int d)
159
{
160
	int b;
161
 
162
	while (1)
163
	{
164
		b = a + d;
165
		if (b == len)
166
			b = 0;
167
		if (b == -1)
168
			b = len - 1;
169
 
170
		if (gel[b][1] == gel[a][1])
171
		{
172
			a = b;
173
			continue;
174
		}
175
 
176
		if (gel[b][1] > gel[a][1])
177
		{
178
			*s = a;
179
			*e = b;
180
			return 0;
181
		}
182
 
183
		return 1;
184
	}
185
}
186
 
187
static void load_edge(int gel[MAXV][MAXN], int s, int e, int *ael, int *del, int n)
188
{
189
	int swp, k, dy;
190
 
191
	if (gel[s][1] > gel[e][1])
192
	{
193
		swp = s; s = e; e = swp;
194
	}
195
 
196
	dy = gel[e][1] - gel[s][1];
197
 
198
	ael[0] = gel[s][0];
199
	del[0] = (gel[e][0] - gel[s][0]) / dy;
200
	for (k = 2; k < n; k++)
201
	{
202
		ael[k] = gel[s][k];
203
		del[k] = (gel[e][k] - gel[s][k]) / dy;
204
	}
205
}
206
 
207
static inline void step_edge(int *ael, int *del, int n)
208
{
209
	int k;
210
	ael[0] += del[0];
211
	for (k = 2; k < n; k++)
212
		ael[k] += del[k];
213
}
214
 
215
static void
216
fz_paint_triangle(fz_pixmap *pix, float *av, float *bv, float *cv, int n, fz_bbox bbox)
217
{
218
	float poly[MAXV][MAXN];
219
	float temp[MAXV][MAXN];
220
	float cx0 = bbox.x0;
221
	float cy0 = bbox.y0;
222
	float cx1 = bbox.x1;
223
	float cy1 = bbox.y1;
224
 
225
	int gel[MAXV][MAXN];
226
	int ael[2][MAXN];
227
	int del[2][MAXN];
228
	int y, s0, s1, e0, e1;
229
	int top, bot, len;
230
 
231
	int i, k;
232
 
233
	copy_vert(poly[0], av, n);
234
	copy_vert(poly[1], bv, n);
235
	copy_vert(poly[2], cv, n);
236
 
237
	len = clip_poly(poly, temp, 3, n, cx0, 0, 0);
238
	len = clip_poly(temp, poly, len, n, cx1, 0, 1);
239
	len = clip_poly(poly, temp, len, n, cy0, 1, 0);
240
	len = clip_poly(temp, poly, len, n, cy1, 1, 1);
241
 
242
	if (len < 3)
243
		return;
244
 
245
	for (i = 0; i < len; i++)
246
	{
247
		gel[i][0] = floorf(poly[i][0] + 0.5f) * 65536; /* trunc and fix */
248
		gel[i][1] = floorf(poly[i][1] + 0.5f);	/* y is not fixpoint */
249
		for (k = 2; k < n; k++)
250
			gel[i][k] = poly[i][k] * 65536;	/* fix with precision */
251
	}
252
 
253
	top = bot = 0;
254
	for (i = 0; i < len; i++)
255
	{
256
		if (gel[i][1] < gel[top][1])
257
			top = i;
258
		if (gel[i][1] > gel[bot][1])
259
			bot = i;
260
	}
261
 
262
	if (gel[bot][1] - gel[top][1] == 0)
263
		return;
264
 
265
	y = gel[top][1];
266
 
267
	if (find_next(gel, len, top, &s0, &e0, 1))
268
		return;
269
	if (find_next(gel, len, top, &s1, &e1, -1))
270
		return;
271
 
272
	load_edge(gel, s0, e0, ael[0], del[0], n);
273
	load_edge(gel, s1, e1, ael[1], del[1], n);
274
 
275
	while (1)
276
	{
277
		int x0 = ael[0][0] >> 16;
278
		int x1 = ael[1][0] >> 16;
279
 
280
		if (ael[0][0] < ael[1][0])
281
			paint_scan(pix, y, x0, x1, ael[0]+2, ael[1]+2, n-2);
282
		else
283
			paint_scan(pix, y, x1, x0, ael[1]+2, ael[0]+2, n-2);
284
 
285
		step_edge(ael[0], del[0], n);
286
		step_edge(ael[1], del[1], n);
287
		y ++;
288
 
289
		if (y >= gel[e0][1])
290
		{
291
			if (find_next(gel, len, e0, &s0, &e0, 1))
292
				return;
293
			load_edge(gel, s0, e0, ael[0], del[0], n);
294
		}
295
 
296
		if (y >= gel[e1][1])
297
		{
298
			if (find_next(gel, len, e1, &s1, &e1, -1))
299
				return;
300
			load_edge(gel, s1, e1, ael[1], del[1], n);
301
		}
302
	}
303
}
304
 
305
static void
306
fz_paint_quad(fz_pixmap *pix,
307
		fz_point p0, fz_point p1, fz_point p2, fz_point p3,
308
		float c0, float c1, float c2, float c3,
309
		int n, fz_bbox bbox)
310
{
311
	float v[4][3];
312
 
313
	v[0][0] = p0.x;
314
	v[0][1] = p0.y;
315
	v[0][2] = c0;
316
 
317
	v[1][0] = p1.x;
318
	v[1][1] = p1.y;
319
	v[1][2] = c1;
320
 
321
	v[2][0] = p2.x;
322
	v[2][1] = p2.y;
323
	v[2][2] = c2;
324
 
325
	v[3][0] = p3.x;
326
	v[3][1] = p3.y;
327
	v[3][2] = c3;
328
 
329
	fz_paint_triangle(pix, v[0], v[2], v[3], n, bbox);
330
	fz_paint_triangle(pix, v[0], v[3], v[1], n, bbox);
331
}
332
 
333
/*
334
 * linear, radial and mesh painting
335
 */
336
 
337
#define HUGENUM 32000 /* how far to extend axial/radial shadings */
338
#define RADSEGS 32 /* how many segments to generate for radial meshes */
339
 
340
static fz_point
341
fz_point_on_circle(fz_point p, float r, float theta)
342
{
343
	p.x = p.x + cosf(theta) * r;
344
	p.y = p.y + sinf(theta) * r;
345
 
346
	return p;
347
}
348
 
349
static void
350
fz_paint_linear(fz_shade *shade, fz_matrix ctm, fz_pixmap *dest, fz_bbox bbox)
351
{
352
	fz_point p0, p1;
353
	fz_point v0, v1, v2, v3;
354
	fz_point e0, e1;
355
	float theta;
356
 
357
	p0.x = shade->mesh[0];
358
	p0.y = shade->mesh[1];
359
	p0 = fz_transform_point(ctm, p0);
360
 
361
	p1.x = shade->mesh[3];
362
	p1.y = shade->mesh[4];
363
	p1 = fz_transform_point(ctm, p1);
364
 
365
	theta = atan2f(p1.y - p0.y, p1.x - p0.x);
366
	theta += (float)M_PI * 0.5f;
367
 
368
	v0 = fz_point_on_circle(p0, HUGENUM, theta);
369
	v1 = fz_point_on_circle(p1, HUGENUM, theta);
370
	v2 = fz_point_on_circle(p0, -HUGENUM, theta);
371
	v3 = fz_point_on_circle(p1, -HUGENUM, theta);
372
 
373
	fz_paint_quad(dest, v0, v1, v2, v3, 0, 255, 0, 255, 3, bbox);
374
 
375
	if (shade->extend[0])
376
	{
377
		e0.x = v0.x - (p1.x - p0.x) * HUGENUM;
378
		e0.y = v0.y - (p1.y - p0.y) * HUGENUM;
379
 
380
		e1.x = v2.x - (p1.x - p0.x) * HUGENUM;
381
		e1.y = v2.y - (p1.y - p0.y) * HUGENUM;
382
 
383
		fz_paint_quad(dest, e0, e1, v0, v2, 0, 0, 0, 0, 3, bbox);
384
	}
385
 
386
	if (shade->extend[1])
387
	{
388
		e0.x = v1.x + (p1.x - p0.x) * HUGENUM;
389
		e0.y = v1.y + (p1.y - p0.y) * HUGENUM;
390
 
391
		e1.x = v3.x + (p1.x - p0.x) * HUGENUM;
392
		e1.y = v3.y + (p1.y - p0.y) * HUGENUM;
393
 
394
		fz_paint_quad(dest, e0, e1, v1, v3, 255, 255, 255, 255, 3, bbox);
395
	}
396
}
397
 
398
static void
399
fz_paint_annulus(fz_matrix ctm,
400
		fz_point p0, float r0, float c0,
401
		fz_point p1, float r1, float c1,
402
		fz_pixmap *dest, fz_bbox bbox)
403
{
404
	fz_point t0, t1, t2, t3, b0, b1, b2, b3;
405
	float theta, step;
406
	int i;
407
 
408
	theta = atan2f(p1.y - p0.y, p1.x - p0.x);
409
	step = (float)M_PI * 2 / RADSEGS;
410
 
411
	for (i = 0; i < RADSEGS / 2; i++)
412
	{
413
		t0 = fz_point_on_circle(p0, r0, theta + i * step);
414
		t1 = fz_point_on_circle(p0, r0, theta + i * step + step);
415
		t2 = fz_point_on_circle(p1, r1, theta + i * step);
416
		t3 = fz_point_on_circle(p1, r1, theta + i * step + step);
417
		b0 = fz_point_on_circle(p0, r0, theta - i * step);
418
		b1 = fz_point_on_circle(p0, r0, theta - i * step - step);
419
		b2 = fz_point_on_circle(p1, r1, theta - i * step);
420
		b3 = fz_point_on_circle(p1, r1, theta - i * step - step);
421
 
422
		t0 = fz_transform_point(ctm, t0);
423
		t1 = fz_transform_point(ctm, t1);
424
		t2 = fz_transform_point(ctm, t2);
425
		t3 = fz_transform_point(ctm, t3);
426
		b0 = fz_transform_point(ctm, b0);
427
		b1 = fz_transform_point(ctm, b1);
428
		b2 = fz_transform_point(ctm, b2);
429
		b3 = fz_transform_point(ctm, b3);
430
 
431
		fz_paint_quad(dest, t0, t1, t2, t3, c0, c0, c1, c1, 3, bbox);
432
		fz_paint_quad(dest, b0, b1, b2, b3, c0, c0, c1, c1, 3, bbox);
433
	}
434
}
435
 
436
static void
437
fz_paint_radial(fz_shade *shade, fz_matrix ctm, fz_pixmap *dest, fz_bbox bbox)
438
{
439
	fz_point p0, p1;
440
	float r0, r1;
441
	fz_point e;
442
	float er, rs;
443
 
444
	p0.x = shade->mesh[0];
445
	p0.y = shade->mesh[1];
446
	r0 = shade->mesh[2];
447
 
448
	p1.x = shade->mesh[3];
449
	p1.y = shade->mesh[4];
450
	r1 = shade->mesh[5];
451
 
452
	if (shade->extend[0])
453
	{
454
		if (r0 < r1)
455
			rs = r0 / (r0 - r1);
456
		else
457
			rs = -HUGENUM;
458
 
459
		e.x = p0.x + (p1.x - p0.x) * rs;
460
		e.y = p0.y + (p1.y - p0.y) * rs;
461
		er = r0 + (r1 - r0) * rs;
462
 
463
		fz_paint_annulus(ctm, e, er, 0, p0, r0, 0, dest, bbox);
464
	}
465
 
466
	fz_paint_annulus(ctm, p0, r0, 0, p1, r1, 255, dest, bbox);
467
 
468
	if (shade->extend[1])
469
	{
470
		if (r0 > r1)
471
			rs = r1 / (r1 - r0);
472
		else
473
			rs = -HUGENUM;
474
 
475
		e.x = p1.x + (p0.x - p1.x) * rs;
476
		e.y = p1.y + (p0.y - p1.y) * rs;
477
		er = r1 + (r0 - r1) * rs;
478
 
479
		fz_paint_annulus(ctm, p1, r1, 255, e, er, 255, dest, bbox);
480
	}
481
}
482
 
483
static void
484
fz_paint_mesh(fz_shade *shade, fz_matrix ctm, fz_pixmap *dest, fz_bbox bbox)
485
{
486
	float tri[3][MAXN];
487
	fz_point p;
488
	float *mesh;
489
	int ntris;
490
	int i, k;
491
 
492
	mesh = shade->mesh;
493
 
494
	if (shade->use_function)
495
		ntris = shade->mesh_len / 9;
496
	else
497
		ntris = shade->mesh_len / ((2 + shade->colorspace->n) * 3);
498
 
499
	while (ntris--)
500
	{
501
		for (k = 0; k < 3; k++)
502
		{
503
			p.x = *mesh++;
504
			p.y = *mesh++;
505
			p = fz_transform_point(ctm, p);
506
			tri[k][0] = p.x;
507
			tri[k][1] = p.y;
508
			if (shade->use_function)
509
				tri[k][2] = *mesh++ * 255;
510
			else
511
			{
512
				fz_convert_color(shade->colorspace, mesh, dest->colorspace, tri[k] + 2);
513
				for (i = 0; i < dest->colorspace->n; i++)
514
					tri[k][i + 2] *= 255;
515
				mesh += shade->colorspace->n;
516
			}
517
		}
518
		fz_paint_triangle(dest, tri[0], tri[1], tri[2], 2 + dest->colorspace->n, bbox);
519
	}
520
}
521
 
522
void
523
fz_paint_shade(fz_shade *shade, fz_matrix ctm, fz_pixmap *dest, fz_bbox bbox)
524
{
525
	unsigned char clut[256][FZ_MAX_COLORS];
526
	fz_pixmap *temp, *conv;
527
	float color[FZ_MAX_COLORS];
528
	int i, k;
529
 
530
	ctm = fz_concat(shade->matrix, ctm);
531
 
532
	if (shade->use_function)
533
	{
534
		for (i = 0; i < 256; i++)
535
		{
536
			fz_convert_color(shade->colorspace, shade->function[i], dest->colorspace, color);
537
			for (k = 0; k < dest->colorspace->n; k++)
538
				clut[i][k] = color[k] * 255;
539
			clut[i][k] = shade->function[i][shade->colorspace->n] * 255;
540
		}
541
		conv = fz_new_pixmap_with_rect(dest->colorspace, bbox);
542
		temp = fz_new_pixmap_with_rect(fz_device_gray, bbox);
543
		fz_clear_pixmap(temp);
544
	}
545
	else
546
	{
547
		temp = dest;
548
	}
549
 
550
	switch (shade->type)
551
	{
552
	case FZ_LINEAR: fz_paint_linear(shade, ctm, temp, bbox); break;
553
	case FZ_RADIAL: fz_paint_radial(shade, ctm, temp, bbox); break;
554
	case FZ_MESH: fz_paint_mesh(shade, ctm, temp, bbox); break;
555
	}
556
 
557
	if (shade->use_function)
558
	{
559
		unsigned char *s = temp->samples;
560
		unsigned char *d = conv->samples;
561
		int len = temp->w * temp->h;
562
		while (len--)
563
		{
564
			int v = *s++;
565
			int a = fz_mul255(*s++, clut[v][conv->n - 1]);
566
			for (k = 0; k < conv->n - 1; k++)
567
				*d++ = fz_mul255(clut[v][k], a);
568
			*d++ = a;
569
		}
570
		fz_paint_pixmap(dest, conv, 255);
571
		fz_drop_pixmap(conv);
572
		fz_drop_pixmap(temp);
573
	}
574
}