1 /* Libart_LGPL - library of basic graphic primitives
2  * Copyright (C) 1998, 1999 Raph Levien
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 
20 #include <stdio.h>
21 #include <string.h>
22 #include <math.h>
23 #include "art_misc.h"
24 #include "art_vpath.h"
25 #include "art_svp.h"
26 #include "art_svp_vpath.h"
27 #include "art_gray_svp.h"
28 #include "art_rgb_svp.h"
29 #include "art_svp_vpath_stroke.h"
30 #include "art_svp_ops.h"
31 #include "art_affine.h"
32 #include "art_rgb_affine.h"
33 #include "art_rgb_bitmap_affine.h"
34 #include "art_rgb_rgba_affine.h"
35 #include "art_alphagamma.h"
36 #include "art_svp_point.h"
37 #include "art_vpath_dash.h"
38 #include "art_render.h"
39 #include "art_render_gradient.h"
40 #include "art_render_svp.h"
41 #include "art_svp_intersect.h"
42 
43 #ifdef DEAD_CODE
44 static void
test_affine(void)45 test_affine (void) {
46   double src[6];
47   double dst[6];
48   double src2[6];
49   char str[128];
50   int i;
51   ArtPoint ps, pd, ptmp;
52 
53   for (i = 0; i < 6; i++)
54     {
55       src[i] = (rand () * 2.0 / RAND_MAX) - 1.0;
56       src2[i] = (rand () * 2.0 / RAND_MAX) - 1.0;
57     }
58 #if 0
59   src[0] = 0.9999999;
60   src[1] = -0.000001;
61   src[2] = 0.000001;
62   src[3] = 0.9999999;
63   src[4] = 0;
64   src[5] = 0;
65 #if 1
66   src[0] = 0.98480775;
67   src[1] = -0.17364818;
68   src[2] = 0.17364818;
69   src[3] = 0.98480775;
70 #endif
71 
72   src2[0] = 0.98480775;
73   src2[1] = -0.17364818;
74   src2[2] = 0.17364818;
75   src2[3] = 0.98480775;
76 #endif
77 
78 
79   ps.x = rand() * 100.0 / RAND_MAX;
80   ps.y = rand() * 100.0 / RAND_MAX;
81 
82   art_affine_point (&pd, &ps, src);
83   art_affine_invert (dst, src);
84   art_affine_point (&ptmp, &pd, dst);
85   art_affine_to_string (str, src);
86   printf ("src = %s\n", str);
87   art_affine_to_string (str, dst);
88   printf ("dst = %s\n", str);
89   printf ("point (%g, %g) -> (%g, %g) -> (%g, %g)\n",
90 	  ps.x, ps.y, pd.x, pd.y, ptmp.x, ptmp.y);
91 
92   art_affine_point (&ptmp, &ps, src);
93   art_affine_point (&pd, &ptmp, src2);
94   art_affine_to_string (str, src2);
95   printf ("src2 = %s\n", str);
96   printf ("point (%g, %g) -> (%g, %g) -> (%g, %g)\n",
97 	  ps.x, ps.y, ptmp.x, ptmp.y, pd.x, pd.y);
98   art_affine_multiply (dst, src, src2);
99   art_affine_to_string (str, dst);
100   printf ("dst = %s\n", str);
101   art_affine_point (&pd, &ps, dst);
102   printf ("point (%g, %g) -> (%g, %g)\n",
103 	  ps.x, ps.y, pd.x, pd.y);
104 
105 }
106 #endif
107 
108 static ArtVpath *
randstar(int n)109 randstar (int n)
110 {
111   ArtVpath *vec;
112   int i;
113   double r, th;
114 
115   vec = art_new (ArtVpath, n + 2);
116   for (i = 0; i < n; i++)
117     {
118       vec[i].code = i ? ART_LINETO : ART_MOVETO;
119       r = rand () * (250.0 / RAND_MAX);
120 #if 0
121       r = r + 0.9 * (250 - r);
122 #endif
123       th = i * 2 * M_PI / n;
124       vec[i].x = 250 + r * cos (th);
125       vec[i].y = 250 - r * sin (th);
126     }
127   vec[i].code = ART_LINETO;
128   vec[i].x = vec[0].x;
129   vec[i].y = vec[0].y;
130   i++;
131   vec[i].code = ART_END;
132   vec[i].x = 0;
133   vec[i].y = 0;
134   return vec;
135 }
136 
137 #define TILE_SIZE 512
138 #define NUM_ITERS 1
139 #define COLOR
140 
141 #ifdef COLOR
142 #define BYTES_PP 3
143 #else
144 #define BYTES_PP 1
145 #endif
146 
147 #ifndef nDEAD_CODE
148 static void
print_svp(ArtSVP * vp)149 print_svp (ArtSVP *vp)
150 {
151   int i, j;
152 
153   for (i = 0; i < vp->n_segs; i++)
154     {
155       printf ("segment %d, dir = %s (%f, %f) - (%f, %f)\n",
156 	      i, vp->segs[i].dir ? "down" : "up",
157 	      vp->segs[i].bbox.x0,
158 	      vp->segs[i].bbox.y0,
159 	      vp->segs[i].bbox.x1,
160 	      vp->segs[i].bbox.y1);
161       for (j = 0; j < vp->segs[i].n_points; j++)
162         printf ("  (%g, %g)\n",
163                 vp->segs[i].points[j].x,
164                 vp->segs[i].points[j].y);
165     }
166 }
167 #endif
168 
169 static void
print_vpath(ArtVpath * vpath)170 print_vpath (ArtVpath *vpath)
171 {
172   int i;
173 
174   for (i = 0; vpath[i].code != ART_END; i++)
175     printf ("%g %g %s\n",
176 	    vpath[i].x, vpath[i].y,
177 	    vpath[i].code == ART_MOVETO_OPEN ? "moveto %open" :
178 	    vpath[i].code == ART_MOVETO ? "moveto" :
179 	    vpath[i].code == ART_LINETO ? "lineto" :
180 	    "?");
181 
182   printf ("stroke\n");
183 }
184 
185 static void
make_testpat(void)186 make_testpat (void)
187 {
188   ArtVpath *vpath, *vpath2, *vpath3;
189   ArtSVP *svp, *svp2;
190   ArtSVP *svp3;
191   art_u8 buf[512 * 512 * BYTES_PP];
192   int i, j;
193   int iter;
194   art_u8 colorimg[256][256][3];
195   art_u8 rgbaimg[256][256][4];
196   art_u8 bitimg[16][2];
197   int x, y;
198   double affine[6];
199   double affine2[6];
200   double affine3[6];
201   ArtAlphaGamma *alphagamma;
202   double dash_data[] = { 20 };
203   ArtVpathDash dash;
204 
205   dash.offset = 0;
206   dash.n_dash = 1;
207   dash.dash = dash_data;
208 
209 #ifdef TEST_AFFINE
210   test_affine ();
211   exit (0);
212 #endif
213 
214   vpath = randstar (50);
215   svp = art_svp_from_vpath (vpath);
216   art_free (vpath);
217 
218   vpath2 = randstar (50);
219 #if 1
220   vpath3 = art_vpath_dash (vpath2, &dash);
221   art_free (vpath2);
222   svp2 = art_svp_vpath_stroke (vpath3,
223 			       ART_PATH_STROKE_JOIN_MITER,
224 			       ART_PATH_STROKE_CAP_BUTT,
225 			       15,
226 			       4,
227 			       0.5);
228   art_free (vpath3);
229 #else
230   svp2 = art_svp_from_vpath (vpath2);
231 #endif
232 
233 #if 1
234   svp3 = art_svp_intersect (svp, svp2);
235 #else
236   svp3 = svp2;
237 #endif
238 
239 #if 0
240   print_svp (svp);
241 #endif
242 
243   for (y = 0; y < 256; y++)
244     for (x = 0; x < 256; x++)
245       {
246 	colorimg[y][x][0] = (x + y) >> 1;
247 	colorimg[y][x][1] = (x + (255 - y)) >> 1;
248 	colorimg[y][x][2] = ((255 - x) + y) >> 1;
249 
250 	rgbaimg[y][x][0] = (x + y) >> 1;
251 	rgbaimg[y][x][1] = (x + (255 - y)) >> 1;
252 	rgbaimg[y][x][2] = ((255 - x) + y) >> 1;
253 	rgbaimg[y][x][3] = y;
254       }
255 
256   for (y = 0; y < 16; y++)
257     for (x = 0; x < 2; x++)
258       bitimg[y][x] = (x << 4) | y;
259 
260   affine[0] = 0.5;
261   affine[1] = .2;
262   affine[2] = -.2;
263   affine[3] = 0.5;
264   affine[4] = 64;
265   affine[5] = 64;
266 
267   affine2[0] = 1;
268   affine2[1] = -.2;
269   affine2[2] = .2;
270   affine2[3] = 1;
271   affine2[4] = 128;
272   affine2[5] = 128;
273 
274   affine3[0] = 5;
275   affine3[1] = -.2;
276   affine3[2] = .2;
277   affine3[3] = 5;
278   affine3[4] = 384;
279   affine3[5] = 32;
280 
281 #if 0
282   alphagamma = art_alphagamma_new (1.8);
283 #else
284   alphagamma = NULL;
285 #endif
286 
287 #ifdef COLOR
288   printf ("P6\n512 512\n255\n");
289 #else
290   printf ("P5\n512 512\n255\n");
291 #endif
292   for (iter = 0; iter < NUM_ITERS; iter++)
293     for (j = 0; j < 512; j += TILE_SIZE)
294       for (i = 0; i < 512; i += TILE_SIZE)
295 	{
296 #ifdef COLOR
297 	  art_rgb_svp_aa (svp, i, j, i + TILE_SIZE, j + TILE_SIZE,
298 			  0xffe0a0, 0x100040,
299 			  buf + (j * 512 + i) * BYTES_PP, 512 * BYTES_PP,
300 			  alphagamma);
301 	  art_rgb_svp_alpha (svp2, i, j, i + TILE_SIZE, j + TILE_SIZE,
302 			     0xff000080,
303 			     buf + (j * 512 + i) * BYTES_PP, 512 * BYTES_PP,
304 			     alphagamma);
305 	  art_rgb_svp_alpha (svp3, i, j, i + TILE_SIZE, j + TILE_SIZE,
306 			     0x00ff0080,
307 			     buf + (j * 512 + i) * BYTES_PP, 512 * BYTES_PP,
308 			     alphagamma);
309 	  art_rgb_affine (buf + (j * 512 + i) * BYTES_PP,
310 			  i, j, i + TILE_SIZE, j + TILE_SIZE, 512 * BYTES_PP,
311 			  (art_u8 *)colorimg, 256, 256, 256 * 3,
312 			  affine,
313 			  ART_FILTER_NEAREST, alphagamma);
314 	  art_rgb_rgba_affine (buf + (j * 512 + i) * BYTES_PP,
315 			       i, j, i + TILE_SIZE, j + TILE_SIZE,
316 			       512 * BYTES_PP,
317 			       (art_u8 *)rgbaimg, 256, 256, 256 * 4,
318 			       affine2,
319 			       ART_FILTER_NEAREST, alphagamma);
320 	  art_rgb_bitmap_affine (buf + (j * 512 + i) * BYTES_PP,
321 				 i, j, i + TILE_SIZE, j + TILE_SIZE,
322 				 512 * BYTES_PP,
323 				 (art_u8 *)bitimg, 16, 16, 2,
324 				 0xffff00ff,
325 				 affine3,
326 				 ART_FILTER_NEAREST, alphagamma);
327 #else
328 	  art_gray_svp_aa (svp, i, j, i + TILE_SIZE, j + TILE_SIZE,
329 			   buf + (j * 512 + i) * BYTES_PP, 512 * BYTES_PP);
330 #endif
331 	}
332 
333   art_svp_free (svp2);
334   art_svp_free (svp3);
335   art_svp_free (svp);
336 
337 #if 1
338   fwrite (buf, 1, 512 * 512 * BYTES_PP, stdout);
339 #endif
340 }
341 
342 static void
test_dist(void)343 test_dist (void)
344 {
345   ArtVpath *vpath;
346   ArtSVP *svp;
347   art_u8 buf[512 * 512 * BYTES_PP];
348   int x, y;
349   int ix;
350   double dist;
351   int wind;
352 
353   vpath = randstar (20);
354 #ifdef NO_STROKE
355   svp = art_svp_from_vpath (vpath);
356 #else
357   svp = art_svp_vpath_stroke (vpath,
358 			       ART_PATH_STROKE_JOIN_MITER,
359 			       ART_PATH_STROKE_CAP_BUTT,
360 			       15,
361 			       4,
362 			       0.5);
363 #endif
364 
365   art_rgb_svp_aa (svp, 0, 0, 512, 512,
366 		  0xffe0a0, 0x100040,
367 		  buf, 512 * BYTES_PP,
368 		  NULL);
369 
370   ix = 0;
371   for (y = 0; y < 512; y++)
372     {
373       for (x = 0; x < 512; x++)
374 	{
375 	  wind = art_svp_point_wind (svp, x, y);
376 	  buf[ix] = 204 - wind * 51;
377 	  dist = art_svp_point_dist (svp, x, y);
378 	  if (((x | y) & 0x3f) == 0)
379 	    {
380 	      fprintf (stderr, "%d,%d: %f\n", x, y, dist);
381 	    }
382 	  buf[ix + 1] = 255 - dist;
383 	  ix += 3;
384 	}
385     }
386 
387   printf ("P6\n512 512\n255\n");
388   fwrite (buf, 1, 512 * 512 * BYTES_PP, stdout);
389 
390 }
391 
392 static void
test_dash(void)393 test_dash (void)
394 {
395   ArtVpath *vpath, *vpath2;
396   double dash_data[] = { 10, 4, 1, 4};
397   ArtVpathDash dash;
398 
399   dash.offset = 0;
400   dash.n_dash = 3;
401   dash.dash = dash_data;
402 
403   vpath = randstar (50);
404   vpath2 = art_vpath_dash (vpath, &dash);
405   printf ("%%!\n");
406   print_vpath (vpath2);
407   printf ("showpage\n");
408   art_free (vpath);
409   art_free (vpath2);
410 }
411 
412 static void
test_render_gradient(art_u8 * buf)413 test_render_gradient (art_u8 *buf)
414 {
415   ArtGradientLinear gradient;
416   ArtGradientStop stops[3] = {
417     { 0.0, { 0x7fff, 0x0000, 0x0000, 0x7fff }},
418     { 0.5, { 0x0000, 0x0000, 0x0000, 0x1000 }},
419     { 1.0, { 0x0000, 0x7fff, 0x0000, 0x7fff }}
420   };
421   ArtVpath *vpath;
422   ArtSVP *svp;
423   ArtRender *render;
424 
425   gradient.a = 0.003;
426   gradient.b = -0.0015;
427   gradient.c = 0.1;
428   gradient.spread = ART_GRADIENT_PAD;
429   gradient.n_stops = sizeof(stops) / sizeof(stops[0]);
430   gradient.stops = stops;
431 
432   vpath = randstar (50);
433   svp = art_svp_from_vpath (vpath);
434 
435   render = art_render_new (0, 0, 512, 512, buf, 512 * 3, 3, 8, ART_ALPHA_NONE,
436 			   NULL);
437   art_render_svp (render, svp);
438   art_render_gradient_linear (render, &gradient, ART_FILTER_NEAREST);
439   art_render_invoke (render);
440 
441 }
442 
443 static void
test_render_rad_gradient(art_u8 * buf)444 test_render_rad_gradient (art_u8 *buf)
445 {
446   ArtGradientRadial gradient;
447   ArtGradientStop stops[3] = {
448     { 0.0, { 0xffff, 0x0000, 0x0000, 0xffff }},
449     { 0.5, { 0xe000, 0xe000, 0x0000, 0xe000 }},
450     { 1.0, { 0x0000, 0x0000, 0x0000, 0x0000 }}
451   };
452   ArtVpath *vpath;
453   ArtSVP *svp;
454   ArtRender *render;
455 
456   gradient.affine[0] = 3.0 / 512;
457   gradient.affine[1] = 0;
458   gradient.affine[2] = 0;
459   gradient.affine[3] = 3.0 / 512;
460   gradient.affine[4] = -1.5;
461   gradient.affine[5] = -1.5;
462   gradient.fx = 0.9;
463   gradient.fy = 0.1;
464 
465   gradient.n_stops = sizeof(stops) / sizeof(stops[0]);
466   gradient.stops = stops;
467 
468   vpath = randstar (50);
469   svp = art_svp_from_vpath (vpath);
470 
471   render = art_render_new (0, 0, 512, 512, buf, 512 * 3, 3, 8, ART_ALPHA_NONE,
472 			   NULL);
473   art_render_svp (render, svp);
474   art_render_gradient_radial (render, &gradient, ART_FILTER_NEAREST);
475   art_render_invoke (render);
476 
477 }
478 
479 static void
test_gradient(void)480 test_gradient (void)
481 {
482   ArtVpath *vpath;
483   ArtSVP *svp;
484   art_u8 buf[512 * 512 * 3];
485   ArtRender *render;
486   ArtPixMaxDepth color[3] = {0x0000, 0x0000, 0x8000 };
487   int i;
488   const int n_iter = 1;
489 
490   vpath = randstar (50);
491   svp = art_svp_from_vpath (vpath);
492 
493   for (i = 0; i < n_iter; i++)
494     {
495 #define USE_RENDER
496 #ifdef USE_RENDER
497       render = art_render_new (0, 0, 512, 512, buf, 512 * 3, 3, 8, ART_ALPHA_NONE,
498 			       NULL);
499       art_render_clear_rgb (render, 0xfff0c0);
500       art_render_svp (render, svp);
501       art_render_image_solid (render, color);
502       art_render_invoke (render);
503 #else
504       art_rgb_svp_aa (svp, 0, 0, 512, 512, 0xfff0c0, 0x000080,
505 		      buf, 512 * 3, NULL);
506 #endif
507     }
508 
509 #if 1
510   test_render_gradient (buf);
511 #endif
512   test_render_rad_gradient (buf);
513 
514   printf ("P6\n512 512\n255\n");
515   fwrite (buf, 1, 512 * 512 * 3, stdout);
516 }
517 
518 #if 0
519 static void
520 output_svp_ppm (const ArtSVP *svp)
521 {
522   art_u8 buf[512 * 512 * 3];
523   art_rgb_svp_aa (svp, 0, 0, 512, 512, 0xfff0c0, 0x000080,
524 		  buf, 512 * 3, NULL);
525   printf ("P6\n512 512\n255\n");
526   fwrite (buf, 1, 512 * 512 * 3, stdout);
527 }
528 #endif
529 
530 static void
test_intersect(void)531 test_intersect (void)
532 {
533   ArtVpath vpath[] = {
534 
535 #if 0
536     /* two triangles */
537     { ART_MOVETO, 100, 100 },
538     { ART_LINETO, 300, 400 },
539     { ART_LINETO, 400, 200 },
540     { ART_LINETO, 100, 100 },
541     { ART_MOVETO, 110, 110 },
542     { ART_LINETO, 310, 410 },
543     { ART_LINETO, 410, 210 },
544     { ART_LINETO, 110, 110 },
545 #endif
546 
547 #if 0
548     /* a bowtie */
549     { ART_MOVETO, 100, 100 },
550     { ART_LINETO, 400, 400 },
551     { ART_LINETO, 400, 100 },
552     { ART_LINETO, 100, 400 },
553     { ART_LINETO, 100, 100 },
554 #endif
555 
556 #if 1
557     /* a square */
558     { ART_MOVETO, 100, 100 },
559     { ART_LINETO, 100, 400 },
560     { ART_LINETO, 400, 400 },
561     { ART_LINETO, 400, 100 },
562     { ART_LINETO, 100, 100 },
563 #endif
564 
565 #if 1
566     /* another square */
567 #define XOFF 10
568 #define YOFF 10
569     { ART_MOVETO, 100 + XOFF, 100 + YOFF },
570     { ART_LINETO, 100 + XOFF, 400 + YOFF },
571     { ART_LINETO, 400 + XOFF, 400 + YOFF },
572     { ART_LINETO, 400 + XOFF, 100 + YOFF },
573     { ART_LINETO, 100 + XOFF, 100 + YOFF },
574 #endif
575 
576     { ART_END, 0, 0}
577   };
578   ArtSVP *svp, *svp2;
579   ArtSvpWriter *swr;
580 
581   svp = art_svp_from_vpath (vpath);
582 
583 #define RUN_INTERSECT
584 #ifdef RUN_INTERSECT
585   swr = art_svp_writer_rewind_new (ART_WIND_RULE_ODDEVEN);
586   art_svp_intersector (svp, swr);
587 
588   svp2 = art_svp_writer_rewind_reap (swr);
589 #endif
590 
591 #if 0
592   output_svp_ppm (svp2);
593 #else
594   print_svp (svp2);
595 #endif
596 
597   art_svp_free (svp);
598 
599 #ifdef RUN_INTERSECT
600   art_svp_free (svp2);
601 #endif
602 }
603 
604 static void
usage(void)605 usage (void)
606 {
607   fprintf (stderr, "usage: testart <test>\n"
608 "  where <test> is one of:\n"
609 "  testpat    -- make random star + gradients test pattern\n"
610 "  gradient   -- test pattern for rendered gradients\n"
611 "  dash       -- dash test (output is valid PostScript)\n"
612 "  dist       -- distance test\n"
613 "  intersect  -- softball test for intersector\n");
614   exit (1);
615 }
616 
617 int
main(int argc,char ** argv)618 main (int argc, char **argv)
619 {
620   if (argc < 2)
621     usage ();
622 
623   if (!strcmp (argv[1], "testpat"))
624     make_testpat ();
625   else if (!strcmp (argv[1], "gradient"))
626     test_gradient ();
627   else if (!strcmp (argv[1], "dist"))
628     test_dist ();
629   else if (!strcmp (argv[1], "dash"))
630     test_dash ();
631   else if (!strcmp (argv[1], "intersect"))
632     test_intersect ();
633   else
634     usage ();
635   return 0;
636 }
637