You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libart-lgpl/testart.c

643 lines
14 KiB

/* Libart_LGPL - library of basic graphic primitives
* Copyright (C) 1998, 1999 Raph Levien
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "art_misc.h"
#include "art_vpath.h"
#include "art_svp.h"
#include "art_svp_vpath.h"
#include "art_gray_svp.h"
#include "art_rgb_svp.h"
#include "art_svp_vpath_stroke.h"
#include "art_svp_ops.h"
#include "art_affine.h"
#include "art_rgb_affine.h"
#include "art_rgb_bitmap_affine.h"
#include "art_rgb_rgba_affine.h"
#include "art_alphagamma.h"
#include "art_svp_point.h"
#include "art_vpath_dash.h"
#include "art_render.h"
#include "art_render_gradient.h"
#include "art_render_svp.h"
#include "art_svp_intersect.h"
#ifdef DEAD_CODE
static void
test_affine (void) {
double src[6];
double dst[6];
double src2[6];
char str[128];
int i;
ArtPoint ps, pd, ptmp;
for (i = 0; i < 6; i++)
{
src[i] = (rand () * 2.0 / RAND_MAX) - 1.0;
src2[i] = (rand () * 2.0 / RAND_MAX) - 1.0;
}
#if 0
src[0] = 0.9999999;
src[1] = -0.000001;
src[2] = 0.000001;
src[3] = 0.9999999;
src[4] = 0;
src[5] = 0;
#if 1
src[0] = 0.98480775;
src[1] = -0.17364818;
src[2] = 0.17364818;
src[3] = 0.98480775;
#endif
src2[0] = 0.98480775;
src2[1] = -0.17364818;
src2[2] = 0.17364818;
src2[3] = 0.98480775;
#endif
ps.x = rand() * 100.0 / RAND_MAX;
ps.y = rand() * 100.0 / RAND_MAX;
art_affine_point (&pd, &ps, src);
art_affine_invert (dst, src);
art_affine_point (&ptmp, &pd, dst);
art_affine_to_string (str, src);
printf ("src = %s\n", str);
art_affine_to_string (str, dst);
printf ("dst = %s\n", str);
printf ("point (%g, %g) -> (%g, %g) -> (%g, %g)\n",
ps.x, ps.y, pd.x, pd.y, ptmp.x, ptmp.y);
art_affine_point (&ptmp, &ps, src);
art_affine_point (&pd, &ptmp, src2);
art_affine_to_string (str, src2);
printf ("src2 = %s\n", str);
printf ("point (%g, %g) -> (%g, %g) -> (%g, %g)\n",
ps.x, ps.y, ptmp.x, ptmp.y, pd.x, pd.y);
art_affine_multiply (dst, src, src2);
art_affine_to_string (str, dst);
printf ("dst = %s\n", str);
art_affine_point (&pd, &ps, dst);
printf ("point (%g, %g) -> (%g, %g)\n",
ps.x, ps.y, pd.x, pd.y);
}
#endif
static ArtVpath *
randstar (int n)
{
ArtVpath *vec;
int i;
double r, th;
vec = art_new (ArtVpath, n + 2);
for (i = 0; i < n; i++)
{
vec[i].code = i ? ART_LINETO : ART_MOVETO;
r = rand () * (250.0 / RAND_MAX);
#if 0
r = r + 0.9 * (250 - r);
#endif
th = i * 2 * M_PI / n;
vec[i].x = 250 + r * cos (th);
vec[i].y = 250 - r * sin (th);
}
vec[i].code = ART_LINETO;
vec[i].x = vec[0].x;
vec[i].y = vec[0].y;
i++;
vec[i].code = ART_END;
vec[i].x = 0;
vec[i].y = 0;
return vec;
}
#define TILE_SIZE 512
#define NUM_ITERS 1
#define COLOR
#ifdef COLOR
#define BYTES_PP 3
#else
#define BYTES_PP 1
#endif
#ifndef nDEAD_CODE
static void
print_svp (ArtSVP *vp)
{
int i, j;
for (i = 0; i < vp->n_segs; i++)
{
printf ("segment %d, dir = %s (%f, %f) - (%f, %f)\n",
i, vp->segs[i].dir ? "down" : "up",
vp->segs[i].bbox.x0,
vp->segs[i].bbox.y0,
vp->segs[i].bbox.x1,
vp->segs[i].bbox.y1);
for (j = 0; j < vp->segs[i].n_points; j++)
printf (" (%g, %g)\n",
vp->segs[i].points[j].x,
vp->segs[i].points[j].y);
}
}
#endif
static void
print_vpath (ArtVpath *vpath)
{
int i;
for (i = 0; vpath[i].code != ART_END; i++)
printf ("%g %g %s\n",
vpath[i].x, vpath[i].y,
vpath[i].code == ART_MOVETO_OPEN ? "moveto %open" :
vpath[i].code == ART_MOVETO ? "moveto" :
vpath[i].code == ART_LINETO ? "lineto" :
"?");
printf ("stroke\n");
}
static void
make_testpat (void)
{
ArtVpath *vpath, *vpath2, *vpath3;
ArtSVP *svp, *svp2;
ArtSVP *svp3;
art_u8 buf[512 * 512 * BYTES_PP];
int i, j;
int iter;
art_u8 colorimg[256][256][3];
art_u8 rgbaimg[256][256][4];
art_u8 bitimg[16][2];
int x, y;
double affine[6];
double affine2[6];
double affine3[6];
ArtAlphaGamma *alphagamma;
double dash_data[] = { 20 };
ArtVpathDash dash;
dash.offset = 0;
dash.n_dash = 1;
dash.dash = dash_data;
#ifdef TEST_AFFINE
test_affine ();
exit (0);
#endif
vpath = randstar (50);
svp = art_svp_from_vpath (vpath);
art_free (vpath);
vpath2 = randstar (50);
#if 1
vpath3 = art_vpath_dash (vpath2, &dash);
art_free (vpath2);
svp2 = art_svp_vpath_stroke (vpath3,
ART_PATH_STROKE_JOIN_MITER,
ART_PATH_STROKE_CAP_BUTT,
15,
4,
0.5);
art_free (vpath3);
#else
svp2 = art_svp_from_vpath (vpath2);
art_free (vpath2);
#endif
#if 1
svp3 = art_svp_intersect (svp, svp2);
#else
svp3 = svp2;
#endif
#if 0
print_svp (svp);
#endif
for (y = 0; y < 256; y++)
for (x = 0; x < 256; x++)
{
colorimg[y][x][0] = (x + y) >> 1;
colorimg[y][x][1] = (x + (255 - y)) >> 1;
colorimg[y][x][2] = ((255 - x) + y) >> 1;
rgbaimg[y][x][0] = (x + y) >> 1;
rgbaimg[y][x][1] = (x + (255 - y)) >> 1;
rgbaimg[y][x][2] = ((255 - x) + y) >> 1;
rgbaimg[y][x][3] = y;
}
for (y = 0; y < 16; y++)
for (x = 0; x < 2; x++)
bitimg[y][x] = (x << 4) | y;
affine[0] = 0.5;
affine[1] = .2;
affine[2] = -.2;
affine[3] = 0.5;
affine[4] = 64;
affine[5] = 64;
affine2[0] = 1;
affine2[1] = -.2;
affine2[2] = .2;
affine2[3] = 1;
affine2[4] = 128;
affine2[5] = 128;
affine3[0] = 5;
affine3[1] = -.2;
affine3[2] = .2;
affine3[3] = 5;
affine3[4] = 384;
affine3[5] = 32;
#if 0
alphagamma = art_alphagamma_new (1.8);
#else
alphagamma = NULL;
#endif
#ifdef COLOR
printf ("P6\n512 512\n255\n");
#else
printf ("P5\n512 512\n255\n");
#endif
for (iter = 0; iter < NUM_ITERS; iter++)
for (j = 0; j < 512; j += TILE_SIZE)
for (i = 0; i < 512; i += TILE_SIZE)
{
#ifdef COLOR
art_rgb_svp_aa (svp, i, j, i + TILE_SIZE, j + TILE_SIZE,
0xffe0a0, 0x100040,
buf + (j * 512 + i) * BYTES_PP, 512 * BYTES_PP,
alphagamma);
art_rgb_svp_alpha (svp2, i, j, i + TILE_SIZE, j + TILE_SIZE,
0xff000080,
buf + (j * 512 + i) * BYTES_PP, 512 * BYTES_PP,
alphagamma);
art_rgb_svp_alpha (svp3, i, j, i + TILE_SIZE, j + TILE_SIZE,
0x00ff0080,
buf + (j * 512 + i) * BYTES_PP, 512 * BYTES_PP,
alphagamma);
art_rgb_affine (buf + (j * 512 + i) * BYTES_PP,
i, j, i + TILE_SIZE, j + TILE_SIZE, 512 * BYTES_PP,
(art_u8 *)colorimg, 256, 256, 256 * 3,
affine,
ART_FILTER_NEAREST, alphagamma);
art_rgb_rgba_affine (buf + (j * 512 + i) * BYTES_PP,
i, j, i + TILE_SIZE, j + TILE_SIZE,
512 * BYTES_PP,
(art_u8 *)rgbaimg, 256, 256, 256 * 4,
affine2,
ART_FILTER_NEAREST, alphagamma);
art_rgb_bitmap_affine (buf + (j * 512 + i) * BYTES_PP,
i, j, i + TILE_SIZE, j + TILE_SIZE,
512 * BYTES_PP,
(art_u8 *)bitimg, 16, 16, 2,
0xffff00ff,
affine3,
ART_FILTER_NEAREST, alphagamma);
#else
art_gray_svp_aa (svp, i, j, i + TILE_SIZE, j + TILE_SIZE,
buf + (j * 512 + i) * BYTES_PP, 512 * BYTES_PP);
#endif
}
art_svp_free (svp2);
art_svp_free (svp3);
art_svp_free (svp);
#if 1
fwrite (buf, 1, 512 * 512 * BYTES_PP, stdout);
#endif
}
static void
test_dist (void)
{
ArtVpath *vpath;
ArtSVP *svp;
art_u8 buf[512 * 512 * BYTES_PP];
int x, y;
int ix;
double dist;
int wind;
vpath = randstar (20);
#ifdef NO_STROKE
svp = art_svp_from_vpath (vpath);
#else
svp = art_svp_vpath_stroke (vpath,
ART_PATH_STROKE_JOIN_MITER,
ART_PATH_STROKE_CAP_BUTT,
15,
4,
0.5);
#endif
art_free (vpath);
art_rgb_svp_aa (svp, 0, 0, 512, 512,
0xffe0a0, 0x100040,
buf, 512 * BYTES_PP,
NULL);
ix = 0;
for (y = 0; y < 512; y++)
{
for (x = 0; x < 512; x++)
{
wind = art_svp_point_wind (svp, x, y);
buf[ix] = 204 - wind * 51;
dist = art_svp_point_dist (svp, x, y);
if (((x | y) & 0x3f) == 0)
{
fprintf (stderr, "%d,%d: %f\n", x, y, dist);
}
buf[ix + 1] = 255 - dist;
ix += 3;
}
}
printf ("P6\n512 512\n255\n");
fwrite (buf, 1, 512 * 512 * BYTES_PP, stdout);
}
static void
test_dash (void)
{
ArtVpath *vpath, *vpath2;
double dash_data[] = { 10, 4, 1, 4};
ArtVpathDash dash;
dash.offset = 0;
dash.n_dash = 3;
dash.dash = dash_data;
vpath = randstar (50);
vpath2 = art_vpath_dash (vpath, &dash);
printf ("%%!\n");
print_vpath (vpath2);
printf ("showpage\n");
art_free (vpath);
art_free (vpath2);
}
static void
test_render_gradient (art_u8 *buf)
{
ArtGradientLinear gradient;
ArtGradientStop stops[3] = {
{ 0.0, { 0x7fff, 0x0000, 0x0000, 0x7fff }},
{ 0.5, { 0x0000, 0x0000, 0x0000, 0x1000 }},
{ 1.0, { 0x0000, 0x7fff, 0x0000, 0x7fff }}
};
ArtVpath *vpath;
ArtSVP *svp;
ArtRender *render;
gradient.a = 0.003;
gradient.b = -0.0015;
gradient.c = 0.1;
gradient.spread = ART_GRADIENT_PAD;
gradient.n_stops = sizeof(stops) / sizeof(stops[0]);
gradient.stops = stops;
vpath = randstar (50);
svp = art_svp_from_vpath (vpath);
art_free (vpath);
render = art_render_new (0, 0, 512, 512, buf, 512 * 3, 3, 8, ART_ALPHA_NONE,
NULL);
art_render_svp (render, svp);
art_svp_free (svp);
art_render_gradient_linear (render, &gradient, ART_FILTER_NEAREST);
art_render_invoke (render);
}
static void
test_render_rad_gradient (art_u8 *buf)
{
ArtGradientRadial gradient;
ArtGradientStop stops[3] = {
{ 0.0, { 0xffff, 0x0000, 0x0000, 0xffff }},
{ 0.5, { 0xe000, 0xe000, 0x0000, 0xe000 }},
{ 1.0, { 0x0000, 0x0000, 0x0000, 0x0000 }}
};
ArtVpath *vpath;
ArtSVP *svp;
ArtRender *render;
gradient.affine[0] = 3.0 / 512;
gradient.affine[1] = 0;
gradient.affine[2] = 0;
gradient.affine[3] = 3.0 / 512;
gradient.affine[4] = -1.5;
gradient.affine[5] = -1.5;
gradient.fx = 0.9;
gradient.fy = 0.1;
gradient.n_stops = sizeof(stops) / sizeof(stops[0]);
gradient.stops = stops;
vpath = randstar (50);
svp = art_svp_from_vpath (vpath);
art_free (vpath);
render = art_render_new (0, 0, 512, 512, buf, 512 * 3, 3, 8, ART_ALPHA_NONE,
NULL);
art_render_svp (render, svp);
art_render_gradient_radial (render, &gradient, ART_FILTER_NEAREST);
art_render_invoke (render);
}
static void
test_gradient (void)
{
ArtVpath *vpath;
ArtSVP *svp;
art_u8 buf[512 * 512 * 3];
ArtRender *render;
ArtPixMaxDepth color[3] = {0x0000, 0x0000, 0x8000 };
int i;
const int n_iter = 1;
vpath = randstar (50);
svp = art_svp_from_vpath (vpath);
art_free (vpath);
for (i = 0; i < n_iter; i++)
{
#define USE_RENDER
#ifdef USE_RENDER
render = art_render_new (0, 0, 512, 512, buf, 512 * 3, 3, 8, ART_ALPHA_NONE,
NULL);
art_render_clear_rgb (render, 0xfff0c0);
art_render_svp (render, svp);
art_render_image_solid (render, color);
art_render_invoke (render);
#else
art_rgb_svp_aa (svp, 0, 0, 512, 512, 0xfff0c0, 0x000080,
buf, 512 * 3, NULL);
#endif
}
#if 1
test_render_gradient (buf);
#endif
test_render_rad_gradient (buf);
printf ("P6\n512 512\n255\n");
fwrite (buf, 1, 512 * 512 * 3, stdout);
}
#if 0
static void
output_svp_ppm (const ArtSVP *svp)
{
art_u8 buf[512 * 512 * 3];
art_rgb_svp_aa (svp, 0, 0, 512, 512, 0xfff0c0, 0x000080,
buf, 512 * 3, NULL);
printf ("P6\n512 512\n255\n");
fwrite (buf, 1, 512 * 512 * 3, stdout);
}
#endif
static void
test_intersect (void)
{
ArtVpath vpath[] = {
#if 0
/* two triangles */
{ ART_MOVETO, 100, 100 },
{ ART_LINETO, 300, 400 },
{ ART_LINETO, 400, 200 },
{ ART_LINETO, 100, 100 },
{ ART_MOVETO, 110, 110 },
{ ART_LINETO, 310, 410 },
{ ART_LINETO, 410, 210 },
{ ART_LINETO, 110, 110 },
#endif
#if 0
/* a bowtie */
{ ART_MOVETO, 100, 100 },
{ ART_LINETO, 400, 400 },
{ ART_LINETO, 400, 100 },
{ ART_LINETO, 100, 400 },
{ ART_LINETO, 100, 100 },
#endif
#if 1
/* a square */
{ ART_MOVETO, 100, 100 },
{ ART_LINETO, 100, 400 },
{ ART_LINETO, 400, 400 },
{ ART_LINETO, 400, 100 },
{ ART_LINETO, 100, 100 },
#endif
#if 1
/* another square */
#define XOFF 10
#define YOFF 10
{ ART_MOVETO, 100 + XOFF, 100 + YOFF },
{ ART_LINETO, 100 + XOFF, 400 + YOFF },
{ ART_LINETO, 400 + XOFF, 400 + YOFF },
{ ART_LINETO, 400 + XOFF, 100 + YOFF },
{ ART_LINETO, 100 + XOFF, 100 + YOFF },
#endif
{ ART_END, 0, 0}
};
ArtSVP *svp, *svp2;
ArtSvpWriter *swr;
svp = art_svp_from_vpath (vpath);
#define RUN_INTERSECT
#ifdef RUN_INTERSECT
swr = art_svp_writer_rewind_new (ART_WIND_RULE_ODDEVEN);
art_svp_intersector (svp, swr);
svp2 = art_svp_writer_rewind_reap (swr);
#endif
#if 0
output_svp_ppm (svp2);
#else
print_svp (svp2);
#endif
art_svp_free (svp);
#ifdef RUN_INTERSECT
art_svp_free (svp2);
#endif
}
static void
usage (void)
{
fprintf (stderr, "usage: testart <test>\n"
" where <test> is one of:\n"
" testpat -- make random star + gradients test pattern\n"
" gradient -- test pattern for rendered gradients\n"
" dash -- dash test (output is valid PostScript)\n"
" dist -- distance test\n"
" intersect -- softball test for intersector\n");
exit (1);
}
int
main (int argc, char **argv)
{
if (argc < 2)
usage ();
if (!strcmp (argv[1], "testpat"))
make_testpat ();
else if (!strcmp (argv[1], "gradient"))
test_gradient ();
else if (!strcmp (argv[1], "dist"))
test_dist ();
else if (!strcmp (argv[1], "dash"))
test_dash ();
else if (!strcmp (argv[1], "intersect"))
test_intersect ();
else
usage ();
return 0;
}