diff options
author | scuri <scuri> | 2008-10-17 06:10:33 +0000 |
---|---|---|
committer | scuri <scuri> | 2008-10-17 06:10:33 +0000 |
commit | 7b52cc13af4e85f1ca2deb6b6c77de9c95ea0dcf (patch) | |
tree | d0857278bde2eff784227c57dcaf930346ceb7ac /src/drv |
First commit - moving from LuaForge to SourceForge
Diffstat (limited to 'src/drv')
-rw-r--r-- | src/drv/cd0emf.c | 17 | ||||
-rw-r--r-- | src/drv/cd0prn.c | 17 | ||||
-rw-r--r-- | src/drv/cd0wmf.c | 16 | ||||
-rw-r--r-- | src/drv/cdcgm.c | 1135 | ||||
-rw-r--r-- | src/drv/cddebug.c | 729 | ||||
-rw-r--r-- | src/drv/cddgn.c | 1696 | ||||
-rw-r--r-- | src/drv/cddxf.c | 1184 | ||||
-rw-r--r-- | src/drv/cdirgb.c | 2135 | ||||
-rw-r--r-- | src/drv/cdmf.c | 1188 | ||||
-rw-r--r-- | src/drv/cdpdf.c | 1491 | ||||
-rw-r--r-- | src/drv/cdpicture.c | 1133 | ||||
-rw-r--r-- | src/drv/cdps.c | 1836 | ||||
-rw-r--r-- | src/drv/cgm.c | 2281 | ||||
-rw-r--r-- | src/drv/cgm.h | 156 |
14 files changed, 15014 insertions, 0 deletions
diff --git a/src/drv/cd0emf.c b/src/drv/cd0emf.c new file mode 100644 index 0000000..13beb4c --- /dev/null +++ b/src/drv/cd0emf.c @@ -0,0 +1,17 @@ +/** \file + * \brief Dummy EMF + * + * See Copyright Notice in cd.h + */ + +#include <stdlib.h> +#include "cd.h" +#include "cdemf.h" + + +cdContext* cdContextEMF(void) +{ + return NULL; +} + + diff --git a/src/drv/cd0prn.c b/src/drv/cd0prn.c new file mode 100644 index 0000000..429a392 --- /dev/null +++ b/src/drv/cd0prn.c @@ -0,0 +1,17 @@ +/** \file + * \brief Dummy Printer + * + * See Copyright Notice in cd.h + */ + +#include <stdlib.h> +#include "cd.h" +#include "cdprint.h" + + + +cdContext* cdContextPrinter(void) +{ + return NULL; +} + diff --git a/src/drv/cd0wmf.c b/src/drv/cd0wmf.c new file mode 100644 index 0000000..a96761a --- /dev/null +++ b/src/drv/cd0wmf.c @@ -0,0 +1,16 @@ +/** \file + * \brief Dummy WMF + * + * See Copyright Notice in cd.h + */ + +#include <stdlib.h> +#include "cd.h" +#include "cdwmf.h" + + +cdContext* cdContextWMF(void) +{ + return NULL; +} + diff --git a/src/drv/cdcgm.c b/src/drv/cdcgm.c new file mode 100644 index 0000000..4ba0065 --- /dev/null +++ b/src/drv/cdcgm.c @@ -0,0 +1,1135 @@ +/** \file + * \brief CGM driver + * + * See Copyright Notice in cd.h + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <math.h> +#include <limits.h> + +#include "cd.h" +#include "cd_private.h" +#include "cdcgm.h" +#include "cgm.h" + +#define get_red(_) (((double)cdRed(_))/255.) +#define get_green(_) (((double)cdGreen(_))/255.) +#define get_blue(_) (((double)cdBlue(_))/255.) + + +struct _cdCtxCanvas +{ + cdCanvas* canvas; + CGM *cgm; + + char filename[256]; /* Arquivo CGM */ + + int codificacao; /* Codificacao */ + int vdc_int_prec; + int first; /* Primeira primitiva a ser desenhada */ + long point; + int hassize; + int patindex; + + struct + { + cdfRect bbox; + int first; + } clip; + + cdfRect b_box; +}; + +static double cve_black[] = { 0.0, 0.0, 0.0 }; +static double cve_white[] = { 1.0, 1.0, 1.0 }; + +/* From INTCGM */ +int cdplayCGM(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax, void *data); +int cdRegisterCallbackCGM(int cb, cdCallback func); + + +/* +%F Atualiza os valores do bounding box +*/ +static void setbbox (cdCtxCanvas *ctxcanvas, double x, double y ) +{ + if ( ctxcanvas->first ) + { + ctxcanvas->b_box.xmin = x; + ctxcanvas->b_box.xmax = x; + ctxcanvas->b_box.ymin = y; + ctxcanvas->b_box.ymax = y; + ctxcanvas->first = 0; + } + + if ( x<ctxcanvas->b_box.xmin ) ctxcanvas->b_box.xmin = x; + if ( x>ctxcanvas->b_box.xmax ) ctxcanvas->b_box.xmax = x; + if ( y<ctxcanvas->b_box.ymin ) ctxcanvas->b_box.ymin = y; + if ( y>ctxcanvas->b_box.ymax ) ctxcanvas->b_box.ymax = y; +} + + +/* +%F metafile descriptor elements +*/ +static void metafile_descriptor (cdCtxCanvas *ctxcanvas) +{ + const char *font_list[] = { "SYSTEM", "COURIER", "TIMES_ROMAN", "HELVETICA", + "SYSTEM_BOLD", "COURIER_BOLD", "TIMES_ROMAN_BOLD", "HELVETICA_BOLD", + "SYSTEM_ITALIC", "COURIER_ITALIC", "TIMES_ROMAN_ITALIC", + "HELVETICA_ITALIC", "SYSTEM_BOLDITALIC", "COURIER_BOLDITALIC", + "TIMES_ROMAN_BOLDITALIC", "HELVETICA_BOLDITALIC", NULL }; + + cgm_metafile_version ( ctxcanvas->cgm, 1); + cgm_metafile_description ( ctxcanvas->cgm, "CD generated" ); + cgm_vdc_type ( ctxcanvas->cgm, 0 /* integer */ ); + cgm_integer_precision ( ctxcanvas->cgm, 16 ); + cgm_real_precision ( ctxcanvas->cgm, 3 /* fixed 32 */ ); + cgm_index_precision ( ctxcanvas->cgm, 16 ); + cgm_colour_precision ( ctxcanvas->cgm, 8 ); + cgm_colour_index_precision ( ctxcanvas->cgm, 8 ); + cgm_maximum_colour_index ( ctxcanvas->cgm, 255ul ); + cgm_colour_value_extent ( ctxcanvas->cgm, cve_black, cve_white ); + + { + static int classes[] = { -1 /* drawing set */ }; + static int ids [] = { 1 /* plus control set */ }; + cgm_metafile_element_list ( ctxcanvas->cgm, 1, classes, ids ); + } + + cgm_begin_metafile_defaults ( ctxcanvas->cgm ); + + cgm_vdc_integer_precision ( ctxcanvas->cgm, ctxcanvas->vdc_int_prec ); + cgm_interior_style ( ctxcanvas->cgm, 1 ); /* SOLID */ + cgm_edge_visibility ( ctxcanvas->cgm, 0 ); /* OFF */ + + cgm_end_metafile_defaults ( ctxcanvas->cgm ); + + cgm_font_list ( ctxcanvas->cgm, font_list ); +} + +/* +%F Pictire descriptor elements +*/ +static void picture_descriptor (cdCtxCanvas *ctxcanvas) +{ + cgm_scaling_mode ( ctxcanvas->cgm, 1 /* metric */, 1.0f ); + cgm_colour_selection_mode ( ctxcanvas->cgm, 1 /* direct */ ); + cgm_line_width_specify_mode ( ctxcanvas->cgm, 0 /* absolute=0, scaled=1 */ ); + cgm_marker_size_specify_mode ( ctxcanvas->cgm, 0 /* absolute=0, scaled=1 */ ); + + ctxcanvas->point = ftell ( ctxcanvas->cgm->file ); + if ( ctxcanvas->codificacao == CD_CLEAR_TEXT ) + { + fprintf ( ctxcanvas->cgm->file, "%80s\n", "" ); + fprintf ( ctxcanvas->cgm->file, "%80s\n", "" ); + } + else + { + cgm_vdc_extent( ctxcanvas->cgm, 0, 0, (double)ctxcanvas->canvas->w, (double)ctxcanvas->canvas->h); + } +} + +/* +%F Control descriptor elements +*/ +static void control_elements (cdCtxCanvas *ctxcanvas) +{ + double c[3] = {1.0,1.0,1.0}; + + cgm_vdc_integer_precision ( ctxcanvas->cgm, ctxcanvas->vdc_int_prec ); + cgm_vdc_real_precision ( ctxcanvas->cgm, 2 /* fixed 32 */ ); + cgm_auxiliary_colour ( ctxcanvas->cgm, c ); +} + +static void cdkillcanvas(cdCtxCanvas *ctxcanvas) +{ + long pt; + + pt = ftell ( ctxcanvas->cgm->file ); + fseek ( ctxcanvas->cgm->file, ctxcanvas->point, SEEK_SET ); + + if (ctxcanvas->hassize) + cgm_vdc_extent ( ctxcanvas->cgm, 0, 0, (double)ctxcanvas->canvas->w, (double)ctxcanvas->canvas->h); + else + { + if ( ctxcanvas->clip.first ) + cgm_vdc_extent ( ctxcanvas->cgm, ctxcanvas->b_box.xmin, ctxcanvas->b_box.ymin, ctxcanvas->b_box.xmax, ctxcanvas->b_box.ymax ); + else + cgm_vdc_extent ( ctxcanvas->cgm, ctxcanvas->clip.bbox.xmin, ctxcanvas->clip.bbox.ymin, ctxcanvas->clip.bbox.xmax, ctxcanvas->clip.bbox.ymax ); + } + + fseek ( ctxcanvas->cgm->file, pt, SEEK_SET ); + + cgm_end_picture ( ctxcanvas->cgm ); + cgm_end_metafile ( ctxcanvas->cgm ); + + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + free(ctxcanvas); +} + +static void cddeactivate(cdCtxCanvas *ctxcanvas) +{ + fflush(ctxcanvas->cgm->file); +} + +/* +%F Comeca uma nova pagina. +*/ +static void cdflush(cdCtxCanvas *ctxcanvas) +{ + long pt; + + pt = ftell ( ctxcanvas->cgm->file ); + fseek ( ctxcanvas->cgm->file, ctxcanvas->point, SEEK_SET ); + + if (ctxcanvas->hassize) + cgm_vdc_extent ( ctxcanvas->cgm, 0, 0, (double)ctxcanvas->canvas->w, (double)ctxcanvas->canvas->h); + else + { + if ( ctxcanvas->clip.first ) + cgm_vdc_extent ( ctxcanvas->cgm, ctxcanvas->b_box.xmin, ctxcanvas->b_box.ymin, + ctxcanvas->b_box.xmax, ctxcanvas->b_box.ymax ); + else + cgm_vdc_extent ( ctxcanvas->cgm, ctxcanvas->clip.bbox.xmin, ctxcanvas->clip.bbox.ymin, + ctxcanvas->clip.bbox.xmax, ctxcanvas->clip.bbox.ymax ); + } + + fseek ( ctxcanvas->cgm->file, pt, SEEK_SET ); + + cgm_end_picture ( ctxcanvas->cgm ); + + cgm_begin_picture ( ctxcanvas->cgm, "Picture x" ); + picture_descriptor ( ctxcanvas); + cgm_begin_picture_body ( ctxcanvas->cgm ); +} + + +/******************************************************/ +/* coordinate transformation */ +/******************************************************/ + +static int cdclip(cdCtxCanvas *ctxcanvas, int mode) +{ + if (mode == CD_CLIPPOLYGON) + return ctxcanvas->canvas->clip_mode; + + cgm_clip_indicator ( ctxcanvas->cgm, mode ); + + if (mode == CD_CLIPAREA) + cgm_clip_rectangle ( ctxcanvas->cgm, (double) ctxcanvas->canvas->clip_rect.xmin, (double) ctxcanvas->canvas->clip_rect.ymin, + (double) ctxcanvas->canvas->clip_rect.xmax, (double) ctxcanvas->canvas->clip_rect.ymax ); + + return mode; +} + +static void clip_bbox (cdCtxCanvas *ctxcanvas, double xmin, double ymin, double xmax, double ymax) +{ + if ( ctxcanvas->clip.first ) + { + ctxcanvas->clip.bbox.xmin = xmin; + ctxcanvas->clip.bbox.xmax = xmax; + ctxcanvas->clip.bbox.ymin = ymin; + ctxcanvas->clip.bbox.ymax = ymax; + ctxcanvas->clip.first = 0; + } + + if ( xmin < ctxcanvas->clip.bbox.xmin ) ctxcanvas->clip.bbox.xmin = xmin; + if ( ymin < ctxcanvas->clip.bbox.ymin ) ctxcanvas->clip.bbox.ymin = ymin; + if ( xmax > ctxcanvas->clip.bbox.xmax ) ctxcanvas->clip.bbox.xmax = xmax; + if ( ymax > ctxcanvas->clip.bbox.ymax ) ctxcanvas->clip.bbox.ymax = ymax; +} + +static void cdcliparea(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + if (ctxcanvas->canvas->clip_mode == CD_CLIPAREA) + cgm_clip_rectangle ( ctxcanvas->cgm, (double) xmin, (double) ymin, + (double) xmax, (double) ymax ); + + clip_bbox (ctxcanvas, (double)xmin, (double)ymin, (double)xmax, (double)ymax ); +} + +static void cdfcliparea(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + if (ctxcanvas->canvas->clip_mode == CD_CLIPAREA) + cgm_clip_rectangle ( ctxcanvas->cgm, xmin, ymin, xmax, ymax ); + + clip_bbox (ctxcanvas, xmin, ymin, xmax, ymax ); +} + +/******************************************************/ +/* primitives */ +/******************************************************/ + +static int cdinteriorstyle (cdCtxCanvas *ctxcanvas, int style); + +static void cdline(cdCtxCanvas *ctxcanvas, int px1, int py1, int px2, int py2) +{ + double points[4]; + + points[0] = (double)px1; + points[1] = (double)py1; + points[2] = (double)px2; + points[3] = (double)py2; + + cgm_polyline( ctxcanvas->cgm, 2, points); + + setbbox (ctxcanvas, points[0], points[1] ); + setbbox (ctxcanvas, points[2], points[3] ); +} + +static void cdfline(cdCtxCanvas *ctxcanvas, double px1, double py1, double px2, double py2) +{ + double points[4]; + + points[0] = px1; + points[1] = py1; + points[2] = px2; + points[3] = py2; + + cgm_polyline( ctxcanvas->cgm, 2, points); + + setbbox (ctxcanvas, points[0], points[1] ); + setbbox (ctxcanvas, points[2], points[3] ); +} + +static void cdrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + double points[4]; + + points[0] = (double)xmin; + points[1] = (double)ymin; + points[2] = (double)xmax; + points[3] = (double)ymax; + + cgm_interior_style ( ctxcanvas->cgm, HOLLOW); + cgm_rectangle( ctxcanvas->cgm, points); + cdinteriorstyle(ctxcanvas, ctxcanvas->canvas->interior_style); + + setbbox (ctxcanvas, points[0], points[1] ); + setbbox (ctxcanvas, points[2], points[1] ); + setbbox (ctxcanvas, points[2], points[3] ); + setbbox (ctxcanvas, points[0], points[3] ); +} + +static void cdfrect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + double points[4]; + + points[0] = xmin; + points[1] = ymin; + points[2] = xmax; + points[3] = ymax; + + cgm_interior_style ( ctxcanvas->cgm, HOLLOW); + cgm_rectangle( ctxcanvas->cgm, points); + cdinteriorstyle(ctxcanvas, ctxcanvas->canvas->interior_style); + + setbbox (ctxcanvas, points[0], points[1] ); + setbbox (ctxcanvas, points[2], points[1] ); + setbbox (ctxcanvas, points[2], points[3] ); + setbbox (ctxcanvas, points[0], points[3] ); +} + +static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + double points[4]; + + points[0] = (double)xmin; + points[1] = (double)ymin; + points[2] = (double)xmax; + points[3] = (double)ymax; + + cgm_rectangle( ctxcanvas->cgm, points); + + setbbox (ctxcanvas, points[0], points[1] ); + setbbox (ctxcanvas, points[2], points[1] ); + setbbox (ctxcanvas, points[2], points[3] ); + setbbox (ctxcanvas, points[0], points[3] ); +} + +static void cdfbox(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + double points[4]; + + points[0] = xmin; + points[1] = ymin; + points[2] = xmax; + points[3] = ymax; + + cgm_rectangle( ctxcanvas->cgm, points); + + setbbox (ctxcanvas, points[0], points[1] ); + setbbox (ctxcanvas, points[2], points[1] ); + setbbox (ctxcanvas, points[2], points[3] ); + setbbox (ctxcanvas, points[0], points[3] ); +} + +static void arc (cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2, + double *center, double *first_end_point, + double *second_end_point, double *dx_start, double *dy_start, + double *dx_end, double *dy_end ) +{ + double width, height; + + center[0] = xc; + center[1] = yc; + + width = w/2; + height = h/2; + + first_end_point[0] = center[0] + width; + first_end_point[1] = center[1]; + + second_end_point[0] = center[0]; + second_end_point[1] = center[1] + height; + + *dx_start = width*cos(a1*CD_DEG2RAD); + *dy_start = height*sin(a1*CD_DEG2RAD); + + *dx_end = width*cos(a2*CD_DEG2RAD); + *dy_end = height*sin(a2*CD_DEG2RAD); + + setbbox (ctxcanvas, center[0]-width, center[1]-height ); + setbbox (ctxcanvas, center[0]+width, center[1]-height ); + setbbox (ctxcanvas, center[0]+width, center[1]+height ); + setbbox (ctxcanvas, center[0]-width, center[1]+height ); +} + +static void cdarc(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + double center[2], first_end_point[2], second_end_point[2]; + double dx_start, dy_start, dx_end, dy_end; + + arc (ctxcanvas, (double)xc, (double)yc, (double)w, (double)h, a1, a2, center, first_end_point, second_end_point, + &dx_start, &dy_start, &dx_end, &dy_end ); + + cgm_elliptical_arc ( ctxcanvas->cgm, center, first_end_point, second_end_point, dx_start, dy_start, dx_end, dy_end ); +} + +static void cdfarc(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + double center[2], first_end_point[2], second_end_point[2]; + double dx_start, dy_start, dx_end, dy_end; + + arc (ctxcanvas, xc, yc, w, h, a1, a2, center, first_end_point, second_end_point, + &dx_start, &dy_start, &dx_end, &dy_end ); + + cgm_elliptical_arc ( ctxcanvas->cgm, center, first_end_point, second_end_point, dx_start, dy_start, dx_end, dy_end ); +} + +static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + double center[2], first_end_point[2], second_end_point[2]; + double dx_start, dy_start, dx_end, dy_end; + + arc (ctxcanvas, (double)xc, (double)yc, (double)w, (double)h, a1, a2, center, first_end_point, second_end_point, + &dx_start, &dy_start, &dx_end, &dy_end ); + + + cgm_elliptical_arc_close ( ctxcanvas->cgm, center, first_end_point, second_end_point, + dx_start, dy_start, dx_end, dy_end, 0 ); + + setbbox (ctxcanvas, (double)xc-w/2., (double)yc-h/2. ); + setbbox (ctxcanvas, (double)xc+w/2., (double)yc-h/2. ); + setbbox (ctxcanvas, (double)xc+w/2., (double)yc+h/2. ); + setbbox (ctxcanvas, (double)xc-w/2., (double)yc+h/2. ); +} + +static void cdfsector(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + double center[2], first_end_point[2], second_end_point[2]; + double dx_start, dy_start, dx_end, dy_end; + + arc (ctxcanvas, xc, yc, w, h, a1, a2, center, first_end_point, second_end_point, + &dx_start, &dy_start, &dx_end, &dy_end ); + + + cgm_elliptical_arc_close ( ctxcanvas->cgm, center, first_end_point, second_end_point, + dx_start, dy_start, dx_end, dy_end, 0 ); + + setbbox (ctxcanvas, xc-w/2., yc-h/2. ); + setbbox (ctxcanvas, xc+w/2., yc-h/2. ); + setbbox (ctxcanvas, xc+w/2., yc+h/2. ); + setbbox (ctxcanvas, xc-w/2., yc+h/2. ); +} + +static void settextbbox (cdCtxCanvas *ctxcanvas, double x, double y, int width, int height ) +{ + switch ( ctxcanvas->canvas->text_alignment ) + { + case CD_NORTH: + setbbox (ctxcanvas, x-(width/2.), y-height ); + setbbox (ctxcanvas, x+(width/2.), y ); + break; + case CD_SOUTH: + setbbox (ctxcanvas, x-(width/2.), y+height ); + setbbox (ctxcanvas, x+(width/2.), y ); + break; + case CD_EAST: + setbbox (ctxcanvas, x-width, y-(height/2.) ); + setbbox (ctxcanvas, x, y+(height/2.) ); + break; + case CD_WEST: + setbbox (ctxcanvas, x, y-(height/2.) ); + setbbox (ctxcanvas, x+width, y+(height/2.) ); + break; + case CD_NORTH_EAST: + setbbox (ctxcanvas, x-width, y-height ); + setbbox (ctxcanvas, x, y ); + break; + case CD_NORTH_WEST: + setbbox (ctxcanvas, x, y-height ); + setbbox (ctxcanvas, x+width, y ); + break; + case CD_SOUTH_EAST: + setbbox (ctxcanvas, x-width, y ); + setbbox (ctxcanvas, x, y+height ); + break; + case CD_SOUTH_WEST: + setbbox (ctxcanvas, x, y ); + setbbox (ctxcanvas, x+width, y+height ); + break; + case CD_CENTER: + setbbox (ctxcanvas, x-(width/2.), y-(height/2.) ); + setbbox (ctxcanvas, x+(width/2.), y+(height/2.) ); + break; + case CD_BASE_LEFT: + setbbox (ctxcanvas, x, y ); + setbbox (ctxcanvas, x+width, y+height ); + break; + case CD_BASE_CENTER: + setbbox (ctxcanvas, x-(width/2.), y ); + setbbox (ctxcanvas, x+(width/2.), y+height ); + break; + case CD_BASE_RIGHT: + setbbox (ctxcanvas, x-width, y ); + setbbox (ctxcanvas, x, y+height ); + break; + } +} + +static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *s) +{ + int width, height; + + cgm_text( ctxcanvas->cgm, 1 /* final */ , (double)x, (double)y, s ); + + cdCanvasGetTextSize(ctxcanvas->canvas, s, &width, &height); + + settextbbox (ctxcanvas, (double) x, (double) y, width, height ); +} + +static void cdftext(cdCtxCanvas *ctxcanvas, double x, double y, const char *s) +{ + int width, height; + + cgm_text( ctxcanvas->cgm, 1 /* final */ , x, y, s ); + + cdCanvasGetTextSize(ctxcanvas->canvas, s, &width, &height); + + settextbbox (ctxcanvas, x, y, width, height ); +} + +static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n) +{ + int i; + double *fpoly; + + fpoly = (double *)malloc(2 * (n+1) * sizeof(double)); + + for (i = 0; i < n; i++) + { + fpoly[2*i] = (double) poly[i].x; + fpoly[2*i+1] = (double) poly[i].y; + + setbbox (ctxcanvas, fpoly[2*i] , fpoly[2*i+1] ); + } + + switch ( mode ) + { + case CD_OPEN_LINES: + cgm_polyline( ctxcanvas->cgm, n, fpoly ); + break; + case CD_CLOSED_LINES: + fpoly[2*n] = fpoly[0]; + fpoly[2*n+1] = fpoly[1]; + n++; + cgm_polyline( ctxcanvas->cgm, n, fpoly ); + break; + case CD_FILL: + cgm_polygon( ctxcanvas->cgm, n, fpoly); + break; + } + + free(fpoly); +} + +static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n) +{ + int i; + double *fpoly = (double*)poly; + + for (i = 0; i < n; i++) + { + setbbox (ctxcanvas, fpoly[2*i] , fpoly[2*i+1] ); + } + + switch ( mode ) + { + case CD_OPEN_LINES: + cgm_polyline( ctxcanvas->cgm, n, fpoly ); + break; + case CD_CLOSED_LINES: + fpoly[2*n] = fpoly[0]; + fpoly[2*n+1] = fpoly[1]; + n++; + cgm_polyline( ctxcanvas->cgm, n, fpoly ); + break; + case CD_FILL: + cgm_polygon( ctxcanvas->cgm, n, fpoly); + break; + } +} + + +/******************************************************/ +/* attributes */ +/******************************************************/ + +static int cdlinestyle(cdCtxCanvas *ctxcanvas, int style) +{ + cgm_line_type( ctxcanvas->cgm, (long)(style + 1)); + return style; +} + +static int cdlinewidth(cdCtxCanvas *ctxcanvas, int width) +{ + cgm_line_width( ctxcanvas->cgm, (double)width ); + return width; +} + +static int cdinteriorstyle (cdCtxCanvas *ctxcanvas, int style ) +{ + switch ( style ) + { + case CD_SOLID: + style = 1; + break; + case CD_STIPPLE: + case CD_PATTERN: + style = 2; + break; + case CD_HATCH: + style = 3; + break; + } + + cgm_interior_style ( ctxcanvas->cgm, style ); + + return style; +} + +static int cdhatch(cdCtxCanvas *ctxcanvas, int style) +{ + int cgm_style = style; + + if ( cgm_style==2 ) + cgm_style = 3; + else if ( cgm_style==3 ) + cgm_style = 2; + + cgm_hatch_index ( ctxcanvas->cgm, (long)cgm_style+1 ); + + cgm_interior_style ( ctxcanvas->cgm, 3 ); + + return style; +} + +static void cdstipple(cdCtxCanvas *ctxcanvas, int n, int m, const unsigned char *stipple) +{ + double *pattab; + int i, j=0; + + pattab = (double *) malloc ( n*m*3*sizeof(double)); + + for ( i=0; i<n*m; i++ ) + { + pattab[j+0] = ( stipple[i] ) ? get_red(ctxcanvas->canvas->foreground) : get_red(ctxcanvas->canvas->background); + pattab[j+1] = ( stipple[i] ) ? get_green(ctxcanvas->canvas->foreground) : get_green(ctxcanvas->canvas->background); + pattab[j+2] = ( stipple[i] ) ? get_blue(ctxcanvas->canvas->foreground) : get_blue(ctxcanvas->canvas->background); + j+=3; + } + + cgm_pattern_table ( ctxcanvas->cgm, (long) ctxcanvas->patindex, (long) n, (long) m, (int) 8, pattab ); + cgm_pattern_index ( ctxcanvas->cgm, (long) ctxcanvas->patindex++ ); + free(pattab); + + cgm_interior_style ( ctxcanvas->cgm, 2 ); /* PATTERN */ +} + +static void cdpattern(cdCtxCanvas *ctxcanvas, int n, int m, const long int *pattern) +{ + double *pattab; + int i, j=0; + + pattab = (double *) malloc ( n*m*3*sizeof(double) ); + + for ( i=0; i<n*m; i++ ) + { + pattab[j+0] = get_red(pattern[i]); + pattab[j+1] = get_green(pattern[i]); + pattab[j+2] = get_blue(pattern[i]); + j+=3; + } + + cgm_pattern_table ( ctxcanvas->cgm, (long) ctxcanvas->patindex, (long) n, (long) m, (int) 8, pattab ); + cgm_pattern_index ( ctxcanvas->cgm, (long) ctxcanvas->patindex++ ); + free(pattab); + + cgm_interior_style ( ctxcanvas->cgm, 2 ); /* PATTERN */ +} + +static int cdfont(cdCtxCanvas *ctxcanvas, const char *type_face, int style, int size) +{ + long index = 0; + + if (cdStrEqualNoCase(type_face, "System")) + switch (style&3) + { + case CD_PLAIN: + index = 1; + break; + case CD_BOLD: + index = 5; + break; + case CD_ITALIC: + index = 9; + break; + case CD_BOLD_ITALIC: + index = 13; + break; + } + else if (cdStrEqualNoCase(type_face, "Courier")) + switch (style&3) + { + case CD_PLAIN: + index = 2; + break; + case CD_BOLD: + index = 6; + break; + case CD_ITALIC: + index = 10; + break; + case CD_BOLD_ITALIC: + index = 14; + break; + } + else if (cdStrEqualNoCase(type_face, "Times")) + switch (style&3) + { + case CD_PLAIN: + index = 3; + break; + case CD_BOLD: + index = 7; + break; + case CD_ITALIC: + index = 11; + break; + case CD_BOLD_ITALIC: + index = 15; + break; + } + else if (cdStrEqualNoCase(type_face, "Helvetica")) + switch (style&3) + { + case CD_PLAIN: + index = 4; + break; + case CD_BOLD: + index = 8; + break; + case CD_ITALIC: + index = 12; + break; + case CD_BOLD_ITALIC: + index = 16; + break; + } + + if (index == 0) return 0; + + cgm_char_height ( ctxcanvas->cgm, cdGetFontSizePixels(ctxcanvas->canvas, size)); + cgm_text_font_index( ctxcanvas->cgm, index ); + + return 1; +} + +static int cdtextalignment(cdCtxCanvas *ctxcanvas, int alignment) +{ + int hor = 0, ver = 0; + enum { NORMHORIZ, LEFT, CTR, RIGHT }; + enum { NORMVERT, TOP, CAP, HALF, BASE, BOTTOM }; + + switch ( alignment ) + { + case CD_NORTH: + hor = CTR; + ver = TOP; + break; + case CD_SOUTH: + hor = CTR; + ver = BOTTOM; + break; + case CD_EAST: + hor = RIGHT; + ver = HALF; + break; + case CD_WEST: + hor = LEFT; + ver = HALF; + break; + case CD_NORTH_EAST: + hor = RIGHT; + ver = TOP; + break; + case CD_NORTH_WEST: + hor = LEFT; + ver = TOP; + break; + case CD_SOUTH_EAST: + hor = RIGHT; + ver = BOTTOM; + break; + case CD_SOUTH_WEST: + hor = LEFT; + ver = BOTTOM; + break; + case CD_CENTER: + hor = CTR; + ver = HALF; + break; + case CD_BASE_LEFT: + hor = LEFT; + ver = BASE; + break; + case CD_BASE_CENTER: + hor = CTR; + ver = BASE; + break; + case CD_BASE_RIGHT: + hor = RIGHT; + ver = BASE; + break; + } + + cgm_text_alignment ( ctxcanvas->cgm, hor, ver , (double)0.0, (double)0.0 ); + + return alignment; +} + +/******************************************************/ +/* color */ +/******************************************************/ + +static long int cdforeground(cdCtxCanvas *ctxcanvas, long int color) +{ + double cor[3]; + + cor[0] = get_red(color); + cor[1] = get_green(color); + cor[2] = get_blue(color); + + cgm_text_colour( ctxcanvas->cgm, cor ); + cgm_fill_colour( ctxcanvas->cgm, cor ); + cgm_line_colour( ctxcanvas->cgm, cor ); + + return color; +} + +static long int cdbackground(cdCtxCanvas *ctxcanvas, long int color) +{ + double bc[3]; + + bc[0] = get_red(color); + bc[1] = get_green(color); + bc[2] = get_blue(color); + + ctxcanvas->canvas->background = color; + cgm_backgound_colour ( ctxcanvas->cgm, bc ); + + return color; +} + +static int cdbackopacity(cdCtxCanvas *ctxcanvas, int opaque) +{ + if (opaque == CD_TRANSPARENT) + cgm_transparency(ctxcanvas->cgm, 1); + else + cgm_transparency(ctxcanvas->cgm, 0); + return opaque; +} + +/******************************************************/ +/* client images */ +/******************************************************/ + +static void cdputimagerectrgb(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + double p[6]; + double *color_array; + int i,j,index,c; + int rw, rh; + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + + color_array = (double *) malloc ( rw*rh*3*sizeof(double) ); + if (!color_array) + return; + + p[0] = (double) x; p[1] = (double) (y+h); + p[2] = (double) (x+w); p[3] = (double) y; + p[4] = (double) (x+w); p[5] = (double) (y+h); + + for ( i=0; i<rh; i++ ) + { + for ( j=0; j<rw; j++ ) + { + index = (ih-i-1-ymin)*iw+j+xmin; + c = i*rw*3+j*3; + color_array[c] = (double) r[index]/255.; + color_array[c+1] = (double) g[index]/255.; + color_array[c+2] = (double) b[index]/255.; + } + } + + cgm_cell_array ( ctxcanvas->cgm, p, (long)rw, (long)rh, 8, color_array ); + + free(color_array); + + setbbox (ctxcanvas, p[0], p[1] ); + setbbox (ctxcanvas, p[2], p[3] ); +} + +static void cdputimagerectmap(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *index, const long int *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + double p[6]; + double *color_array; + int i,j,c; + unsigned char r, g, b; + int rw, rh; + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + + color_array = (double *) malloc ( rw*rh*3*sizeof(double) ); + if (!color_array) + return; + + p[0] = (double) x; p[1] = (double) y; + p[2] = (double) (x+w); p[3] = (double) (y+h); + p[4] = (double) (x+w); p[5] = (double) y; + + for ( i=0; i<rh; i++ ) + { + for ( j=0; j<rw; j++ ) + { + c = i*rw*3+j*3; + cdDecodeColor(colors[index[(ih-i-1-ymin)*iw+j+xmin]], &r,&b,&g); + color_array[c] = ((double)r)/255.; + color_array[c+1] = ((double)g)/255.; + color_array[c+2] = ((double)b)/255.; + } + } + + cgm_cell_array ( ctxcanvas->cgm, p, (long)rw, (long)rh, 8, color_array ); + + free(color_array); + + setbbox (ctxcanvas, p[0], p[1] ); + setbbox (ctxcanvas, p[2], p[3] ); +} + +/******************************************************/ +/* server images */ +/******************************************************/ + +static void cdpixel(cdCtxCanvas *ctxcanvas, int x, int y, long int color) +{ + double cor[3]; + double pts[2]; + + pts[0] = (double) x; + pts[1] = (double) y; + + cor[0] = get_red(color); + cor[1] = get_green(color); + cor[2] = get_blue(color); + + cgm_marker_colour( ctxcanvas->cgm, cor); + cgm_polymarker ( ctxcanvas->cgm, 1, pts ); +} + +/* +%F Cria um canvas CGM. +Parametros passados em data: +[nome] nome do arquivo de saida <= 255 caracteres +[size] tamanho do papel +-t codificacao clear text se nao binaria +*/ +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + cdCtxCanvas *ctxcanvas; + char *line = (char *)data; + char c; + char words[4][256]; + char filename[10240] = ""; + double w=0, h=0, r=0; + int p=0; + int i, n; + + line += cdGetFileName(line, filename); + if (filename[0] == 0) + return; + + n = sscanf(line, "%s %s %s %s", words[0], words[1], words[2], words[3]); + + ctxcanvas = (cdCtxCanvas *)malloc(sizeof(cdCtxCanvas)); + + canvas->ctxcanvas = ctxcanvas; + ctxcanvas->canvas = canvas; + + strcpy(ctxcanvas->filename, filename); + + canvas->w_mm = (double)INT_MAX*3.78; + canvas->h_mm = (double)INT_MAX*3.78; + canvas->xres = 3.78; + canvas->yres = 3.78; + canvas->bpp = 24; + + ctxcanvas->vdc_int_prec = 16; + ctxcanvas->codificacao = CD_BIN; + ctxcanvas->first = 1; + ctxcanvas->clip.first = 1; + ctxcanvas->patindex = 1; + + ctxcanvas->hassize = 0; /* Indica se foi passado um tamanho para o canvas */ + + for (i = 0; i < n; i++) + { + if (sscanf ( words[i], "%lgx%lg", &w, &h )== 2) + { + canvas->w_mm = w; + canvas->h_mm = h; + ctxcanvas->hassize = 1; + } + else if (sscanf ( words[i], "%lg", &r ) == 1) + canvas->yres = canvas->xres = r; + else if (sscanf ( words[i], "-%c%d", &c, &p )>0) + { + if ( c=='t' ) + ctxcanvas->codificacao = CD_CLEAR_TEXT; + else if ( c=='p' ) + ctxcanvas->vdc_int_prec = p; + } + } + + if ( ctxcanvas->vdc_int_prec != 16 && w == 0.0 && h == 0.0 ) + { + canvas->w_mm = (double) (pow(2,p)/2)-1; + canvas->h_mm = (double) (pow(2,p)/2)-1; + } + + /* update canvas context */ + canvas->w = (int)(canvas->w_mm * canvas->xres); + canvas->h = (int)(canvas->h_mm * canvas->yres); + + ctxcanvas->cgm = cgm_begin_metafile ( ctxcanvas->filename, ctxcanvas->codificacao, "CD - CanvasDraw, Tecgraf/PUC-RIO" ); + + metafile_descriptor(ctxcanvas); + + cgm_begin_picture ( ctxcanvas->cgm, "Picture x" ); + + picture_descriptor (ctxcanvas); + + cgm_clip_rectangle ( ctxcanvas->cgm, 0, 0, (double)canvas->w, (double)canvas->h); + cgm_clip_indicator (ctxcanvas->cgm, 0); + + cgm_begin_picture_body ( ctxcanvas->cgm ); + + control_elements (ctxcanvas); + + cgm_marker_type( ctxcanvas->cgm, MARKER_DOT); + cgm_marker_size( ctxcanvas->cgm, 1.0); +} + +static void cdinittable(cdCanvas* canvas) +{ + /* initialize function table*/ + canvas->cxFlush = cdflush; + canvas->cxPixel = cdpixel; + canvas->cxLine = cdline; + canvas->cxPoly = cdpoly; + canvas->cxRect = cdrect; + canvas->cxBox = cdbox; + canvas->cxArc = cdarc; + canvas->cxSector = cdsector; + canvas->cxText = cdtext; + canvas->cxFLine = cdfline; + canvas->cxFPoly = cdfpoly; + canvas->cxFRect = cdfrect; + canvas->cxFBox = cdfbox; + canvas->cxFArc = cdfarc; + canvas->cxFSector = cdfsector; + canvas->cxFText = cdftext; + canvas->cxPutImageRectRGB = cdputimagerectrgb; + canvas->cxPutImageRectMap = cdputimagerectmap; + + canvas->cxClip = cdclip; + canvas->cxClipArea = cdcliparea; + canvas->cxFClipArea = cdfcliparea; + canvas->cxLineStyle = cdlinestyle; + canvas->cxLineWidth = cdlinewidth; + canvas->cxInteriorStyle = cdinteriorstyle; + canvas->cxHatch = cdhatch; + canvas->cxStipple = cdstipple; + canvas->cxPattern = cdpattern; + canvas->cxFont = cdfont; + canvas->cxTextAlignment = cdtextalignment; + canvas->cxBackground = cdbackground; + canvas->cxForeground = cdforeground; + canvas->cxBackOpacity = cdbackopacity; + + canvas->cxKillCanvas = cdkillcanvas; + canvas->cxDeactivate = cddeactivate; +} + +/******************************************************/ + +static cdContext cdCGMContext = +{ + CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_PALETTE | + CD_CAP_CLIPPOLY | CD_CAP_WRITEMODE | CD_CAP_IMAGESRV | + CD_CAP_LINECAP | CD_CAP_LINEJOIN | CD_CAP_REGION | CD_CAP_CHORD | + CD_CAP_FONTDIM | CD_CAP_TEXTSIZE | + CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB | + CD_CAP_TEXTORIENTATION), + 0, + cdcreatecanvas, + cdinittable, + cdplayCGM, + cdRegisterCallbackCGM, +}; + +cdContext* cdContextCGM(void) +{ + return &cdCGMContext; +} + diff --git a/src/drv/cddebug.c b/src/drv/cddebug.c new file mode 100644 index 0000000..5532568 --- /dev/null +++ b/src/drv/cddebug.c @@ -0,0 +1,729 @@ +/** \file + * \brief CD DEBUG driver + * + * See Copyright Notice in cd.h + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +#include "cd.h" +#include "wd.h" +#include "cd_private.h" +#include "cddebug.h" + + +#define CDDBG_FLUSH "Flush" +#define CDDBG_CLEAR "Clear" +#define CDDBG_CLIP "Clip" +#define CDDBG_CLIPAREA "Cliparea" +#define CDDBG_LINE "Line" +#define CDDBG_BOX "Box" +#define CDDBG_ARC "Arc" +#define CDDBG_SECTOR "Sector" +#define CDDBG_TEXT "Text" +#define CDDBG_BEGIN "Begin" +#define CDDBG_VERTEX "Vertex" +#define CDDBG_END "End" +#define CDDBG_MARK "Mark" +#define CDDBG_BACKOPACITY "BackOpacity" +#define CDDBG_WRITEMODE "WriteMode" +#define CDDBG_LINESTYLE "LineStyle" +#define CDDBG_LINEWIDTH "LineWidth" +#define CDDBG_INTERIORSTYLE "InteriorStyle" +#define CDDBG_HATCH "Hatch" +#define CDDBG_STIPPLE "Stipple" +#define CDDBG_PATTERN "Pattern" +#define CDDBG_NATIVEFONT "NativeFont" +#define CDDBG_TEXTALIGNMENT "TextAlignment" +#define CDDBG_PALETTE "Palette" +#define CDDBG_BACKGROUND "Background" +#define CDDBG_FOREGROUND "Foreground" +#define CDDBG_PIXEL "Pixel" +#define CDDBG_SCROLLAREA "ScrollArea" +#define CDDBG_TEXTORIENTATION "TextOrientation" +#define CDDBG_RECT "Rect" +#define CDDBG_FILLMODE "FillMode" +#define CDDBG_LINESTYLEDASHES "LineStyleDashes" +#define CDDBG_LINECAP "LineCap" +#define CDDBG_LINEJOIN "LineJoin" +#define CDDBG_CHORD "Chord" +#define CDDBG_FLINE "fLine" +#define CDDBG_FRECT "fRect" +#define CDDBG_FBOX "fBox" +#define CDDBG_FARC "fArc" +#define CDDBG_FSECTOR "fSector" +#define CDDBG_FTEXT "fText" +#define CDDBG_FVERTEX "fVertex" +#define CDDBG_MATRIX "Matrix" +#define CDDBG_FCHORD "fChord" +#define CDDBG_FCLIPAREA "fClipArea" +#define CDDBG_FONT "Font" +#define CDDBG_PUTIMAGERGB "PutImageRGB" +#define CDDBG_PUTIMAGERGBA "PutImageRGBA" +#define CDDBG_PUTIMAGEMAP "PutImageMap" + +struct _cdCtxCanvas +{ + cdCanvas* canvas; + char* filename; + FILE* file; + int last_line_style; + int last_fill_mode; +}; + +struct _cdCtxImage { + cdCtxCanvas *ctxcanvas; +}; + +static void cdflush(cdCtxCanvas *ctxcanvas) +{ + fflush(ctxcanvas->file); + fprintf(ctxcanvas->file, "%s()\n", CDDBG_FLUSH); +} + +static void cdclear(cdCtxCanvas *ctxcanvas) +{ + fprintf(ctxcanvas->file, "%s()\n", CDDBG_CLEAR); +} + +static int cdclip(cdCtxCanvas *ctxcanvas, int mode) +{ + const char* enum2str[] = { + "CD_CLIPOFF", + "CD_CLIPAREA", + "CD_CLIPPOLYGON", + "CD_CLIPREGION" + }; + fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_CLIP, enum2str[mode]); + return mode; +} + +static void cdcliparea(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + fprintf(ctxcanvas->file, "%s(%d, %d, %d, %d)\n", CDDBG_CLIPAREA, xmin, xmax, ymin, ymax); +} + +static void cdfcliparea(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + fprintf(ctxcanvas->file, "%s(%g, %g, %g, %g)\n", CDDBG_FCLIPAREA, xmin, xmax, ymin, ymax); +} + +static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix) +{ + if (matrix) + fprintf(ctxcanvas->file, "%s(%g, %g, %g, %g, %g, %g)\n", CDDBG_MATRIX, matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]); + else + fprintf(ctxcanvas->file, "%s(NULL)\n", CDDBG_MATRIX); +} + +static void cdline(cdCtxCanvas *ctxcanvas, int x1, int y1, int x2, int y2) +{ + fprintf(ctxcanvas->file, "%s(%d, %d, %d, %d)\n", CDDBG_LINE, x1, y1, x2, y2); +} + +static void cdfline(cdCtxCanvas *ctxcanvas, double x1, double y1, double x2, double y2) +{ + fprintf(ctxcanvas->file, "%s(%g, %g, %g, %g)\n", CDDBG_FLINE, x1, y1, x2, y2); +} + +static void cdrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + fprintf(ctxcanvas->file, "%s(%d, %d, %d, %d)\n", CDDBG_RECT, xmin, xmax, ymin, ymax); +} + +static void cdfrect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + fprintf(ctxcanvas->file, "%s(%g, %g, %g, %g)\n", CDDBG_FRECT, xmin, xmax, ymin, ymax); +} + +static const char* get_region_mode(int combine_mode) +{ + const char* enum2str[] = { + "CD_UNION", + "CD_INTERSECT", + "CD_DIFFERENCE", + "CD_NOTINTERSECT" + }; + return enum2str[combine_mode]; +} + +static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + if (ctxcanvas->canvas->new_region) + fprintf(ctxcanvas->file, "%sRegion(%d, %d, %d, %d, %s)\n", CDDBG_BOX, xmin, xmax, ymin, ymax, get_region_mode(ctxcanvas->canvas->combine_mode)); + else + fprintf(ctxcanvas->file, "%s(%d, %d, %d, %d)\n", CDDBG_BOX, xmin, xmax, ymin, ymax); +} + +static void cdfbox(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + if (ctxcanvas->canvas->new_region) + fprintf(ctxcanvas->file, "%sRegion(%g, %g, %g, %g, %s)\n", CDDBG_FBOX, xmin, xmax, ymin, ymax, get_region_mode(ctxcanvas->canvas->combine_mode)); + else + fprintf(ctxcanvas->file, "%s(%g, %g, %g, %g)\n", CDDBG_FBOX, xmin, xmax, ymin, ymax); +} + +static void cdarc(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + fprintf(ctxcanvas->file, "%s(%d, %d, %d, %d, %g, %g)\n", CDDBG_ARC, xc, yc, w, h, a1, a2); +} + +static void cdfarc(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + fprintf(ctxcanvas->file, "%s(%g, %g, %g, %g, %g, %g)\n", CDDBG_FARC, xc, yc, w, h, a1, a2); +} + +static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + if (ctxcanvas->canvas->new_region) + fprintf(ctxcanvas->file, "%sRegion(%d, %d, %d, %d, %g, %g, %s)\n", CDDBG_SECTOR, xc, yc, w, h, a1, a2, get_region_mode(ctxcanvas->canvas->combine_mode)); + else + fprintf(ctxcanvas->file, "%s(%d, %d, %d, %d, %g, %g)\n", CDDBG_SECTOR, xc, yc, w, h, a1, a2); +} + +static void cdfsector(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + if (ctxcanvas->canvas->new_region) + fprintf(ctxcanvas->file, "%sRegion(%g, %g, %g, %g, %g, %g, %s)\n", CDDBG_FSECTOR, xc, yc, w, h, a1, a2, get_region_mode(ctxcanvas->canvas->combine_mode)); + else + fprintf(ctxcanvas->file, "%s(%g, %g, %g, %g, %g, %g)\n", CDDBG_FSECTOR, xc, yc, w, h, a1, a2); +} + +static void cdchord(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + if (ctxcanvas->canvas->new_region) + fprintf(ctxcanvas->file, "%sRegion(%d, %d, %d, %d, %g, %g, %s)\n", CDDBG_CHORD, xc, yc, w, h, a1, a2, get_region_mode(ctxcanvas->canvas->combine_mode)); + else + fprintf(ctxcanvas->file, "%s(%d, %d, %d, %d, %g, %g)\n", CDDBG_CHORD, xc, yc, w, h, a1, a2); +} + +static void cdfchord(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + if (ctxcanvas->canvas->new_region) + fprintf(ctxcanvas->file, "%sRegion(%g, %g, %g, %g, %g, %g, %s)\n", CDDBG_FCHORD, xc, yc, w, h, a1, a2, get_region_mode(ctxcanvas->canvas->combine_mode)); + else + fprintf(ctxcanvas->file, "%s(%g, %g, %g, %g, %g, %g)\n", CDDBG_FCHORD, xc, yc, w, h, a1, a2); +} + +static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *text) +{ + if (ctxcanvas->canvas->new_region) + fprintf(ctxcanvas->file, "%sRegion(%d, %d, \"%s\", %s)\n", CDDBG_TEXT, x, y, text, get_region_mode(ctxcanvas->canvas->combine_mode)); + else + fprintf(ctxcanvas->file, "%s(%d, %d, \"%s\")\n", CDDBG_TEXT, x, y, text); +} + +static void cdftext(cdCtxCanvas *ctxcanvas, double x, double y, const char *text) +{ + if (ctxcanvas->canvas->new_region) + fprintf(ctxcanvas->file, "%sRegion(%g, %g, \"%s\", %s)\n", CDDBG_FTEXT, x, y, text, get_region_mode(ctxcanvas->canvas->combine_mode)); + else + fprintf(ctxcanvas->file, "%s(%g, %g, \"%s\")\n", CDDBG_FTEXT, x, y, text); +} + +static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n) +{ + int i; + const char* enum2str[] = { + "CD_FILL", + "CD_OPEN_LINES", + "CD_CLOSED_LINES", + "CD_CLIP", + "CD_BEZIER", + "CD_REGION" + }; + + if (mode == CD_FILL && ctxcanvas->canvas->fill_mode != ctxcanvas->last_fill_mode) + { + const char* enum2str[] = { + "CD_EVENODD", + "CD_WINDING" + }; + fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_FILLMODE, enum2str[ctxcanvas->canvas->fill_mode]); + ctxcanvas->last_fill_mode = ctxcanvas->canvas->fill_mode; + } + + if (ctxcanvas->canvas->new_region) + fprintf(ctxcanvas->file, "%sRegion(%s, %s)\n", CDDBG_BEGIN, enum2str[mode], get_region_mode(ctxcanvas->canvas->combine_mode)); + else + fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_BEGIN, enum2str[mode]); + + for(i = 0; i<n; i++) + fprintf(ctxcanvas->file, "%s(%d, %d)\n", CDDBG_VERTEX, poly[i].x, poly[i].y); + + fprintf(ctxcanvas->file, "%s()\n", CDDBG_END); +} + +static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n) +{ + int i; + const char* enum2str[] = { + "CD_FILL", + "CD_OPEN_LINES", + "CD_CLOSED_LINES", + "CD_CLIP", + "CD_BEZIER", + "CD_REGION" + }; + + if (mode == CD_FILL && ctxcanvas->canvas->fill_mode != ctxcanvas->last_fill_mode) + { + const char* enum2str[] = { + "CD_EVENODD", + "CD_WINDING" + }; + fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_FILLMODE, enum2str[ctxcanvas->canvas->fill_mode]); + ctxcanvas->last_fill_mode = ctxcanvas->canvas->fill_mode; + } + + fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_BEGIN, enum2str[mode]); + + for(i = 0; i<n; i++) + fprintf(ctxcanvas->file, "%s(%g, %g)\n", CDDBG_FVERTEX, poly[i].x, poly[i].y); + + fprintf(ctxcanvas->file, "%s()\n", CDDBG_END); +} + +static int cdbackopacity(cdCtxCanvas *ctxcanvas, int opacity) +{ + const char* enum2str[] = { + "CD_OPAQUE", + "CD_TRANSPARENT" + }; + fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_BACKOPACITY, enum2str[opacity]); + return opacity; +} + +static int cdwritemode(cdCtxCanvas *ctxcanvas, int mode) +{ + const char* enum2str[] = { + "CD_REPLACE", + "CD_XOR", + "CD_NOT_XOR" + }; + fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_WRITEMODE, enum2str[mode]); + return mode; +} + +static int cdlinestyle(cdCtxCanvas *ctxcanvas, int style) +{ + const char* enum2str[] = { + "CD_CONTINUOUS", + "CD_DASHED", + "CD_DOTTED", + "CD_DASH_DOT", + "CD_DASH_DOT_DOT", + "CD_CUSTOM" + }; + + if (style == CD_CUSTOM && ctxcanvas->canvas->line_style != ctxcanvas->last_line_style) + { + int i; + + fprintf(ctxcanvas->file, "%s(%d", CDDBG_LINESTYLEDASHES, ctxcanvas->canvas->line_dashes_count); + for (i = 0; i < ctxcanvas->canvas->line_dashes_count; i++) + fprintf(ctxcanvas->file, ", %d", ctxcanvas->canvas->line_dashes[i]); + fprintf(ctxcanvas->file, ")\n"); + + ctxcanvas->last_line_style = ctxcanvas->canvas->line_style; + } + + fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_LINESTYLE, enum2str[style]); + return style; +} + +static int cdlinewidth(cdCtxCanvas *ctxcanvas, int width) +{ + fprintf(ctxcanvas->file, "%s(%d)\n", CDDBG_LINEWIDTH, width); + return width; +} + +static int cdlinecap(cdCtxCanvas *ctxcanvas, int cap) +{ + const char* enum2str[] = { + "CD_CAPFLAT", + "CD_CAPSQUARE", + "CD_CAPROUND" + }; + fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_LINECAP, enum2str[cap]); + return cap; +} + +static int cdlinejoin(cdCtxCanvas *ctxcanvas, int join) +{ + const char* enum2str[] = { + "CD_MITER", + "CD_BEVEL", + "CD_ROUND" + }; + fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_LINEJOIN, enum2str[join]); + return join; +} + +static int cdinteriorstyle(cdCtxCanvas *ctxcanvas, int style) +{ + const char* enum2str[] = { + "CD_SOLID", + "CD_HATCH", + "CD_STIPPLE", + "CD_PATTERN", + "CD_HOLLOW" + }; + fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_INTERIORSTYLE, enum2str[style]); + return style; +} + +static int cdhatch(cdCtxCanvas *ctxcanvas, int style) +{ + const char* enum2str[] = { + "CD_HORIZONTAL", + "CD_VERTICAL", + "CD_FDIAGONAL", + "CD_BDIAGONAL", + "CD_CROSS", + "CD_DIAGCROSS" + }; + fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_HATCH, enum2str[style]); + return style; +} + +static void cdstipple(cdCtxCanvas *ctxcanvas, int w, int h, const unsigned char *stipple) +{ + fprintf(ctxcanvas->file, "%s(%d, %d, %p)\n", CDDBG_STIPPLE, w, h, stipple); +} + +static void cdpattern(cdCtxCanvas *ctxcanvas, int w, int h, const long int *pattern) +{ + fprintf(ctxcanvas->file, "%s(%d, %d, %p)\n", CDDBG_PATTERN, w, h, pattern); +} + +static int cdfont(cdCtxCanvas *ctxcanvas, const char* type_face, int style, int size) +{ + char style_str[50] = ""; + if (style & CD_BOLD) + strcat(style_str, "CD_BOLD"); + if (style & CD_ITALIC) + { + if (style_str[0]!=0) strcat(style_str, "|"); + strcat(style_str, "CD_ITALIC"); + } + if (style & CD_UNDERLINE) + { + if (style_str[0]!=0) strcat(style_str, "|"); + strcat(style_str, "CD_UNDERLINE"); + } + if (style & CD_STRIKEOUT) + { + if (style_str[0]!=0) strcat(style_str, "|"); + strcat(style_str, "CD_STRIKEOUT"); + } + if (style_str[0]==0) strcat(style_str, "CD_PLAIN"); + fprintf(ctxcanvas->file, "%s(\"%s\", %s, %d)\n", CDDBG_FONT, type_face, style_str, size); + return 1; +} + +static int cdnativefont(cdCtxCanvas *ctxcanvas, const char* font) +{ + fprintf(ctxcanvas->file, "%s(\"%s\")\n", CDDBG_NATIVEFONT, font); + return 1; +} + +static int cdtextalignment(cdCtxCanvas *ctxcanvas, int alignment) +{ + const char* enum2str[] = { + "CD_NORTH", + "CD_SOUTH", + "CD_EAST", + "CD_WEST", + "CD_NORTH_EAST", + "CD_NORTH_WEST", + "CD_SOUTH_EAST", + "CD_SOUTH_WEST", + "CD_CENTER", + "CD_BASE_LEFT", + "CD_BASE_CENTER", + "CD_BASE_RIGHT" + }; + fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_TEXTALIGNMENT, enum2str[alignment]); + return alignment; +} + +static double cdtextorientation(cdCtxCanvas *ctxcanvas, double angle) +{ + fprintf(ctxcanvas->file, "%s(%g)\n", CDDBG_TEXTORIENTATION, angle); + return angle; +} + +static void cdpalette(cdCtxCanvas *ctxcanvas, int n, const long int *palette, int mode) +{ + const char* enum2str[] = { + "CD_POLITE", + "CD_FORCE" + }; + fprintf(ctxcanvas->file, "%s(%d, %p, %s)\n", CDDBG_PALETTE, n, palette, enum2str[mode]); +} + +static long cdbackground(cdCtxCanvas *ctxcanvas, long int color) +{ + unsigned char r, g, b; + cdDecodeColor(color, &r, &g, &b); + fprintf(ctxcanvas->file, "%s(%d, %d, %d)\n", CDDBG_BACKGROUND, (int)r, (int)g, (int)b); + return color; +} + +static long cdforeground(cdCtxCanvas *ctxcanvas, long int color) +{ + unsigned char r, g, b; + cdDecodeColor(color, &r, &g, &b); + fprintf(ctxcanvas->file, "%s(%d, %d, %d)\n", CDDBG_FOREGROUND, (int)r, (int)g, (int)b); + return color; +} + +static void cdputimagerectrgb(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + fprintf(ctxcanvas->file, "%s(%d, %d, %p, %p, %p, %d, %d, %d, %d, %d, %d, %d, %d)\n", CDDBG_PUTIMAGERGB, iw, ih, r, g, b, x, y, w, h, xmin, xmax, ymin, ymax); +} + +static void cdputimagerectrgba(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, const unsigned char *a, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + fprintf(ctxcanvas->file, "%s(%d, %d, %p, %p, %p, %p, %d, %d, %d, %d, %d, %d, %d, %d)\n", CDDBG_PUTIMAGERGBA, iw, ih, r, g, b, a, x, y, w, h, xmin, xmax, ymin, ymax); +} + +static void cdputimagerectmap(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *index, const long int *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + fprintf(ctxcanvas->file, "%s(%d, %d, %p, %p, %d, %d, %d, %d, %d, %d, %d, %d)\n", CDDBG_PUTIMAGEMAP, iw, ih, index, colors, x, y, w, h, xmin, xmax, ymin, ymax); +} + +static void cdpixel(cdCtxCanvas *ctxcanvas, int x, int y, long int color) +{ + unsigned char r, g, b; + cdDecodeColor(color, &r, &g, &b); + fprintf(ctxcanvas->file, "%s(%d, %d, %d, %d, %d)\n", CDDBG_PIXEL, x, y, (int)r, (int)g, (int)b); +} + +static void cdscrollarea(cdCtxCanvas *ctxcanvas, int xmin,int xmax, int ymin,int ymax, int dx,int dy) +{ + fprintf(ctxcanvas->file, "%s(%d, %d, %d, %d, %d, %d)\n", CDDBG_SCROLLAREA, xmin, xmax, ymin, ymax, dx, dy); +} + +static void cdgetimagergb(cdCtxCanvas* ctxcanvas, unsigned char *r, unsigned char *g, unsigned char *b, int x, int y, int w, int h) +{ + fprintf(ctxcanvas->file, "%p, %p, %p = GetImageRGB(%d, %d, %d, %d)\n", r, g, b, x, y, w, h); +} + +static cdCtxImage* cdcreateimage(cdCtxCanvas* ctxcanvas, int w, int h) +{ + cdCtxImage* ctximage = malloc(sizeof(cdCtxImage)); + ctximage->ctxcanvas = ctxcanvas; + fprintf(ctxcanvas->file, "%p = GetImage(%d, %d)\n", ctximage, w, h); + return ctximage; +} + +static void cdkillimage(cdCtxImage* ctximage) +{ + fprintf(ctximage->ctxcanvas->file, "KillImage(%p)\n", ctximage); + free(ctximage); +} + +static void cdgetimage(cdCtxCanvas* ctxcanvas, cdCtxImage* ctximage, int x, int y) +{ + fprintf(ctxcanvas->file, "GetImage(%p, %d, %d)\n", ctximage, x, y); +} + +static void cdputimagerect(cdCtxCanvas* ctxcanvas, cdCtxImage* ctximage, int x, int y, int xmin, int xmax, int ymin, int ymax) +{ + fprintf(ctxcanvas->file, "PutImage(%p, %d, %d, %d, %d, %d, %d)\n", ctximage, x, y, xmin, xmax, ymin, ymax); +} + +static void cdnewregion(cdCtxCanvas* ctxcanvas) +{ + fprintf(ctxcanvas->file, "NewRegion()\n"); +} + +static int cdispointinregion(cdCtxCanvas* ctxcanvas, int x, int y) +{ + fprintf(ctxcanvas->file, "IsPointInRegion(%d, %d)\n", x, y); + return 0; +} + +static void cdoffsetregion(cdCtxCanvas* ctxcanvas, int x, int y) +{ + fprintf(ctxcanvas->file, "OffsetRegion(%d, %d)\n", x, y); +} + +static void cdgetregionbox(cdCtxCanvas* ctxcanvas, int *xmin, int *xmax, int *ymin, int *ymax) +{ + (void)xmin; + (void)ymin; + (void)xmax; + (void)ymax; + fprintf(ctxcanvas->file, "GetRegionBox()\n"); +} + +static int cdactivate(cdCtxCanvas* ctxcanvas) +{ + fprintf(ctxcanvas->file, "Activate()\n"); + return CD_OK; +} + +static void cddeactivate(cdCtxCanvas* ctxcanvas) +{ + fprintf(ctxcanvas->file, "Deactivate()\n"); +} + +static void cdgetfontdim(cdCtxCanvas* ctxcanvas, int *max_width, int *height, int *ascent, int *descent) +{ + int tmp_max_width, tmp_height, tmp_ascent, tmp_descent; + if (!max_width) max_width = &tmp_max_width; + if (!height) height = &tmp_height; + if (!ascent) ascent = &tmp_ascent; + if (!descent) descent = &tmp_descent; + cdgetfontdimEX(ctxcanvas, max_width, height, ascent, descent); + fprintf(ctxcanvas->file, "%d, %d, %d, %d = GetFontDim()\n", *max_width, *height, *ascent, *descent); +} + +static void cdgettextsize(cdCtxCanvas* ctxcanvas, const char *s, int *width, int *height) +{ + int tmp_width, tmp_height; + if (!width) width = &tmp_width; + if (!height) height = &tmp_height; + cdgettextsizeEX(ctxcanvas, s, width, height); + fprintf(ctxcanvas->file, "%d, %d = GetTextSize(\"%s\")\n", *width, *height, s); +} + +static void cdkillcanvas(cdCtxCanvas *ctxcanvas) +{ + fprintf(ctxcanvas->file, "KillCanvas()\n"); + free(ctxcanvas->filename); + fclose(ctxcanvas->file); + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + free(ctxcanvas); +} + +static void cdcreatecanvas(cdCanvas *canvas, void *data) +{ + char filename[10240] = ""; + char* strdata = (char*)data; + double w_mm = INT_MAX*3.78, h_mm = INT_MAX*3.78, res = 3.78; + cdCtxCanvas* ctxcanvas; + int size; + + strdata += cdGetFileName(strdata, filename); + if (filename[0] == 0) + return; + + sscanf(strdata, "%lgx%lg %lg", &w_mm, &h_mm, &res); + + ctxcanvas = (cdCtxCanvas *)malloc(sizeof(cdCtxCanvas)); + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + + ctxcanvas->file = fopen(filename, "w"); + if (!ctxcanvas->file) + { + free(ctxcanvas); + return; + } + + size = strlen(filename); + ctxcanvas->filename = malloc(size+1); + memcpy(ctxcanvas->filename, filename, size+1); + + ctxcanvas->canvas = canvas; + + /* update canvas context */ + canvas->w = (int)(w_mm * res); + canvas->h = (int)(h_mm * res); + canvas->w_mm = w_mm; + canvas->h_mm = h_mm; + canvas->bpp = 24; + canvas->xres = res; + canvas->yres = res; + canvas->ctxcanvas = ctxcanvas; + + ctxcanvas->last_line_style = -1; + ctxcanvas->last_fill_mode = -1; + + fprintf(ctxcanvas->file, "CreateCanvas(CD_DEBUG, \"%s\")\n", (char*)data); +} + +static void cdinittable(cdCanvas* canvas) +{ + canvas->cxFlush = cdflush; + canvas->cxClear = cdclear; + canvas->cxPixel = cdpixel; + canvas->cxLine = cdline; + canvas->cxPoly = cdpoly; + canvas->cxRect = cdrect; + canvas->cxBox = cdbox; + canvas->cxArc = cdarc; + canvas->cxSector = cdsector; + canvas->cxChord = cdchord; + canvas->cxText = cdtext; + canvas->cxPutImageRectRGB = cdputimagerectrgb; + canvas->cxPutImageRectRGBA = cdputimagerectrgba; + canvas->cxPutImageRectMap = cdputimagerectmap; + canvas->cxScrollArea = cdscrollarea; + canvas->cxFLine = cdfline; + canvas->cxFPoly = cdfpoly; + canvas->cxFRect = cdfrect; + canvas->cxFBox = cdfbox; + canvas->cxFArc = cdfarc; + canvas->cxFSector = cdfsector; + canvas->cxFChord = cdfchord; + canvas->cxFText = cdftext; + canvas->cxClip = cdclip; + canvas->cxClipArea = cdcliparea; + canvas->cxBackOpacity = cdbackopacity; + canvas->cxWriteMode = cdwritemode; + canvas->cxLineStyle = cdlinestyle; + canvas->cxLineWidth = cdlinewidth; + canvas->cxLineCap = cdlinecap; + canvas->cxLineJoin = cdlinejoin; + canvas->cxInteriorStyle = cdinteriorstyle; + canvas->cxHatch = cdhatch; + canvas->cxStipple = cdstipple; + canvas->cxPattern = cdpattern; + canvas->cxFont = cdfont; + canvas->cxNativeFont = cdnativefont; + canvas->cxTextAlignment = cdtextalignment; + canvas->cxTextOrientation = cdtextorientation; + canvas->cxPalette = cdpalette; + canvas->cxBackground = cdbackground; + canvas->cxForeground = cdforeground; + canvas->cxFClipArea = cdfcliparea; + canvas->cxTransform = cdtransform; + canvas->cxKillCanvas = cdkillcanvas; + canvas->cxGetImageRGB = cdgetimagergb; + canvas->cxScrollArea = cdscrollarea; + canvas->cxCreateImage = cdcreateimage; + canvas->cxKillImage = cdkillimage; + canvas->cxGetImage = cdgetimage; + canvas->cxPutImageRect = cdputimagerect; + canvas->cxNewRegion = cdnewregion; + canvas->cxIsPointInRegion = cdispointinregion; + canvas->cxOffsetRegion = cdoffsetregion; + canvas->cxGetRegionBox = cdgetregionbox; + canvas->cxActivate = cdactivate; + canvas->cxDeactivate = cddeactivate; + canvas->cxGetFontDim = cdgetfontdim; + canvas->cxGetTextSize = cdgettextsize; +} + +static cdContext cdDebugContext = +{ + CD_CAP_ALL, + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + +cdContext* cdContextDebug(void) +{ + return &cdDebugContext; +} + diff --git a/src/drv/cddgn.c b/src/drv/cddgn.c new file mode 100644 index 0000000..32435b9 --- /dev/null +++ b/src/drv/cddgn.c @@ -0,0 +1,1696 @@ +/** \file + * \brief DGN driver + * + * See Copyright Notice in cd.h + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <limits.h> + +#include "cd.h" +#include "cd_private.h" +#include "cddgn.h" + +/* defines */ + +#define MAX_NUM_VERTEX 101 +#define MAX_NUM_VERTEX_PER_POLYLINE 15000 + +#ifndef PI +#define PI 3.14159265358979323846 +#endif + +#define END_OF_DGN_FILE 0xffff +#define DGN_FILE_BLOCK 512 + +#define NOFILL 0 /* tipos de fill que o driver faz */ +#define CONVEX 1 +#define NORMAL 2 + +/* macros */ + +#define SIZE_LINE_STRING(x) (19+4*(x)) +#define SIZE_FILLED_SHAPE(x) (27+4*(x)) +#define SIZE_ARC 40 +#define SIZE_LINE 26 + +#define IGNORE(x) ((void) x) + + +/* estruturas similares as que o MicroStation usa */ + +typedef struct +{ + union + { + struct + { + unsigned level:6; + unsigned :1; + unsigned complex:1; + unsigned type:7; + unsigned :1; + } flags; + short type_as_word; + } type; + + unsigned short words; + unsigned long xmin; + unsigned long ymin; + unsigned long xmax; + unsigned long ymax; +} Elm_hdr; + +typedef struct +{ + short attindx; + union + { + short s; + struct + { + unsigned /*class*/ :4; + unsigned /*res*/ :4; + unsigned /*l*/ :1; + unsigned /*n*/ :1; + unsigned /*m*/ :1; + unsigned attributes:1; + unsigned /*r*/ :1; + unsigned /*p*/ :1; + unsigned /*s*/ :1; + unsigned /*hole*/ :1; + } flags; + } props; + + union + { + short s; + struct + { + unsigned style:3; + unsigned weight:5; + unsigned color:8; + } b; + } symb; + +} Disp_hdr; + +/* tipo de poligono/setor */ +enum +{ + FILLED, + OPEN +}; + +/* grupos de tamanhos de caracter + (usado por gettextwidth e cdgetfontdim) */ + +static long fontsizes[4][8]= +{ + {1,2,4,5,6,7,0}, + {5,3,2,1,0}, + {8,6,4,3,2,1,0}, + {5,3,2,1,0} +}; + + +/********************** + * contexto do driver * + **********************/ + +struct _cdCtxCanvas +{ + cdCanvas* canvas; + + FILE *file; /* arquivo dgn */ + long int bytes; /* tamanho do arquivo */ + char level; + + short color, style; + + short alignment; + short typeface_index; + short symbology; + long tl; + short is_base; /* setado se texto e' do tipo CD_BASE_... */ + + short fill_type; /* como o driver faz fill: + NOFILL -> nao faz fill + CONVEX -> so faz fill de poligonos convexos + NORMAL -> faz fill normalmente */ + + long colortable[256]; /* palette */ + short num_colors; + + short is_complex; +}; + +/* prototipos de funcao */ +static void startComplexShape(cdCtxCanvas*, unsigned short,short,unsigned short, + unsigned long,unsigned long, + unsigned long,unsigned long); +static void endComplexElement(cdCtxCanvas*); + +/****************************** + * * + * funcoes internas do driver * + * * + ******************************/ + +/********************************************************* + * Obtem o descent do texto (para letras como q,p,g etc) * + *********************************************************/ + +static long get_descent(const char *text, int size_pixel) +{ + char *descent="jgyqp"; + long a=0; + long length = strlen(text); + + while(a < length) + { + if(strchr(descent, text[a])) + return size_pixel/2; + + a++; + } + return 0; +} + +/*********************************************** + * Calcula a largura da string no MicroStation * + ***********************************************/ + +static long gettextwidth(cdCtxCanvas* ctxcanvas, const char *s, int size_pixel) +{ + long a=0, + width=0, + length = strlen(s); + + short default_size=0; + + static char *fontchars[4][8] = + { + { /* CD_SYSTEM */ + "Ww", + "jshyut#*-=<>", + "iIl[]", + ";:.,'|!()`{}", + "","","","" + }, + + { /* CD_COURIER */ + "Iflrit!();.'", + "1|[]\"/`", + "BCDEKPRSUVXYbdgkpq&-_", + "w#%", + "Wm^+=<>~", + "@","","" + }, + + { /* CD_TIMES_ROMAN */ + "m", + "HMUWw", + "CSTZLbhknpuvxy23567890e", + "fstz1#$-=<>", + "Iijl*[]", + ";:.,'|!()`{}", + "","" + }, + + { /* CD_HELVETICA */ + "Ww", + "jshyut#*-=<>", + "iIl[]", + ";:.,'|!()`{}", + "","","","" + } + }; + + if (ctxcanvas->typeface_index == 1) + default_size=2; + else if (ctxcanvas->typeface_index == 2) + default_size=5; + else if (ctxcanvas->typeface_index == 3) + default_size=4; + else + default_size=4; + + for(a=0,width=0;a < length; a++) + { + static short size_number; + static char letter; + + if(s[a] == ' ') + letter = s[a-1]; + else + letter = s[a]; + + for(size_number=0;size_number < 8;size_number++) + { + if(strchr(fontchars[ctxcanvas->typeface_index][size_number], letter)) + { + width+=(ctxcanvas->tl*fontsizes[ctxcanvas->typeface_index][size_number])/6; + break; + } + } + + if(size_number == 8) + width+=(ctxcanvas->tl*default_size)/6; + + width+=ctxcanvas->tl/3; + } + + width-=ctxcanvas->tl/3; + + if (ctxcanvas->canvas->font_style & CD_ITALIC) + width+= (long) ((double)size_pixel*tan(4*atan(1)/8)); /* angulo de 15 graus */ + + return width; +} + +/**************************** + * Salva um byte no arquivo * + ****************************/ + +static void put_byte(cdCtxCanvas* ctxcanvas, unsigned char byte) +{ + fputc(byte, ctxcanvas->file); +} + +/************************************ + * Salva um sequencia de caracteres * + ************************************/ + +static void writec (cdCtxCanvas* ctxcanvas, const char *t, short tam ) +{ + short i; + + ctxcanvas->bytes += tam; + for ( i = 0; i < tam; i++ ) + fputc ( t[i], ctxcanvas->file ); +} + +/****************** + * Salva uma word * + ******************/ + +static void put_word(cdCtxCanvas* ctxcanvas, unsigned short w) +{ + char c; + + c = (char) (w & 0xff); + fputc (c, ctxcanvas->file); + c = (char) ((w >> 8) & 0xff); + fputc (c, ctxcanvas->file); + ctxcanvas->bytes += 2; +} + +/**************************** + * Salva um long no arquivo * + ****************************/ + +static void put_long (cdCtxCanvas* ctxcanvas, unsigned long i) +{ + put_word(ctxcanvas, (short) (i >> 16)); + put_word(ctxcanvas, (short) i); +} + +/******************* + * Salva um double * + *******************/ + +static void put_as_double(cdCtxCanvas* ctxcanvas, long i) +{ + float dfloat=(float) 4*i; + + put_long(ctxcanvas, *((long *) &dfloat)); + put_long(ctxcanvas, 0); + + ctxcanvas->bytes+=sizeof(float); +} + +/**************************** + * Salva uma UOR no arquivo * + ****************************/ + +static void put_uor(cdCtxCanvas* ctxcanvas, long i) +{ + put_word(ctxcanvas, (unsigned short)((i >> 16) ^ (1 << 15))); /* troca o bit 31 + para transformar em uor */ + put_word(ctxcanvas, (unsigned short)i); +} + +/*************************************** + * Salva a bounding box de um elemento * + ***************************************/ + +static void put_bound(cdCtxCanvas* ctxcanvas, long xmin, long xmax, long ymin, long ymax) +{ + put_uor(ctxcanvas, xmin); + put_uor(ctxcanvas, ymin); + put_uor(ctxcanvas, 0L); + put_uor(ctxcanvas, xmax); + put_uor(ctxcanvas, ymax); + put_uor(ctxcanvas, 0L); +} + +/****************************************** + * Calcula a bounding box de uma polyline * + ******************************************/ + +static void line_string_bound(cdPoint *buffer, short num_vertex, + unsigned long *xmin, unsigned long *ymin, + unsigned long *xmax, unsigned long *ymax) +{ + short i; + unsigned long v; + + *xmin = *xmax = buffer[0].x; + *ymin = *ymax = buffer[0].y; + + for (i = 1; i < num_vertex; i++) + { + v = buffer[i].x; + if (v < *xmin) + *xmin = v; + else if (v > *xmax) + *xmax = v; + + v = (long) buffer[i].y; + if (v < *ymin) + *ymin = v; + else if (v > *ymax) + *ymax = v; + } +} + +/************************************ + * Retorna symbology de um elemento * + ************************************/ + +static short symbology(cdCtxCanvas* ctxcanvas) +{ + return (short)((ctxcanvas->color << 8) | (ctxcanvas->canvas->line_width << 3) | ctxcanvas->style); +} + +/***************************************** + * Salva um Element Header no arquivo * + *****************************************/ + +static void putElementHeader(cdCtxCanvas* ctxcanvas, Elm_hdr *ehdr) +{ + ehdr->type.flags.complex = ctxcanvas->is_complex; + + put_word(ctxcanvas, (short)(ehdr->type.flags.type << 8 | + ehdr->type.flags.complex << 7 | ehdr->type.flags.level)); + + + put_word(ctxcanvas, ehdr->words); + put_bound(ctxcanvas, ehdr->xmin, ehdr->xmax, ehdr->ymin, ehdr->ymax); +} + +/************************************** + * Salva um display header no arquivo * + **************************************/ + +static void putDisplayHeader(cdCtxCanvas* ctxcanvas, Disp_hdr *dhdr) +{ + put_word(ctxcanvas, 0); /* graphics group */ + put_word(ctxcanvas, dhdr->attindx); /* index to attributes */ + put_word(ctxcanvas, dhdr->props.flags.attributes << 11); /* properties */ + put_word(ctxcanvas, dhdr->symb.s); /* display symbology */ +} + + +/*************************************** + * completa o arquivo com zeros para * + * que o numero de bytes seja multiplo * + * de 512 * + ***************************************/ + +static void complete_file(cdCtxCanvas* ctxcanvas) +{ + long resto, i; + + put_word(ctxcanvas, END_OF_DGN_FILE); + + resto = DGN_FILE_BLOCK - ctxcanvas->bytes % DGN_FILE_BLOCK; + + /* checa validade do tamanho do arquivo */ + if (resto%2 != 0) return; + + for (i = 0; i < resto; i+=2) + put_word(ctxcanvas, 0); +} + +/************************************* + * Salva um elemento arco no arquivo * + *************************************/ + +static void arc (cdCtxCanvas* ctxcanvas, long xc, long yc, long w, long h, double a1, double a2) +{ + Elm_hdr ehdr; + Disp_hdr dhdr; + + /* raster header element */ + ehdr.type.flags.level=ctxcanvas->level; + ehdr.type.flags.type=16; + ehdr.words=SIZE_ARC-2; + ehdr.xmin=xc - w/2; + ehdr.xmax=xc + w/2; + ehdr.ymin=yc - h/2; + ehdr.ymax=yc + h/2; + + putElementHeader(ctxcanvas, &ehdr); + + /* Display Header */ + dhdr.attindx = ehdr.words - 14; + dhdr.props.flags.attributes = 0; + dhdr.symb.s = symbology(ctxcanvas); + putDisplayHeader(ctxcanvas, &dhdr); + + put_long(ctxcanvas, (long) a1*360000); /* start angle */ + put_long(ctxcanvas, (long) (a2-a1)*360000); /* sweep angle */ + put_as_double(ctxcanvas, w/2); /* primary axis */ + put_as_double(ctxcanvas, h/2); /* secondary axis */ + put_long(ctxcanvas, 0); /* rotation angle (sempre 0) */ + put_as_double(ctxcanvas, xc); /* x origin */ + put_as_double(ctxcanvas, yc); /* y origin */ +} + +/*************************************** + * Salva um elemento elipse no arquivo * + ***************************************/ + +static void ellipse(cdCtxCanvas* ctxcanvas, long xc, long yc, long w, long h, short type) +{ + Elm_hdr ehdr; + Disp_hdr dhdr; + + /* raster header element */ + ehdr.type.flags.level=ctxcanvas->level; + ehdr.type.flags.type=15; + ehdr.words=34+((type==FILLED) ? 8 : 0); + ehdr.xmin=xc - w/2; + ehdr.xmax=xc + w/2; + ehdr.ymin=yc - h/2; + ehdr.ymax=yc + h/2; + + putElementHeader(ctxcanvas, &ehdr); + + /* Display Header */ + dhdr.attindx=20; + dhdr.props.flags.attributes=(type == FILLED) ? 1 : 0; + dhdr.symb.s=symbology(ctxcanvas); + putDisplayHeader(ctxcanvas, &dhdr); + + put_as_double(ctxcanvas, w/2); /* primary axis */ + put_as_double(ctxcanvas, h/2); /* secondary axis */ + put_long(ctxcanvas, 50); /* rotation angle (sempre 0) */ + put_as_double(ctxcanvas, xc); /* x origin */ + put_as_double(ctxcanvas, yc); /* y origin */ + + /* salva atributo de fill */ + if(type == FILLED) + { + put_word(ctxcanvas, 0x1007); + put_word(ctxcanvas, 65); + put_word(ctxcanvas, 0x802); + put_word(ctxcanvas, 0x0001); + put_word(ctxcanvas, ctxcanvas->color); + put_word(ctxcanvas, 0); + put_word(ctxcanvas, 0); + put_word(ctxcanvas, 0); + } +} + +static short getclosestColor(cdCtxCanvas* ctxcanvas, long color) +{ + short count=0, closest=0; + long diff=0; + unsigned char r = cdRed(color), + g = cdGreen(color), + b = cdBlue(color); + short rd, gd, bd; + long newdiff; + + /* procura a cor mais proxima */ + + diff = 3*65536; /* inicializa com maior diferenca possivel */ + + for(count=0; count < ctxcanvas->num_colors; count++) + { + rd = r - cdRed(ctxcanvas->colortable[count]); + gd = g - cdGreen(ctxcanvas->colortable[count]); + bd = b - cdBlue(ctxcanvas->colortable[count]); + + newdiff = rd*rd + gd*gd + bd*bd; + + if(newdiff <= diff) + { + /* verifica se encontrou a cor */ + if(newdiff == 0) + return count-1; + + diff = newdiff; + closest=count-1; + } + } + + /* nao encontrou a cor, tenta adicionar na palette, ou retorna a mais proxima */ + if(ctxcanvas->num_colors < 254) + { + ctxcanvas->colortable[ctxcanvas->num_colors+1] = color; + return ctxcanvas->num_colors++; + } + else + return closest; +} + +static void saveColorTable(cdCtxCanvas* ctxcanvas) +{ + unsigned char r,g,b; + short i; + + put_word(ctxcanvas, (0x05 << 8) | 1); /* colortable */ + put_word(ctxcanvas, 434); + + put_long(ctxcanvas, 0); + put_long(ctxcanvas, 0); + put_long(ctxcanvas, 0); + put_long(ctxcanvas, 0xffffffff); + put_long(ctxcanvas, 0xffffffff); + put_long(ctxcanvas, 0xffffffff); + + put_word(ctxcanvas, 0); + put_word(ctxcanvas, 420); + put_word(ctxcanvas, 0x0400); + put_word(ctxcanvas, 0x100); + put_word(ctxcanvas, 0); + + for(i=0;i<256;i++) + { + cdDecodeColor(ctxcanvas->colortable[i], &r, &g, &b); + put_byte(ctxcanvas, r); + put_byte(ctxcanvas, g); + put_byte(ctxcanvas, b); + } + + put_word(ctxcanvas, 25); + for(i=0;i<32;i++) + put_word(ctxcanvas, 0x2020); +} + + +/***************************** + * Le uma word de um arquivo * + *****************************/ + +static short file_get_word(FILE *fp) +{ + short word=0; + + word = (short)fgetc(fp); + word |= ((short)fgetc(fp) << 8) & 0xff00; + + return word; +} + +/******************************** + * Salva uma word em um arquivo * + ********************************/ + +static void file_put_word (short word, FILE *fp) +{ + fputc ((char) (word & 0xff), fp); + fputc ((char) ((word >> 8) & 0xff), fp); +} + +/******************************************* + * Le elementos de um arquivo DGN e os * + * coloca no inicio do arquivo aberto pelo * + * driver * + *******************************************/ + +static void dgn_copy (FILE *file, cdCtxCanvas *ctxcanvas) +{ + short word=0; + + while ((word = file_get_word(file)) != END_OF_DGN_FILE) + { + file_put_word(word, ctxcanvas->file); /* type e level do elemento */ + ctxcanvas->bytes+=2; + + word = file_get_word(file); /* words to follow */ + file_put_word(word, ctxcanvas->file); + ctxcanvas->bytes+=2; + + while (word) /* copia resto do elemento */ + { + file_put_word(file_get_word(file), ctxcanvas->file); + word--; + ctxcanvas->bytes+=2; + } + } +} + + +/* + * Funcoes do driver + */ + +static void cdkillcanvas(cdCtxCanvas* ctxcanvas) +{ + saveColorTable(ctxcanvas); + complete_file(ctxcanvas); + fclose (ctxcanvas->file); + + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + free(ctxcanvas); +} + +static void cddeactivate (cdCtxCanvas* ctxcanvas) +{ + fflush(ctxcanvas->file); +} + +static void cdflush (cdCtxCanvas* ctxcanvas) +{ + fflush(ctxcanvas->file); +} + + +/******************************************************/ +/* primitives */ +/******************************************************/ + +static void cdline (cdCtxCanvas* ctxcanvas, int x1, int y1, int x2, int y2) +{ + Elm_hdr ehdr; + Disp_hdr dhdr; + cdPoint buffer[2]; + + buffer[0].x=x1; + buffer[0].y=y1; + buffer[1].x=x2; + buffer[1].y=y2; + + ehdr.type.flags.level=ctxcanvas->level; + ehdr.type.flags.type=3; + + ehdr.words=SIZE_LINE-2; + + line_string_bound(buffer, 2, &ehdr.xmin, + &ehdr.ymin,&ehdr.xmax,&ehdr.ymax); + + putElementHeader(ctxcanvas, &ehdr); + + /* Display Header */ + dhdr.attindx = ehdr.words - 14; + dhdr.props.flags.attributes = 0; + dhdr.symb.s=symbology(ctxcanvas); + + putDisplayHeader(ctxcanvas, &dhdr); + + /* pontos inicial e final da linha */ + + put_long(ctxcanvas, (long) x1); + put_long(ctxcanvas, (long) y1); + put_long(ctxcanvas, (long) x2); + put_long(ctxcanvas, (long) y2); +} + +static void cdbox (cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + Elm_hdr ehdr; + Disp_hdr dhdr; + + /* raster header element */ + ehdr.type.flags.level=ctxcanvas->level; + ehdr.type.flags.type=6; + ehdr.words=17+4*5+8; + ehdr.xmin=xmin; + ehdr.xmax=xmax; + ehdr.ymin=ymin; + ehdr.ymax=ymax; + + putElementHeader(ctxcanvas, &ehdr); + + /* Display Header */ + dhdr.attindx=3+4*5; + dhdr.props.flags.attributes=1; + dhdr.symb.s=symbology(ctxcanvas); + putDisplayHeader(ctxcanvas, &dhdr); + + put_word(ctxcanvas, 5); /* numero de vertices */ + + /* vertices */ + put_long(ctxcanvas, (long) xmin); + put_long(ctxcanvas, (long) ymin); + + put_long(ctxcanvas, (long) xmax); + put_long(ctxcanvas, (long) ymin); + + put_long(ctxcanvas, (long) xmax); + put_long(ctxcanvas, (long) ymax); + + put_long(ctxcanvas, (long) xmin); + put_long(ctxcanvas, (long) ymax); + + put_long(ctxcanvas, (long) xmin); + put_long(ctxcanvas, (long) ymin); + + /* atributos de fill */ + + put_word(ctxcanvas, 0x1007); + put_word(ctxcanvas, 65); + put_word(ctxcanvas, 0x802); + put_word(ctxcanvas, 0x0001); + put_word(ctxcanvas, ctxcanvas->color); + put_word(ctxcanvas, 0); + put_word(ctxcanvas, 0); + put_word(ctxcanvas, 0); +} + +static void cdarc (cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + if (a2 == a1 + 360) + ellipse(ctxcanvas, xc,yc,w,h,OPEN); + else + arc(ctxcanvas, xc, yc, w, h, a1, a2); +} + +static void cdsector (cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + if (a2 == a1 + 360) + { + ellipse(ctxcanvas, xc,yc,w,h,FILLED); + return; + } + + startComplexShape(ctxcanvas, 3, 1, SIZE_ARC+SIZE_LINE*2, + (unsigned long) xc-w/2, (unsigned long) yc-h/2, + (unsigned long) xc+h/2, (unsigned long) yc+h/2); + + arc(ctxcanvas, xc, yc, w, h, a1, a2); + + cdline(ctxcanvas, xc, yc, (int) + (((double)w*cos(a1*CD_DEG2RAD)/2.+.5)), (int) (((double)h*sin(a1*CD_DEG2RAD))/2.+.5)); + cdline(ctxcanvas, xc, yc, (int) + (((double)w*cos(a2*CD_DEG2RAD)/2.+.5)), (int) (((double)h*sin(a2*CD_DEG2RAD))/2.+.5)); + + endComplexElement(ctxcanvas); +} + +static void cdtext (cdCtxCanvas* ctxcanvas, int x, int y, const char *s) +{ + long n=0; + long descent=0; + short w=0; + long hc=0,wc=0; + int size_pixel; + short italic = (ctxcanvas->canvas->font_style&CD_ITALIC); + + Elm_hdr ehdr; + Disp_hdr dhdr; + + n = strlen(s); + + if(n > 255) + n=255; + + w = (short)((n/2)+(n%2)); + size_pixel = cdGetFontSizePixels(ctxcanvas->canvas, ctxcanvas->canvas->font_size); + descent=get_descent(s, size_pixel); + hc = size_pixel+descent; + wc = gettextwidth(ctxcanvas, s, size_pixel); + + y+=descent; + + switch (ctxcanvas->alignment) + { + case 12: x = x; y = y; break; + case 13: x = x; y = y - (int) (hc/2.0); break; + case 14: x = x; y = y - (int) hc; break; + case 6: x = x - (int) (wc/2.0); y = y; break; + case 7: x = x - (int) (wc/2.0); y = y - (int) (hc/2.0); break; + case 8: x = x - (int) (wc/2.0); y = y - (int) hc; break; + case 0: x = x - (int) wc; y = y; break; + case 1: x = x - (int) wc; y = y - (int) (hc/2.0); break; + case 2: x = x - (int) wc; y = y - (int) hc; break; + } + + if(ctxcanvas->is_base) + y -= (int) (hc/4.0); + + /* raster header element */ + ehdr.type.flags.level=ctxcanvas->level; + ehdr.type.flags.type=17; + ehdr.words=28+w+((italic) ? 8 : 0); + ehdr.xmin=x; + ehdr.xmax=x+wc; + ehdr.ymin=y-descent; + ehdr.ymax=y+hc; + + putElementHeader(ctxcanvas, &ehdr); + + /* Display Header */ + dhdr.attindx=14+w; + dhdr.props.flags.attributes=(italic) ? 1 : 0; + + if (ctxcanvas->canvas->font_style&CD_BOLD) + dhdr.symb.s=ctxcanvas->color << 8 | (3 << 3); + else + dhdr.symb.s=ctxcanvas->color << 8; + + putDisplayHeader(ctxcanvas, &dhdr); + + put_word(ctxcanvas, (ctxcanvas->alignment << 8) | ctxcanvas->typeface_index); + + put_long(ctxcanvas, (long)((1000 * ctxcanvas->tl) / 6) | (1 << 7)); + put_long(ctxcanvas, (long)((1000 * size_pixel) / 6) | (1 << 7)); + + put_long(ctxcanvas, 0); + put_long(ctxcanvas, x); + put_long(ctxcanvas, y); + put_word(ctxcanvas, (unsigned short) n); + writec(ctxcanvas, s, (short)(n+(n%2))); /* deve escrever sempre um numero par de caracteres */ + + if(italic) + { + put_word(ctxcanvas, 0x1007); /* atributos e words to follow */ + put_word(ctxcanvas, 0x80d4); /* tipo de atributo */ + put_long(ctxcanvas, 0x000865c0); + put_long(ctxcanvas, 0x00520000); + put_long(ctxcanvas, 0x00000000); + } +} + +static void startComplexShape(cdCtxCanvas* ctxcanvas, + unsigned short num_elements, + short is_fill, + unsigned short size, + unsigned long xmin, + unsigned long ymin, + unsigned long xmax, + unsigned long ymax) +{ + Elm_hdr ehdr; + Disp_hdr dhdr; + + ehdr.type.flags.level=ctxcanvas->level; + ehdr.type.flags.type=14; + ehdr.words=22 + ((is_fill) ? 8 : 0); + ehdr.xmax = xmax; + ehdr.xmin = xmin; + ehdr.ymax = ymax; + ehdr.ymin = ymin; + + putElementHeader(ctxcanvas, &ehdr); + + /* Display Header */ + dhdr.attindx=4; + dhdr.props.flags.attributes = (is_fill) ? 1 : 0; + dhdr.symb.s=symbology(ctxcanvas); + + putDisplayHeader(ctxcanvas, &dhdr); + + put_word(ctxcanvas, size + 5 + ((is_fill) ? 8 : 0)); + put_word(ctxcanvas, num_elements); + + put_long(ctxcanvas, 0); /* atributo nulo */ + put_long(ctxcanvas, 0); + + /* salva atributo de fill */ + if(is_fill) + { + put_word(ctxcanvas, 0x1007); + put_word(ctxcanvas, 65); + put_word(ctxcanvas, 0x802); + put_word(ctxcanvas, 0x0001); + put_word(ctxcanvas, ctxcanvas->color); + put_word(ctxcanvas, 0); + put_word(ctxcanvas, 0); + put_word(ctxcanvas, 0); + } + + /* marca inicio de elemento complexo */ + + ctxcanvas->is_complex = 1; +} + + +static void startComplexChain(cdCtxCanvas* ctxcanvas, + unsigned short num_elements, + unsigned short size, + unsigned long xmin, + unsigned long ymin, + unsigned long xmax, + unsigned long ymax) + +{ + Elm_hdr ehdr; + Disp_hdr dhdr; + + ehdr.type.flags.level=ctxcanvas->level; + ehdr.type.flags.type=12; + + ehdr.words=22; + ehdr.xmax = xmax; + ehdr.xmin = xmin; + ehdr.ymax = ymax; + ehdr.ymin = ymin; + + + putElementHeader(ctxcanvas, &ehdr); + + /* Display Header */ + dhdr.attindx=4; + dhdr.props.flags.attributes = 1; + dhdr.symb.s=symbology(ctxcanvas); + + putDisplayHeader(ctxcanvas, &dhdr); + + put_word(ctxcanvas, size+5); + put_word(ctxcanvas, num_elements); + + put_long(ctxcanvas, 0); /* atributo nulo */ + put_long(ctxcanvas, 0); + + + /* marca inicio de elemento complexo */ + + ctxcanvas->is_complex = 1; +} + +static void endComplexElement(cdCtxCanvas* ctxcanvas) +{ + ctxcanvas->is_complex = 0; +} + +static void putLineString(cdCtxCanvas* ctxcanvas, cdPoint *buffer, short num_vertex) +{ + Elm_hdr ehdr; + Disp_hdr dhdr; + short i=0; + + ehdr.type.flags.level=ctxcanvas->level; + + ehdr.type.flags.type=4; + + ehdr.words=SIZE_LINE_STRING(num_vertex)-2; + + line_string_bound(buffer, num_vertex, &ehdr.xmin, + &ehdr.ymin,&ehdr.xmax,&ehdr.ymax); + + putElementHeader(ctxcanvas, &ehdr); + + /* Display Header */ + dhdr.attindx=ehdr.words-14; + dhdr.props.flags.attributes = 0; + dhdr.symb.s=symbology(ctxcanvas); + + putDisplayHeader(ctxcanvas, &dhdr); + + put_word(ctxcanvas, num_vertex); + + for (i = 0; i < num_vertex; i++) + { + put_long(ctxcanvas, (long) buffer[i].x); + put_long(ctxcanvas, (long) buffer[i].y); + } +} + +static void putShape(cdCtxCanvas* ctxcanvas, cdPoint *buffer, short num_vertex) +{ + Elm_hdr ehdr; + Disp_hdr dhdr; + short i=0; + + ehdr.type.flags.level=ctxcanvas->level; + ehdr.type.flags.type=6; + + ehdr.words=SIZE_FILLED_SHAPE(num_vertex)-2; + + line_string_bound(buffer, num_vertex, &ehdr.xmin, + &ehdr.ymin,&ehdr.xmax,&ehdr.ymax); + + + putElementHeader(ctxcanvas, &ehdr); + + /* Display Header */ + dhdr.attindx=ehdr.words - 14 - 8; /* 8 -> size of attributes */ + dhdr.props.flags.attributes = 1; + dhdr.symb.s=symbology(ctxcanvas); + + putDisplayHeader(ctxcanvas, &dhdr); + + put_word(ctxcanvas, num_vertex); + + for (i = 0; i < num_vertex; i++) + { + put_long(ctxcanvas, (long) buffer[i].x); + put_long(ctxcanvas, (long) buffer[i].y); + } + + put_word(ctxcanvas, 0x1007); + put_word(ctxcanvas, 65); + put_word(ctxcanvas, 0x802); + put_word(ctxcanvas, 0x0001); + put_word(ctxcanvas, ctxcanvas->color); + put_word(ctxcanvas, 0); + put_word(ctxcanvas, 0); + put_word(ctxcanvas, 0); +} + +static void cdpoly(cdCtxCanvas* ctxcanvas, int mode, cdPoint* poly, int n) +{ + short is_fill=0; + + if(mode == CD_FILL && ctxcanvas->fill_type == NOFILL) + mode = CD_CLOSED_LINES; + + if(n > MAX_NUM_VERTEX_PER_POLYLINE) + n = MAX_NUM_VERTEX_PER_POLYLINE; + + /* acerta buffer de pontos */ + if(mode == CD_FILL || mode == CD_CLOSED_LINES) + { + poly[n].x = poly[0].x; + poly[n].y = poly[0].y; + n++; + } + + /* se fill_type for CONVEX, testa se poligono e' convexo ou concavo */ + if((ctxcanvas->fill_type == CONVEX) && (n > 3) && (mode == CD_FILL)) + { + short signal=0; + short count=0; + long vect=0; + + /* calcula sinal do vetorial entre o primeiro lado e o segundo */ + vect = (poly[1].x - poly[0].x) * + (poly[2].y - poly[1].y) - + (poly[1].y - poly[0].y) * + (poly[2].x - poly[1].x); + + if(vect == 0) + mode = CD_CLOSED_LINES; /* ver se precisa mudar */ + else + { + signal = (short)(vect/abs(vect)); + + for(count=1 ; count< (n-2); count++) + { + vect = (poly[count+1].x - poly[count].x) * + (poly[count+2].y - poly[count+1].y) - + (poly[count+1].y - poly[count].y) * + (poly[count+2].x - poly[count+1].x); + + if(vect == 0) + { + mode=CD_CLOSED_LINES; + break; + } + + if((vect/abs(vect)) != signal) + { + mode=CD_CLOSED_LINES; + break; + } + } + } + } + + /* se tiver fill */ + + if(mode == CD_FILL) + is_fill=1; + + if(n > MAX_NUM_VERTEX) /* tem que usar complex shape ou chain */ + { + short count=0; + short num_whole_elements = n / MAX_NUM_VERTEX; + short num_whole_vertex = num_whole_elements * MAX_NUM_VERTEX; + short rest = n % MAX_NUM_VERTEX; + short is_there_rest = (rest > 0) ? 1 : 0; + unsigned long xmax, xmin, ymax, ymin; + unsigned short size = + SIZE_LINE_STRING(MAX_NUM_VERTEX)*num_whole_elements+ + SIZE_LINE_STRING(rest)*is_there_rest; + + line_string_bound(poly, n, &xmin, &ymin, &xmax, &ymax); + + if(mode == CD_OPEN_LINES) + startComplexChain(ctxcanvas, (unsigned short) (num_whole_elements+((rest > 0) ? 1 : 0)), + size, xmin, ymin, xmax, ymax); + else + startComplexShape(ctxcanvas, (unsigned short) (num_whole_elements+((rest > 0) ? 1 : 0)), + is_fill, size, xmin, ymin, xmax, ymax); + + for(count=0;count < num_whole_vertex; count+=MAX_NUM_VERTEX, n-=MAX_NUM_VERTEX) + putLineString(ctxcanvas, &poly[count], MAX_NUM_VERTEX); + + if(rest) + putLineString(ctxcanvas, &poly[num_whole_vertex],n); + + endComplexElement(ctxcanvas); + } + else + { + if(is_fill) + putShape(ctxcanvas, poly, n); + else + putLineString(ctxcanvas, poly, n); + } +} + +/************** + * attributes * + **************/ + +static int cdlinestyle (cdCtxCanvas* ctxcanvas, int style) +{ + switch(style) + { + case CD_CONTINUOUS: + ctxcanvas->style = 0; + break; + + case CD_DASHED: + ctxcanvas->style = 3; + break; + + case CD_DOTTED: + ctxcanvas->style = 1; + break; + + case CD_DASH_DOT: + ctxcanvas->style = 4; + break; + + case CD_DASH_DOT_DOT: + ctxcanvas->style = 6; + break; + } + + return style; +} + +static int cdlinewidth (cdCtxCanvas* ctxcanvas, int width) +{ + (void)ctxcanvas; + width = width & 31; + return width; +} + +static int cdfont(cdCtxCanvas* ctxcanvas, const char *type_face, int style, int size) +{ + (void)style; + ctxcanvas->tl = (long)(cdGetFontSizePoints(ctxcanvas->canvas, size)/4)*3; + + if (cdStrEqualNoCase(type_face, "Courier")) + ctxcanvas->typeface_index=1; + else if (cdStrEqualNoCase(type_face, "Times")) + ctxcanvas->typeface_index=2; + else if (cdStrEqualNoCase(type_face, "Helvetica")) + ctxcanvas->typeface_index=3; + else if (cdStrEqualNoCase(type_face, "System")) + ctxcanvas->typeface_index=0; + else + return 0; + + return 1; +} + +static void cdgetfontdim (cdCtxCanvas* ctxcanvas, int *max_width, int *height, int *ascent, int *descent) +{ + int size_pixel; + + if(max_width) + { + int a=0; + *max_width=0; + + while(fontsizes[ctxcanvas->typeface_index][a]) + { + if(fontsizes[ctxcanvas->typeface_index][a] > *max_width) + *max_width = fontsizes[ctxcanvas->typeface_index][a]; + a++; + } + } + + size_pixel = cdGetFontSizePixels(ctxcanvas->canvas, ctxcanvas->canvas->font_size); + + if(height) *height = (size_pixel*3)/2; + if(ascent) *ascent = size_pixel; + if(descent) *descent = size_pixel/2; +} + +static void cdgettextsize (cdCtxCanvas* ctxcanvas, const char *s, int *width, int *height) +{ + int size_pixel = cdGetFontSizePixels(ctxcanvas->canvas, ctxcanvas->canvas->font_size); + if(height) *height = size_pixel + get_descent(s, size_pixel); + if(width) *width = gettextwidth(ctxcanvas, s, size_pixel); +} + +static int cdtextalignment (cdCtxCanvas* ctxcanvas, int alignment) +{ + ctxcanvas->is_base = 0; + + /* DGN guarda posicao do texto em relacao ao ponto */ + + switch(alignment) + { + case CD_NORTH: + ctxcanvas->alignment = 8; /* center-bottom */ + break; + + case CD_SOUTH: + ctxcanvas->alignment = 6; /* center-top */ + break; + + case CD_EAST: + ctxcanvas->alignment = 1; /* left-center */ + break; + + case CD_WEST: + ctxcanvas->alignment = 13; /* right-center */ + break; + + case CD_NORTH_EAST: + ctxcanvas->alignment = 2; /* left-bottom */ + break; + + case CD_NORTH_WEST: + ctxcanvas->alignment = 14; /* right-bottom */ + break; + + case CD_SOUTH_EAST: + ctxcanvas->alignment = 0; /* left-top */ + break; + + case CD_SOUTH_WEST: + ctxcanvas->alignment = 12; /* right-top */ + break; + + case CD_CENTER: + ctxcanvas->alignment = 7; /* center-center */ + break; + + case CD_BASE_LEFT: + ctxcanvas->alignment = 13; /* right-center */ + ctxcanvas->is_base=1; + break; + + case CD_BASE_CENTER: + ctxcanvas->alignment = 7; /* center-center */ + ctxcanvas->is_base=1; + break; + + case CD_BASE_RIGHT: + ctxcanvas->alignment = 1; /* left-center */ + ctxcanvas->is_base=1; + break; + } + + return alignment; +} + +/******************************************************/ +/* color */ +/******************************************************/ + +static void cdpalette (cdCtxCanvas* ctxcanvas, int n, const long int *palette, int mode) +{ + int c=0; + + IGNORE(mode); + + for(c=0; c < n; c++) + ctxcanvas->colortable[c] = *palette++; + + ctxcanvas->num_colors = n; +} + +static long int cdforeground (cdCtxCanvas* ctxcanvas, long int color) +{ + ctxcanvas->color = getclosestColor(ctxcanvas, color); + return color; +} + +/******************************************************/ +/* client images */ +/******************************************************/ + +static void cdputimagerectmap(cdCtxCanvas* ctxcanvas, int iw, int ih, const unsigned char *index, + const long int *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int i=0,j=0, remainder=iw%2, total_colors; + int *ix=NULL,*iy=NULL; + Elm_hdr ehdr; + Disp_hdr dhdr; + unsigned char map_colors[256]; + + + /* raster header element */ + ehdr.type.flags.level=ctxcanvas->level; + ehdr.type.flags.type=87; + ehdr.words=39; + ehdr.xmin=x; + ehdr.xmax=x+w; + ehdr.ymin=y; + ehdr.ymax=y+h; + + putElementHeader(ctxcanvas, &ehdr); + + /* Display Header */ + dhdr.attindx=25; + dhdr.symb.s=0; + + putDisplayHeader(ctxcanvas, &dhdr); + + /* description of the element */ + put_long(ctxcanvas, 21+(23+w/2+w%2)*h); /* total length of cell */ + put_word(ctxcanvas, 0x0714); /* raster flags */ + put_word(ctxcanvas, 0x0100); /* background e foreground colors + (nao usados) */ + put_word(ctxcanvas, w); /* largura da imagem em pixels */ + put_word(ctxcanvas, h); /* altura da imagem em pixel */ + put_long(ctxcanvas, 0); /* resevado */ + put_as_double(ctxcanvas, 0); /* resolution (nao usado) */ + + put_word(ctxcanvas, 0x4080); /* scale */ + put_long(ctxcanvas, 0); + put_word(ctxcanvas, 0); + + put_long(ctxcanvas, x); /* origem */ + put_long(ctxcanvas, y+h); + put_long(ctxcanvas, 0); + + put_word(ctxcanvas, 0); /* no de vertices */ + + ctxcanvas->is_complex = 1; /* elemento complexo */ + + /* obtem o maior indice usado na imagem */ + + total_colors = 0; + for (i = 0; i < iw*ih; i++) + { + if (index[i] > total_colors) + total_colors = index[i]; + } + total_colors++; + + /* cria tabela para acelerar match de cor na palette */ + + for (i = 0; i < total_colors; i++) + { + map_colors[i] = (unsigned char)getclosestColor(ctxcanvas, colors[i]); + } + + /** salva dados da imagem **/ + + /* calcula stretch */ + + ix = cdGetZoomTable(w, xmax-xmin+1, xmin); + iy = cdGetZoomTable(h, ymax-ymin+1, ymin); + + for(i=h-1; i >= 0; i--) + { + /* raster header element */ + ehdr.type.flags.level=ctxcanvas->level; + ehdr.type.flags.type=88; + ehdr.words=21+w/2+remainder; + + putElementHeader(ctxcanvas, &ehdr); + + /* Display Header */ + dhdr.attindx=7+w/2+remainder; + dhdr.symb.s=0; + putDisplayHeader(ctxcanvas, &dhdr); + + put_word(ctxcanvas, 0x0714); /* raster flags */ + put_word(ctxcanvas, 0x0100); /* background e foreground + colors (nao usados) */ + + put_word(ctxcanvas, 0); /* x offset da origem */ + put_word(ctxcanvas, i); /* y offset */ + put_word(ctxcanvas, w); /* numero de pixels neste elemento */ + + for(j=0; j < w; j++) + put_byte(ctxcanvas, map_colors[index[(iy[i])*iw + ix[j]]]); + + if(remainder) put_byte(ctxcanvas, 0); + } + + ctxcanvas->is_complex = 0; + + free(ix); /* libera memoria alocada */ + free(iy); +} + +/******************************************************/ +/* server images */ +/******************************************************/ + +static void cdpixel (cdCtxCanvas* ctxcanvas, int x, int y, long int color) +{ + long old_color = cdforeground(ctxcanvas, color); + int old_linestyle = cdlinestyle(ctxcanvas, CD_CONTINUOUS); + int old_linewidth = cdlinewidth(ctxcanvas, 1); + + cdline(ctxcanvas, x,y,x,y); + + cdforeground(ctxcanvas, old_color); + cdlinestyle(ctxcanvas, old_linestyle); + cdlinewidth(ctxcanvas, old_linewidth); +} + +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + cdCtxCanvas *ctxcanvas; + char* strdata = (char*)data; + char words[4][256]; + char filename[10240] = ""; + char seedfile[10240] = ""; + int count = 0; + double res = 0; + + if (!data) return; + + /* separa palavras da expressao, que e' na forma + "filename [mm_wxmm_h] [res] [-f] [-sseedfile]" */ + + strdata += cdGetFileName(strdata, filename); + if (filename[0] == 0) + return; + + sscanf(strdata, "%s %s %s %s", words[0], words[1], words[2], words[3]); + + if(!strlen(filename)) /* se nao pegou filename */ + return; + + ctxcanvas = (cdCtxCanvas *) malloc(sizeof(cdCtxCanvas)); + + /* tenta criar arquivo DGN */ + + if((ctxcanvas->file = fopen (filename, "wb"))==NULL) + { + free(ctxcanvas); + return; + } + + /* verifica se foi passado tamanho do canvas em mm. Se foi, + extrai-o da string */ + + if(sscanf(words[0], "%lgx%lg", + &canvas->w_mm, &canvas->h_mm) == 2) + { + count++; /* incrementa contador de palavras */ + + if(canvas->w_mm == 0 || canvas->h_mm == 0) + { + fclose(ctxcanvas->file); + free(ctxcanvas); + return; + } + } + else + canvas->w_mm = canvas->h_mm = 0; + + /* Verifica se foi passada resolucao */ + + if(sscanf(words[count], "%lg", &res) == 1) + { + count++; /* incrementa contador de palavras */ + + if(res <= 0) /* verifica validade da resolucao */ + { + fclose(ctxcanvas->file); + free(ctxcanvas); + return; + } + } + else + res = 3.78; + + /* se tamanho em milimetros nao tiver sido inicializado, + usa como default o tamanho maximo em pixels para fazer as + contas + */ + + if (canvas->w_mm == 0 || canvas->h_mm == 0) + { + canvas->w = INT_MAX; + canvas->h = INT_MAX; + + canvas->w_mm = canvas->w / res; + canvas->h_mm = canvas->h / res; + } + else + { + canvas->w = (long) (canvas->w_mm * res); + canvas->h = (long) (canvas->h_mm * res); + } + + canvas->xres = res; + canvas->yres = res; + canvas->bpp = 8; + + /* verifica se usuario que alterar metodo de fill */ + + if (strcmp(words[count], "-f")==0) + { + ctxcanvas->fill_type = CONVEX; + count++; + } + else + ctxcanvas->fill_type = NORMAL; + + /* se tiver passado seedfile como argumento */ + if(sscanf(words[count], "-s%s", seedfile) == 1) + { + FILE *seed=NULL; + char *cd_dir = getenv("CDDIR"); + static char newfilename[512]; + + if(cd_dir == NULL) + cd_dir = "."; + + sprintf(newfilename, "%s/%s", cd_dir, seedfile); + + count++; + + /* testa concatenando com variavel de ambiente */ + + if((seed = fopen (newfilename, "rb"))==NULL) + { + /* tenta abrir usando string passada pelo usuario + diretamente */ + + if((seed = fopen (seedfile, "rb"))==NULL) + { + fclose(ctxcanvas->file); + free(ctxcanvas); + return; + } + } + + /* concatena seed */ + + fseek(seed, 0, SEEK_SET); + fseek(ctxcanvas->file, 0, SEEK_SET); + + ctxcanvas->bytes=0; + dgn_copy(seed, ctxcanvas); + fclose(seed); + } + + ctxcanvas->canvas = canvas; + canvas->ctxcanvas = ctxcanvas; + + /* config */ + + ctxcanvas->level = 1; + + /** valores default do contexto sao setados **/ + + /* texto */ + + ctxcanvas->alignment = 12; + ctxcanvas->is_base = 1; + ctxcanvas->typeface_index = 0; + ctxcanvas->tl=12; + + /* cores */ + + memset(ctxcanvas->colortable, 0, 1024); + ctxcanvas->colortable[0] = CD_BLACK; + ctxcanvas->num_colors = 1; + + /* atributos */ + + ctxcanvas->color = 1; + ctxcanvas->style = 0; + + /* DGN */ + + ctxcanvas->is_complex=0; +} + +static void cdinittable(cdCanvas* canvas) +{ + canvas->cxFlush = cdflush; + canvas->cxPixel = cdpixel; + canvas->cxLine = cdline; + canvas->cxPoly = cdpoly; + canvas->cxBox = cdbox; + canvas->cxArc = cdarc; + canvas->cxSector = cdsector; + canvas->cxText = cdtext; + canvas->cxGetFontDim = cdgetfontdim; + canvas->cxGetTextSize = cdgettextsize; + canvas->cxPutImageRectMap = cdputimagerectmap; + + canvas->cxLineStyle = cdlinestyle; + canvas->cxLineWidth = cdlinewidth; + canvas->cxFont = cdfont; + canvas->cxTextAlignment = cdtextalignment; + canvas->cxPalette = cdpalette; + canvas->cxForeground = cdforeground; + + canvas->cxKillCanvas = cdkillcanvas; + canvas->cxDeactivate = cddeactivate; +} + +/******************************************************/ + +static cdContext cdDGNContext = +{ + CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_PLAY | + CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB | + CD_CAP_CLIPAREA | CD_CAP_CLIPPOLY | CD_CAP_RECT | + CD_CAP_LINECAP | CD_CAP_LINEJOIN | CD_CAP_REGION | CD_CAP_CHORD | + CD_CAP_IMAGERGB | CD_CAP_IMAGESRV | + CD_CAP_BACKGROUND | CD_CAP_BACKOPACITY | CD_CAP_WRITEMODE | + CD_CAP_HATCH | CD_CAP_STIPPLE | CD_CAP_PATTERN | + CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB | + CD_CAP_FPRIMTIVES | CD_CAP_TEXTORIENTATION), + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + +cdContext* cdContextDGN(void) +{ + return &cdDGNContext; +} + + diff --git a/src/drv/cddxf.c b/src/drv/cddxf.c new file mode 100644 index 0000000..b5c8854 --- /dev/null +++ b/src/drv/cddxf.c @@ -0,0 +1,1184 @@ +/** \file + * \brief DXF driver + * + * See Copyright Notice in cd.h + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <limits.h> +#include "cd.h" +#include "cd_private.h" +#include "cddxf.h" + + +#ifndef ignore +#define ignore(x) (void)x +#endif + +#ifndef max +#define max(x, y) ((x > y)? x : y) +#endif + +#ifndef min +#define min(x, y) ((x < y)? x : y) +#endif + +struct _cdCtxCanvas +{ + cdCanvas* canvas; + + FILE *file; /* pointer to file */ + int layer; /* layer */ + + int tf; /* text font */ + double th; /* text height (in points) */ + int toa; /* text oblique angle (for italics) */ + int tha, tva; /* text horizontal and vertical alignment */ + + int fgcolor; /* foreground AutoCAD palette color */ + + int lt; /* line type */ + double lw; /* line width (in milimeters) */ +}; + + +static void wnamline (cdCtxCanvas* ctxcanvas, int t) /* write name of a line */ +{ + + static char *line[] = + {"CONTINUOUS", + "DASHED", + "HIDDEN", + "CENTER", + "PHANTOM", + "DOT", + "DASHDOT", + "BORDER", + "DIVIDE"}; + +/* + AutoCAD line styles ( see acad.lin ): + + 0 CONTINUOUS ____________________________________________ + 1 DASHED __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ + 2 HIDDEN _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + 3 CENTER ____ _ ____ _ ____ _ ____ _ ____ _ ____ _ __ + 4 PHANTOM _____ _ _ _____ _ _ _____ _ _ _____ _ _ ____ + 5 DOT ............................................ + 6 DASHDOT __ . __ . __ . __ . __ . __ . __ . __ . __ . + 7 BORDER __ __ . __ __ . __ __ . __ __ . __ __ . __ _ + 8 DIVIDE __ . . __ . . __ . . __ . . __ . . __ . . __ + +*/ + + fprintf (ctxcanvas->file, "%s\n", line[t]); +} + + +static void wnamfont (cdCtxCanvas *ctxcanvas, int t) /* write name of a font */ +{ + static char *font[] = + { + "STANDARD", + "ROMAN", + "ROMAN_BOLD", + "ROMANTIC", + "ROMANTIC_BOLD", + "SANSSERIF", + "SANSSERIF_BOLD", + }; +/* + CD Fonts / Style AutoCAD Fonts + ------------------------------------------------------------------- + CD_SYSTEM 0 STANDARD + CD_COURIER / CD_PLAIN 1 ROMAN + CD_COURIER / CD_BOLD 2 ROMAN_BOLD + CD_COURIER / CD_ITALIC 1 ROMAN (ctxcanvas->toa = 15) + CD_COURIER / CD_BOLD_ITALIC 2 ROMAN_BOLD (ctxcanvas->toa = 15) + CD_TIMES_ROMAN / CD_PLAIN 3 ROMANTIC + CD_TIMES_ROMAN / CD_BOLD 4 ROMANTIC_BOLD + CD_TIMES_ROMAN / CD_ITALIC 3 ROMANTIC (ctxcanvas->toa = 15) + CD_TIMES_ROMAN / CD_BOLD_ITALIC 4 ROMANTIC_BOLD (ctxcanvas->toa = 15) + CD_HELVETICA / CD_PLAIN 5 SANSSERIF + CD_HELVETICA / CD_BOLD 6 SANSSERIF_BOLD + CD_HELVETICA / CD_ITALIC 5 SANSSERIF (ctxcanvas->toa = 15) + CD_HELVETICA / CD_BOLD_ITALIC 6 SANSSERIF_BOLD(ctxcanvas->toa = 15) +*/ + + fprintf (ctxcanvas->file, "%s\n", font[t]); +} + + +static void writepoly (cdCtxCanvas *ctxcanvas, cdPoint *poly, int nv) /* write polygon */ +{ + int i; + + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "POLYLINE\n" ); + fprintf ( ctxcanvas->file, "8\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */ + + fprintf ( ctxcanvas->file, "6\n" ); + wnamline( ctxcanvas, ctxcanvas->lt ); /* line type */ + + fprintf ( ctxcanvas->file, "62\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->fgcolor ); + fprintf ( ctxcanvas->file, "66\n" ); + fprintf ( ctxcanvas->file, "1\n" ); + fprintf ( ctxcanvas->file, "40\n" ); + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw/ctxcanvas->canvas->xres ); + fprintf ( ctxcanvas->file, "41\n" ); /* entire polygon line width */ + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw/ctxcanvas->canvas->xres ); + for ( i=0; i<nv; i++ ) + { + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "VERTEX\n" ); + fprintf ( ctxcanvas->file, "8\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */ + fprintf ( ctxcanvas->file, "10\n" ); + fprintf ( ctxcanvas->file, "%f\n", poly[i].x/ctxcanvas->canvas->xres ); + fprintf ( ctxcanvas->file, "20\n" ); + fprintf ( ctxcanvas->file, "%f\n", poly[i].y/ctxcanvas->canvas->xres ); + } + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "SEQEND\n" ); +} + +static void writepolyf (cdCtxCanvas *ctxcanvas, cdfPoint *poly, int nv) /* write polygon */ +{ + int i; + + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "POLYLINE\n" ); + fprintf ( ctxcanvas->file, "8\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */ + + fprintf ( ctxcanvas->file, "6\n" ); + wnamline( ctxcanvas, ctxcanvas->lt ); /* line type */ + + fprintf ( ctxcanvas->file, "62\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->fgcolor ); + fprintf ( ctxcanvas->file, "66\n" ); + fprintf ( ctxcanvas->file, "1\n" ); + fprintf ( ctxcanvas->file, "40\n" ); + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw/ctxcanvas->canvas->xres ); + fprintf ( ctxcanvas->file, "41\n" ); /* entire polygon line width */ + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw/ctxcanvas->canvas->xres ); + for ( i=0; i<nv; i++ ) + { + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "VERTEX\n" ); + fprintf ( ctxcanvas->file, "8\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */ + fprintf ( ctxcanvas->file, "10\n" ); + fprintf ( ctxcanvas->file, "%f\n", poly[i].x/ctxcanvas->canvas->xres ); + fprintf ( ctxcanvas->file, "20\n" ); + fprintf ( ctxcanvas->file, "%f\n", poly[i].y/ctxcanvas->canvas->xres ); + } + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "SEQEND\n" ); +} + +static void deflines (cdCtxCanvas *ctxcanvas) /* define lines */ +{ + int i, j; + static char *line[] = + {"Solid line", + "Dashed line", + "Hidden line", + "Center line", + "Phantom line", + "Dot line", + "Dashdot line", + "Border line", + "Divide Line"}; + +#define TABSIZE (sizeof(tab)/sizeof(tab[0])) + + static int tab[][8] = + { + { 0, 0, 0 , 0, 0, 0, 0, 0 }, + { 2, 15, 10, -5, 0, 0, 0, 0 }, + { 2, 10, 5 , -5, 0, 0, 0, 0 }, + { 4, 35, 20, -5, 5, -5, 0, 0 }, + { 6, 50, 25, -5, 5, -5, 5, -5 }, + { 2, 5, 0 , -5, 0, 0, 0, 0 }, + { 4, 20, 10, -5, 0, -5, 0, 0 }, + { 6, 35, 10, -5, 10, -5, 0, -5 }, + { 6, 25, 10, -5, 0, -5, 0, -5 } + }; + + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "TABLE\n"); + fprintf (ctxcanvas->file, "2\n"); + fprintf (ctxcanvas->file, "LTYPE\n"); + fprintf (ctxcanvas->file, "70\n"); + fprintf (ctxcanvas->file, "5\n"); + for (j = 0; j < TABSIZE; j++) + { + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "LTYPE\n"); + fprintf (ctxcanvas->file, "2\n"); + + wnamline (ctxcanvas, j); /* line style */ + + fprintf (ctxcanvas->file, "70\n"); + fprintf (ctxcanvas->file, "64\n"); + fprintf (ctxcanvas->file, "3\n"); + fprintf (ctxcanvas->file, "%s\n", line[j]); /* line style */ + fprintf (ctxcanvas->file, "72\n"); + fprintf (ctxcanvas->file, "65\n"); + fprintf (ctxcanvas->file, "73\n"); + fprintf (ctxcanvas->file, "%d\n", tab[j][0]); /* number of parameters */ + fprintf (ctxcanvas->file, "40\n"); + fprintf (ctxcanvas->file, "%d\n", tab[j][1]); + for (i = 2; i < 2 + tab[j][0]; i++) + { + fprintf (ctxcanvas->file, "49\n"); + fprintf (ctxcanvas->file, "%d\n", tab[j][i]); /* parameters */ + } + } + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "ENDTAB\n"); +} + + +static void deffonts (cdCtxCanvas *ctxcanvas) /* define fonts */ +{ + int i; + static char *font[] = + { + "romanc.shx" , + "romant.shx" , + "rom_____.pfb", + "romb____.pfb", + "sas_____.pfb", + "sasb____.pfb" + }; + + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "TABLE\n"); + fprintf (ctxcanvas->file, "2\n"); + fprintf (ctxcanvas->file, "STYLE\n"); + fprintf (ctxcanvas->file, "70\n"); + fprintf (ctxcanvas->file, "5\n"); + for (i = 1; i < 7; i++) + { + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "STYLE\n"); + fprintf (ctxcanvas->file, "2\n"); + + wnamfont (ctxcanvas, i); /* font style name */ + + fprintf (ctxcanvas->file, "3\n"); + fprintf (ctxcanvas->file, "%s\n", font[i-1]); /* font style file */ + fprintf (ctxcanvas->file, "70\n"); + fprintf (ctxcanvas->file, "64\n"); + fprintf (ctxcanvas->file, "71\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "40\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "41\n"); + fprintf (ctxcanvas->file, "1\n"); + fprintf (ctxcanvas->file, "42\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "50\n"); + fprintf (ctxcanvas->file, "0\n"); + } + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "ENDTAB\n"); +} + +static void cddeactivate (cdCtxCanvas *ctxcanvas) +{ + fflush (ctxcanvas->file); /* flush file */ +} + +static void cdkillcanvas(cdCtxCanvas *ctxcanvas) +{ + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "ENDSEC\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "EOF\n"); /* fputs eof */ + fprintf (ctxcanvas->file, " \n"); + + fflush (ctxcanvas->file); /* flush file */ + fclose (ctxcanvas->file); + + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + free (ctxcanvas); +} + +static void cdflush (cdCtxCanvas *ctxcanvas) +{ + ctxcanvas->layer++; +} + +/*==========================================================================*/ +/* Primitives */ +/*==========================================================================*/ +static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n) +{ + if (mode == CD_CLOSED_LINES || mode == CD_FILL) + { + poly[n].x = poly[0].x; + poly[n].y = poly[0].y; + n++; + } + + writepoly (ctxcanvas, poly, n); /* write polygon */ +} + +static void cdline (cdCtxCanvas *ctxcanvas, int x1, int y1, int x2, int y2) +{ + cdPoint line[2]; /* uses new array of points to avoid */ + + line[0].x = x1; /* starting point */ + line[0].y = y1; + line[1].x = x2; /* ending point */ + line[1].y = y2; + writepoly (ctxcanvas, line, 2); /* draw line as a polygon */ +} + +static void cdboxrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + cdPoint rect[5]; /* uses new array of points to avoid */ + + rect[0].x = xmin; + rect[0].y = ymin; + rect[1].x = xmin; + rect[1].y = ymax; + rect[2].x = xmax; /* box edges */ + rect[2].y = ymax; + rect[3].x = xmax; + rect[3].y = ymin; + rect[4].x = xmin; + rect[4].y = ymin; + writepoly (ctxcanvas, rect, 5); /* draw box as a polygon */ +} + +static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n) +{ + if (mode == CD_CLOSED_LINES || mode == CD_FILL) + { + poly[n].x = poly[0].x; + poly[n].y = poly[0].y; + n++; + } + + writepolyf (ctxcanvas, poly, n); /* write polygon */ +} + +static void cdfline (cdCtxCanvas *ctxcanvas, double x1, double y1, double x2, double y2) +{ + cdfPoint line[2]; /* uses new array of points to avoid */ + + line[0].x = x1; /* starting point */ + line[0].y = y1; + line[1].x = x2; /* ending point */ + line[1].y = y2; + writepolyf (ctxcanvas, line, 2); /* draw line as a polygon */ +} + +static void cdfboxrect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + cdfPoint rect[5]; /* uses new array of points to avoid */ + + rect[0].x = xmin; + rect[0].y = ymin; + rect[1].x = xmin; + rect[1].y = ymax; + rect[2].x = xmax; /* box edges */ + rect[2].y = ymax; + rect[3].x = xmax; + rect[3].y = ymin; + rect[4].x = xmin; + rect[4].y = ymin; + writepolyf (ctxcanvas, rect, 5); /* draw box as a polygon */ +} + +/*--------------------------------------------------------------------------*/ +/* gives radius of the circle most resembling elliptic arc at angle t */ +/*--------------------------------------------------------------------------*/ +static double calc_radius (double a, double b, double t) +{ + return (pow ((a*a*sin(t)*sin(t) + b*b*cos(t)*cos(t)), 1.5))/(a*b); +} + +/*--------------------------------------------------------------------------*/ +/* calculates bulge for a given circular arc segment (between points p1 and */ +/* p2, with radius r). Bulge is the tangent of 1/4 the angle theta of the */ +/* arc segment(a bulge of 1 is a semicircle, which has an angle of 180 deg) */ +/*--------------------------------------------------------------------------*/ +static double calc_bulge (double a, double b, double t1, double t2) +{ + cdfPoint p1, p2; /* initial and ending arc points */ + double r; /* radius most resembling arc at angle (t1+t2)/2 */ + double theta; /* angle of circular arc segment */ + double sin_theta; /* sine of theta */ + double dist_x; /* distance between two points along the x axis */ + double dist_y; /* distance between two points along the y axis */ + double halfdist; /* half distance between two points */ + + p1.x = a*cos(t1); + p1.y = b*sin(t1); + p2.x = a*cos(t2); + p2.y = b*sin(t2); + r = calc_radius (a, b, (t1+t2)/2); + + dist_x = p2.x - p1.x; + dist_y = p2.y - p1.y; + halfdist = (sqrt (dist_x*dist_x + dist_y*dist_y))/2; + sin_theta = halfdist/r; + if (sin_theta > 1) sin_theta = 1; + theta = 2*asin(sin_theta); + + return tan(theta/4); +} + +static void writevertex (cdCtxCanvas *ctxcanvas, int xc, int yc, double a, double b, double t, double bulge) +{ + cdfPoint p; + p.x = (xc + a*cos(t))/ctxcanvas->canvas->xres; + p.y = (yc + b*sin(t))/ctxcanvas->canvas->xres; + + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "VERTEX\n" ); + fprintf ( ctxcanvas->file, "8\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */ + fprintf ( ctxcanvas->file, "10\n" ); + fprintf ( ctxcanvas->file, "%f\n", p.x ); + fprintf ( ctxcanvas->file, "20\n" ); /* vertex coordinates */ + fprintf ( ctxcanvas->file, "%f\n", p.y ); + fprintf ( ctxcanvas->file, "42\n" ); /* bulge from this vertex */ + fprintf ( ctxcanvas->file, "%f\n", bulge ); /* to the next one */ +} + +static void cdarc (cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + double bulge; /* bulge is the tangent of 1/4 the angle for a given */ + /* circle arc segment (a bulge of 1 is a semicircle) */ + double t; /* current arc angle being calculated */ + double t1; /* a1 in radians */ + double t2; /* a2 in radians */ + double a; /* half horizontal axis */ + double b; /* half vertical axis */ + double seg_angle; /* angle of every arc segment */ + double diff; /* angle between a1 and a2 */ + int nseg; /* number of arc segments */ + int i; + + a = w/2; + b = h/2; + t1 = a1*CD_DEG2RAD; /* a1 in radians */ + t2 = a2*CD_DEG2RAD; /* a2 in radians */ + diff = fabs(a2 - a1); + nseg = cdRound(diff)/(360/32); /* 32 segments in closed ellipse */ + nseg = max(nseg, 1); + seg_angle = (t2-t1)/nseg; + + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "POLYLINE\n" ); + fprintf ( ctxcanvas->file, "8\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */ + fprintf ( ctxcanvas->file, "6\n" ); + wnamline( ctxcanvas, ctxcanvas->lt ); /* line type */ + fprintf ( ctxcanvas->file, "62\n" ); + fprintf ( ctxcanvas->file, "%3d\n", ctxcanvas->fgcolor ); /* color */ + fprintf ( ctxcanvas->file, "66\n" ); + fprintf ( ctxcanvas->file, "1\n" ); + fprintf ( ctxcanvas->file, "70\n" ); + fprintf ( ctxcanvas->file, "128\n" ); + fprintf ( ctxcanvas->file, "40\n" ); + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw ); + fprintf ( ctxcanvas->file, "41\n" ); /* entire arc line width */ + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw ); + + for (i=0, t=t1; i<nseg; i++, t+=seg_angle) + { /* calculate bulge between t */ + bulge = calc_bulge (a, b, t, t+seg_angle); /* and t+seg_angle and write */ + writevertex (ctxcanvas, xc, yc, a, b, t, bulge); /* vertex at t */ + } + writevertex (ctxcanvas, xc, yc, a, b, t2, 0); /* bulge of last vertex is useless */ + + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "SEQEND\n" ); +} + +static void cdsector (cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + double bulge; /* bulge is the tangent of 1/4 the angle for a given */ + /* circle arc segment (a bulge of 1 is a semicircle) */ + double t; /* current arc angle being calculated */ + double t1; /* a1 in radians */ + double t2; /* a2 in radians */ + double a; /* half horizontal axis */ + double b; /* half vertical axis */ + double seg_angle; /* angle of every arc segment */ + double diff; /* angle between a1 and a2 */ + int nseg; /* number of arc segments */ + int i; + + a = w/2; + b = h/2; + t1 = a1*CD_DEG2RAD; /* a1 in radians */ + t2 = a2*CD_DEG2RAD; /* a2 in radians */ + diff = fabs(a2 - a1); + nseg = cdRound(diff)/(360/32); /* 32 segments in closed ellipse */ + nseg = max(nseg, 1); + seg_angle = (t2-t1)/nseg; + + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "POLYLINE\n" ); + fprintf ( ctxcanvas->file, "8\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */ + fprintf ( ctxcanvas->file, "6\n" ); + wnamline( ctxcanvas, ctxcanvas->lt ); /* line type */ + fprintf ( ctxcanvas->file, "62\n" ); + fprintf ( ctxcanvas->file, "%3d\n", ctxcanvas->fgcolor ); /* color */ + fprintf ( ctxcanvas->file, "66\n" ); + fprintf ( ctxcanvas->file, "1\n" ); + fprintf ( ctxcanvas->file, "70\n" ); + fprintf ( ctxcanvas->file, "128\n" ); + fprintf ( ctxcanvas->file, "40\n" ); + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw ); + fprintf ( ctxcanvas->file, "41\n" ); /* entire arc line width */ + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw ); + + if ((a2-a1) != 360) + writevertex (ctxcanvas, xc, yc, 0, 0, 0, 0); /* center */ + for (i=0, t=t1; i<nseg; i++, t+=seg_angle) + { /* calculate bulge between t */ + bulge = calc_bulge (a, b, t, t+seg_angle); /* and t+seg_angle and write */ + writevertex (ctxcanvas, xc, yc, a, b, t, bulge); /* vertex at t */ + } + writevertex (ctxcanvas, xc, yc, a, b, t2, 0); /* bulge of last vertex is useless */ + if ((a2-a1) != 360) + writevertex (ctxcanvas, xc, yc, 0, 0, 0, 0); /* center */ + + fprintf ( ctxcanvas->file, " 0\n" ); + fprintf ( ctxcanvas->file, "SEQEND\n" ); +} + +static void cdtext (cdCtxCanvas *ctxcanvas, int x, int y, const char *s) +{ + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "TEXT\n" ); + fprintf ( ctxcanvas->file, "8\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */ + fprintf ( ctxcanvas->file, "7\n" ); + wnamfont( ctxcanvas, ctxcanvas->tf ); /* current font */ + fprintf ( ctxcanvas->file, "62\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->fgcolor ); /* color */ + fprintf ( ctxcanvas->file, "10\n" ); + fprintf ( ctxcanvas->file, "%f\n", x/ctxcanvas->canvas->xres ); /* current position */ + fprintf ( ctxcanvas->file, "20\n" ); + fprintf ( ctxcanvas->file, "%f\n", y/ctxcanvas->canvas->xres ); + fprintf ( ctxcanvas->file, "11\n" ); + fprintf ( ctxcanvas->file, "%f\n", x/ctxcanvas->canvas->xres ); /* alignment point */ + fprintf ( ctxcanvas->file, "21\n" ); + fprintf ( ctxcanvas->file, "%f\n", y/ctxcanvas->canvas->xres ); + fprintf ( ctxcanvas->file, "40\n" ); + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->th ); /* text height */ + fprintf ( ctxcanvas->file, "50\n" ); + fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->canvas->text_orientation ); /* text orientation angle */ + fprintf ( ctxcanvas->file, "51\n" ); + fprintf ( ctxcanvas->file, "%3d\n", ctxcanvas->toa ); /* text oblique angle */ + fprintf ( ctxcanvas->file, "72\n" ); + fprintf ( ctxcanvas->file, "%3d\n", ctxcanvas->tha ); /* text horizontal alignment */ + fprintf ( ctxcanvas->file, "73\n" ); + fprintf ( ctxcanvas->file, "%3d\n", ctxcanvas->tva ); /* text vertical alignment */ + fprintf ( ctxcanvas->file, "1\n" ); + fprintf ( ctxcanvas->file, "%s\n", s ); /* text */ +} + + +/*==========================================================================*/ +/* Attributes */ +/*==========================================================================*/ + +static int cdlinestyle (cdCtxCanvas *ctxcanvas, int style) +{ + switch (style) + { + case CD_CONTINUOUS: + ctxcanvas->lt = 0; + break; + case CD_DASHED: + ctxcanvas->lt = 1; + break; + case CD_DOTTED: + ctxcanvas->lt = 5; + break; + case CD_DASH_DOT: + ctxcanvas->lt = 6; + break; + case CD_DASH_DOT_DOT: + ctxcanvas->lt = 8; + break; + } + + return style; +} + +static int cdlinewidth (cdCtxCanvas *ctxcanvas, int width) +{ + ctxcanvas->lw = width/ctxcanvas->canvas->xres; + return width; +} + +static int cdfont (cdCtxCanvas *ctxcanvas, const char *type_face, int style, int size) +{ + /* obs: DXF's text height (ctxcanvas->th) corresponds to CD ascent */ + + if (cdStrEqualNoCase(type_face, "System")) + { + ctxcanvas->tf = 0; + ctxcanvas->toa = 0; + ctxcanvas->th = 0.75; + } + else if (cdStrEqualNoCase(type_face, "Courier")) + { + switch (style&3) + { + case CD_PLAIN: + ctxcanvas->tf = 1; + ctxcanvas->toa = 0; + break; + + case CD_BOLD: + ctxcanvas->tf = 2; + ctxcanvas->toa = 0; + break; + + case CD_ITALIC: + ctxcanvas->tf = 1; + ctxcanvas->toa = 15; + break; + + case CD_BOLD_ITALIC: + ctxcanvas->tf = 2; + ctxcanvas->toa = 15; + break; + } + ctxcanvas->th = 0.75; + } + else if (cdStrEqualNoCase(type_face, "Times")) + { + switch (style&3) + { + case CD_PLAIN: + ctxcanvas->tf = 3; + ctxcanvas->toa = 0; + break; + + case CD_BOLD: + ctxcanvas->tf = 4; + ctxcanvas->toa = 0; + break; + + case CD_ITALIC: + ctxcanvas->tf = 3; + ctxcanvas->toa = 15; + break; + + case CD_BOLD_ITALIC: + ctxcanvas->tf = 4; + ctxcanvas->toa = 15; + break; + } + ctxcanvas->th = 1.125; + } + else if (cdStrEqualNoCase(type_face, "Helvetica")) + { + switch (style&3) + { + case CD_PLAIN: + ctxcanvas->tf = 5; + ctxcanvas->toa = 0; + break; + + case CD_BOLD: + ctxcanvas->tf = 6; + ctxcanvas->toa = 0; + break; + + case CD_ITALIC: + ctxcanvas->tf = 5; + ctxcanvas->toa = 15; + break; + + case CD_BOLD_ITALIC: + ctxcanvas->tf = 6; + ctxcanvas->toa = 15; + break; + } + ctxcanvas->th = 1.; + } + else + return 0; + + ctxcanvas->th = ctxcanvas->th * cdGetFontSizePoints(ctxcanvas->canvas, size); + + return 1; +} + +static void cdgetfontdim (cdCtxCanvas *ctxcanvas, int *max_width, int *height, int *ascent, int *descent) +{ + double tangent_ta; + double pixel_th; + + tangent_ta = tan(ctxcanvas->toa*CD_DEG2RAD); + pixel_th = (ctxcanvas->th*ctxcanvas->canvas->xres)/CD_MM2PT; /* points to pixels */ + switch (ctxcanvas->tf) + { + case 0: /* STANDARD font (CD_SYSTEM) */ + if (height) *height = cdRound(pixel_th*4/3); + if (ascent) *ascent = _cdRound(pixel_th); + if (descent) *descent = cdRound(pixel_th/3); + if (max_width) *max_width = _cdRound(pixel_th); + break; + + case 1: /* ROMAN fonts (CD_COURIER) */ + case 2: + if (height) *height = cdRound(pixel_th*4/3); + if (ascent) *ascent = _cdRound(pixel_th); + if (descent) *descent = cdRound(pixel_th/3); + if (max_width) *max_width = cdRound((pixel_th*21/20) + tangent_ta*(*ascent)); + break; + + case 3: /* ROMANTIC fonts (CD_TIMES_ROMAN) */ + if (height) *height = cdRound(pixel_th*8/9); + if (ascent) *ascent = cdRound(pixel_th*2/3); + if (descent) *descent = cdRound(pixel_th*2/9); + if (max_width) *max_width = cdRound((pixel_th*14/15) + tangent_ta*(*ascent)); + break; + + case 4: + if (height) *height = cdRound(pixel_th*8/9); + if (ascent) *ascent = cdRound(pixel_th*2/3); + if (descent) *descent = cdRound(pixel_th*2/9); + if (max_width) *max_width = cdRound((pixel_th*29/30) + tangent_ta*(*ascent)); + break; + + case 5: /* SANSSERIF fonts (CD_HELVETICA) */ + case 6: + if (height) *height = _cdRound(pixel_th); + if (ascent) *ascent = cdRound(pixel_th*3/4); + if (descent) *descent = cdRound(pixel_th/4); + if (max_width) *max_width = cdRound((pixel_th*15/16) + tangent_ta*(*ascent)); + break; + } +} + +static void cdgettextsize (cdCtxCanvas *ctxcanvas, const char *s, int *width, int *height) +{ + int i; + double tangent_ta; + double pixel_th; + + i = (int)strlen(s); + tangent_ta = tan(ctxcanvas->toa*CD_DEG2RAD); + pixel_th = (ctxcanvas->th*ctxcanvas->canvas->xres)/CD_MM2PT; /* points to pixels */ + + switch (ctxcanvas->tf) /* width return value based on maximum character width */ + { + case 0: /* STANDARD font (CD_SYSTEM) */ + if (height) *height = cdRound(pixel_th*4/3); + if (width) *width = cdRound(pixel_th*i + (pixel_th/3)*(i-1)); + break; + + case 1: /* ROMAN fonts (CD_COURIER) */ + case 2: + if (height) *height = cdRound(pixel_th*4/3); + if (width) *width = cdRound((pixel_th*21/20)*i + (pixel_th/10)*(i-1) + tangent_ta*pixel_th); + break; + + case 3: /* ROMANTIC fonts (CD_TIMES_ROMAN) */ + if (height) *height = cdRound(pixel_th*2/3 + pixel_th*2/9); + if (width) *width = cdRound((pixel_th*14/15)*i + (pixel_th/45)*(i-1) + tangent_ta*pixel_th*2/3); + break; + + case 4: + if (height) *height = cdRound(pixel_th*2/3 + pixel_th*2/9); + if (width) *width = cdRound((pixel_th*29/30)*i + (pixel_th*2/45)*(i-1) + tangent_ta*pixel_th*2/3); + break; + + case 5: /* SANSSERIF fonts (CD_HELVETICA) */ + case 6: + if (height) *height = _cdRound(pixel_th); + if (width) *width = cdRound((pixel_th*15/16)*i + (pixel_th/45)*(i-1) + tangent_ta*pixel_th*3/4); + break; + } +} + +static int cdtextalignment (cdCtxCanvas *ctxcanvas, int alignment) +{ + switch (alignment) /* convert alignment to DXF format */ + { + case CD_BASE_LEFT: + ctxcanvas->tva = 0; + ctxcanvas->tha = 0; + break; + + case CD_BASE_CENTER: + ctxcanvas->tva = 0; + ctxcanvas->tha = 1; + break; + + case CD_BASE_RIGHT: + ctxcanvas->tva = 0; + ctxcanvas->tha = 2; + break; + + case CD_SOUTH_WEST: + ctxcanvas->tva = 1; + ctxcanvas->tha = 0; + break; + + case CD_SOUTH: + ctxcanvas->tva = 1; + ctxcanvas->tha = 1; + break; + + case CD_SOUTH_EAST: + ctxcanvas->tva = 1; + ctxcanvas->tha = 2; + break; + + case CD_WEST: + ctxcanvas->tva = 2; + ctxcanvas->tha = 0; + break; + + case CD_CENTER: + ctxcanvas->tva = 2; + ctxcanvas->tha = 1; + break; + + case CD_EAST: + ctxcanvas->tva = 2; + ctxcanvas->tha = 2; + break; + + case CD_NORTH_WEST: + ctxcanvas->tva = 3; + ctxcanvas->tha = 0; + break; + + case CD_NORTH: + ctxcanvas->tva = 3; + ctxcanvas->tha = 1; + break; + + case CD_NORTH_EAST: + ctxcanvas->tva = 3; + ctxcanvas->tha = 2; + break; + } + + return alignment; +} + +/*==========================================================================*/ +/* Color */ +/*==========================================================================*/ + +static void RGB_to_HSB (unsigned char r, unsigned char g, unsigned char b, + double *hue, double *sat, double *bright) +{ + double maximum; + double minimum; + double delta; + double red = r/255.; /* red, green and blue range from 0 to 1 */ + double green = g/255.; + double blue = b/255.; + + maximum = max(max(red, green), blue); /* stores higher index */ + minimum = min(min(red, green), blue); /* stores lower index */ + delta = maximum - minimum; + + *bright = maximum*100; + *sat = 0; + + if (maximum != 0) /* sat from 0 to 100 */ + *sat = (delta*100)/maximum; + + if (*sat != 0) /* hue from 0 to 359 */ + { + if (red == maximum) *hue = (green - blue)/delta; + if (green == maximum) *hue = 2 + (blue - red)/delta; + if (blue == maximum) *hue = 4 + (red - green)/delta; + *hue *= 60; + if (*hue < 0) *hue += 360; + } + else + *hue = 0; /* color is greyscale (hue is meaningless) */ +} + +static int HSB_to_AutoCAD_Palette (double hue, double sat, double bright) +{ + int index; + int h, s, b; + + if (bright < 17) /* 5 levels of brightness in AutoCAD palette, 6 with */ + { /* black. If bright < 17, index is black (7). */ + index = 7; /* 17 is 100/6 (rounded up) */ + } + else if (sat < 10) /* low saturation makes color tend to */ + { /* grey/white. 6 levels of grey/white in */ + b = (int)floor(bright/14.3)-1;/* palette WITHOUT black. 14.3 is 100/7 */ + index = 250 + b; /* index is grey to white(255 in palette) */ + } + else + { + h = cdRound(hue/15.) + 1; + if (h > 24) h -= 24; /* 15 is 360/24 */ + h *= 10; /* h ranges from 10 to 240 in palette */ + s = (sat < 55) ? 1 : 0; /* s is 'high'(0) or 'low'(1) in palette */ + b = (int)floor(bright/16.7)-1;/* b is 0, 2, 4, 6 or 8 in palette */ + b = 2*(4 - b); /* (from brightest to dimmest) */ + index = h + s + b; /* index is simple sum of h, s and b */ + } + return index; +} + +static int get_palette_index (long int color) /* gives closest palette */ +{ /* index to RGB color */ + unsigned char red, green, blue; + double hue, sat, bright; + + cdDecodeColor (color, &red, &green, &blue); /* AutoCAD palette is */ + RGB_to_HSB (red, green, blue, &hue, &sat, &bright); /* based on HSB model */ + + return HSB_to_AutoCAD_Palette (hue, sat, bright); +} + +static long int cdforeground (cdCtxCanvas *ctxcanvas, long int color) +{ + ctxcanvas->fgcolor = get_palette_index (color); + return color; +} + + +/*==========================================================================*/ +/* Server Images */ +/*==========================================================================*/ + +static void cdpixel (cdCtxCanvas *ctxcanvas, int x, int y, long int color) +{ + int oldcolor = ctxcanvas->fgcolor; /* put 'color' as current */ + cdforeground (ctxcanvas, color); /* foreground color */ + fprintf ( ctxcanvas->file, "0\n" ); + fprintf ( ctxcanvas->file, "POINT\n" ); + fprintf ( ctxcanvas->file, "8\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */ + fprintf ( ctxcanvas->file, "62\n" ); + fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->fgcolor ); /* color */ + fprintf ( ctxcanvas->file, "10\n" ); + fprintf ( ctxcanvas->file, "%f\n", x/ctxcanvas->canvas->xres ); /* position */ + fprintf ( ctxcanvas->file, " 20\n" ); + fprintf ( ctxcanvas->file, "%f\n", y/ctxcanvas->canvas->xres ); + ctxcanvas->fgcolor = oldcolor; /* retrieve old fgcolor */ +} + +/******************************************************/ + +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + char filename[10240] = ""; + char* strdata = (char*)data; + cdCtxCanvas *ctxcanvas; + double param1, param2, param3; + + ctxcanvas = (cdCtxCanvas *) malloc (sizeof (cdCtxCanvas)); + + param1 = 0; + param2 = 0; + param3 = 0; + + strdata += cdGetFileName(strdata, filename); + if (filename[0] == 0) + return; + + sscanf(strdata, "%lfx%lf %lf", ¶m1, ¶m2, ¶m3); + + ctxcanvas->file = fopen (filename, "w"); + if (ctxcanvas->file == NULL) + { + free(ctxcanvas); + return; + } + + if (!param1) + { + canvas->w_mm = INT_MAX*3.78; + canvas->h_mm = INT_MAX*3.78; + canvas->xres = 3.78; + } + else if (!param2) + { + canvas->w_mm = INT_MAX*param1; + canvas->h_mm = INT_MAX*param1; + canvas->xres = param1; + } + else if (!param3) + { + canvas->w_mm = param1; + canvas->h_mm = param2; + canvas->xres = 3.78; + } + else + { + canvas->w_mm = param1; + canvas->h_mm = param2; + canvas->xres = param3; + } + + ctxcanvas->canvas = canvas; + canvas->ctxcanvas = ctxcanvas; + + canvas->bpp = 8; + + canvas->yres = canvas->xres; + + canvas->w = (int)(canvas->w_mm * canvas->xres); + canvas->h = (int)(canvas->h_mm * canvas->yres); + + ctxcanvas->layer = 0; /* reset layer */ + + ctxcanvas->tf = 0; /* text font (0 is STANDARD) */ + ctxcanvas->th = 9; /* text height */ + ctxcanvas->toa = 0; /* text oblique angle */ + ctxcanvas->tva = 0; /* text vertical alignment (0 is baseline) */ + ctxcanvas->tha = 0; /* text horizontal alignment (0 is left) */ + ctxcanvas->fgcolor = 7; /* foreground AutoCAD palette color */ + + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "SECTION\n"); /* header maker */ + fprintf (ctxcanvas->file, "2\n"); + fprintf (ctxcanvas->file, "HEADER\n"); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$LIMCHECK\n"); + fprintf (ctxcanvas->file, "70\n"); + fprintf (ctxcanvas->file, "1\n"); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$LIMMIN\n"); + fprintf (ctxcanvas->file, "10\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "20\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$LIMMAX\n"); + fprintf (ctxcanvas->file, "10\n"); + fprintf (ctxcanvas->file, "%f\n", ctxcanvas->canvas->w_mm); + fprintf (ctxcanvas->file, "20\n"); + fprintf (ctxcanvas->file, "%f\n", ctxcanvas->canvas->h_mm); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$EXTMIN\n"); + fprintf (ctxcanvas->file, "10\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "20\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$EXTMAX\n"); + fprintf (ctxcanvas->file, "10\n"); + fprintf (ctxcanvas->file, "%f\n", ctxcanvas->canvas->w_mm); + fprintf (ctxcanvas->file, "20\n"); + fprintf (ctxcanvas->file, "%f\n", ctxcanvas->canvas->h_mm); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$CLAYER\n"); + fprintf (ctxcanvas->file, "8\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$LUNITS\n"); + fprintf (ctxcanvas->file, "70\n"); + fprintf (ctxcanvas->file, "2\n"); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$LUPREC\n"); + fprintf (ctxcanvas->file, "70\n"); /* precision (resolution dependant) */ + fprintf (ctxcanvas->file, "%d\n", (int)ceil(log10(ctxcanvas->canvas->xres))); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$AUNITS\n"); + fprintf (ctxcanvas->file, "70\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$AUPREC\n"); + fprintf (ctxcanvas->file, "70\n"); + fprintf (ctxcanvas->file, "2\n"); + fprintf (ctxcanvas->file, "9\n"); + fprintf (ctxcanvas->file, "$TEXTSTYLE\n"); + fprintf (ctxcanvas->file, "7\n"); + fprintf (ctxcanvas->file, "STANDARD\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "ENDSEC\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "SECTION\n"); + fprintf (ctxcanvas->file, "2\n"); + fprintf (ctxcanvas->file, "TABLES\n"); + + deflines (ctxcanvas); /* define lines */ + deffonts (ctxcanvas); /* define fonts */ + + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "ENDSEC\n"); + fprintf (ctxcanvas->file, "0\n"); + fprintf (ctxcanvas->file, "SECTION\n"); + fprintf (ctxcanvas->file, "2\n"); + fprintf (ctxcanvas->file, "ENTITIES\n"); +} + +static void cdinittable(cdCanvas* canvas) +{ + canvas->cxFlush = cdflush; + canvas->cxPixel = cdpixel; + canvas->cxLine = cdline; + canvas->cxPoly = cdpoly; + canvas->cxRect = cdboxrect; + canvas->cxBox = cdboxrect; + canvas->cxFLine = cdfline; + canvas->cxFPoly = cdfpoly; + canvas->cxFRect = cdfboxrect; + canvas->cxFBox = cdfboxrect; + canvas->cxArc = cdarc; + canvas->cxSector = cdsector; + canvas->cxText = cdtext; + canvas->cxGetFontDim = cdgetfontdim; + canvas->cxGetTextSize = cdgettextsize; + + canvas->cxLineStyle = cdlinestyle; + canvas->cxLineWidth = cdlinewidth; + canvas->cxFont = cdfont; + canvas->cxTextAlignment = cdtextalignment; + canvas->cxForeground = cdforeground; + + canvas->cxKillCanvas = cdkillcanvas; + canvas->cxDeactivate = cddeactivate; +} + +/******************************************************/ + +static cdContext cdDXFContext = +{ + CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_PLAY | CD_CAP_PALETTE | + CD_CAP_CLIPAREA | CD_CAP_CLIPPOLY | + CD_CAP_LINECAP | CD_CAP_LINEJOIN | CD_CAP_REGION | CD_CAP_CHORD | + CD_CAP_IMAGERGB | CD_CAP_IMAGEMAP | CD_CAP_IMAGESRV | + CD_CAP_BACKGROUND | CD_CAP_BACKOPACITY | CD_CAP_WRITEMODE | + CD_CAP_HATCH | CD_CAP_STIPPLE | CD_CAP_PATTERN | + CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB), + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + +cdContext* cdContextDXF(void) +{ + return &cdDXFContext; +} + diff --git a/src/drv/cdirgb.c b/src/drv/cdirgb.c new file mode 100644 index 0000000..9fbb540 --- /dev/null +++ b/src/drv/cdirgb.c @@ -0,0 +1,2135 @@ +/** \file + * \brief Image RGB Driver + * + * See Copyright Notice in cd.h + */ + +#include <stdlib.h> +#include <memory.h> +#include <math.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#include "cd.h" +#include "cd_private.h" +#include "cd_truetype.h" +#include "sim.h" +#include "cdirgb.h" + + +struct _cdCtxImage +{ + int w, h; + unsigned char* red; /* red color buffer */ + unsigned char* green; /* green color buffer */ + unsigned char* blue; /* blue color buffer */ + unsigned char* alpha; /* alpha color buffer */ +}; + + +struct _cdCtxCanvas +{ + cdCanvas* canvas; + + int user_image; /* can not free an user image */ + + unsigned char* red; /* red color buffer */ + unsigned char* green; /* green color buffer */ + unsigned char* blue; /* blue color buffer */ + unsigned char* alpha; /* alpha color buffer */ + unsigned char* clip; /* clipping buffer */ + + unsigned char* clip_region; /* clipping region used during NewRegion */ + + float rotate_angle; + int rotate_center_x, + rotate_center_y; + + cdCanvas* canvas_dbuffer; /* used by the CD_DBUFFERRGB driver */ +}; + +/*******************/ +/* Local functions */ +/*******************/ + +#define _sNormX(_ctxcanvas, _x) (_x < 0? 0: _x < _ctxcanvas->canvas->w? _x: _ctxcanvas->canvas->w-1) +#define _sNormY(_ctxcanvas, _y) (_y < 0? 0: _y < _ctxcanvas->canvas->h? _y: _ctxcanvas->canvas->h-1) + +#define RGBA_COMPOSE(_SRC, _SRC_ALPHA, _DST, _TMP_MULTI, _TMP_ALPHA) (unsigned char)(((_SRC_ALPHA)*(_SRC) + (_TMP_MULTI)*(_DST)) / (_TMP_ALPHA)) + +#define RGBA_COLOR_COMBINE(_ctxcanvas, _pdst_red, _pdst_green, _pdst_blue, _pdst_alpha, _src_red, _src_green, _src_blue, _src_alpha) \ +{ \ + unsigned char _tmp_red = 0, _tmp_green = 0, _tmp_blue = 0; \ + \ + if (_pdst_alpha) /* (_pdst_alpha != NULL) */ \ + { \ + if (_src_alpha != 255) /* some transparency */ \ + { \ + if (_src_alpha != 0) /* source not full transparent */ \ + { \ + if (*_pdst_alpha == 0) /* destiny full transparent */ \ + { \ + _tmp_red = _src_red; \ + _tmp_green = _src_green; \ + _tmp_blue = _src_blue; \ + *_pdst_alpha = _src_alpha; \ + } \ + else if (*_pdst_alpha == 255) /* destiny opaque */ \ + { \ + _tmp_red = CD_ALPHA_BLEND(_src_red, *_pdst_red, _src_alpha); \ + _tmp_green = CD_ALPHA_BLEND(_src_green, *_pdst_green, _src_alpha); \ + _tmp_blue = CD_ALPHA_BLEND(_src_blue, *_pdst_blue, _src_alpha); \ + /* *_pdst_alpha is not changed */ \ + } \ + else /* (0<*_pdst_alpha<255 && 0<_src_alpha<255) destiny and source are semi-transparent */ \ + { \ + /* Closed Compositing Formulas for SRC over DST, Colors Not Premultiplied by Alpha: */ \ + int _tmp_multi = *_pdst_alpha * (255 - _src_alpha); \ + int _tmp_alpha = _src_alpha + _tmp_multi; \ + _tmp_red = RGBA_COMPOSE(_src_red, _src_alpha, *_pdst_red, _tmp_multi, _tmp_alpha); \ + _tmp_green = RGBA_COMPOSE(_src_green, _src_alpha, *_pdst_green, _tmp_multi, _tmp_alpha); \ + _tmp_blue = RGBA_COMPOSE(_src_blue, _src_alpha, *_pdst_blue, _tmp_multi, _tmp_alpha); \ + *_pdst_alpha = (unsigned char)(_tmp_alpha / 255); \ + } \ + } \ + else /* (_src_alpha == 0) source full transparent */ \ + { \ + _tmp_red = *_pdst_red; \ + _tmp_green = *_pdst_green; \ + _tmp_blue = *_pdst_blue; \ + /* *_pdst_alpha is not changed */ \ + } \ + } \ + else /* (_src_alpha == 255) source has no alpha = opaque */ \ + { \ + _tmp_red = _src_red; \ + _tmp_green = _src_green; \ + _tmp_blue = _src_blue; \ + *_pdst_alpha = (unsigned char)255; /* set destiny as opaque */ \ + } \ + } \ + else /* (_pdst_alpha == NULL) */ \ + { \ + if (_src_alpha != 255) /* source has some transparency */ \ + { \ + if (_src_alpha != 0) /* source semi-transparent */ \ + { \ + _tmp_red = CD_ALPHA_BLEND(_src_red, *_pdst_red, _src_alpha); \ + _tmp_green = CD_ALPHA_BLEND(_src_green, *_pdst_green, _src_alpha); \ + _tmp_blue = CD_ALPHA_BLEND(_src_blue, *_pdst_blue, _src_alpha); \ + } \ + else /* (_src_alpha == 0) source full transparent */ \ + { \ + _tmp_red = *_pdst_red; \ + _tmp_green = *_pdst_green; \ + _tmp_blue = *_pdst_blue; \ + } \ + } \ + else /* (_src_alpha == 255) source has no alpha = opaque */ \ + { \ + _tmp_red = _src_red; \ + _tmp_green = _src_green; \ + _tmp_blue = _src_blue; \ + } \ + } \ + \ + switch (_ctxcanvas->canvas->write_mode) \ + { \ + case CD_REPLACE: \ + *_pdst_red = _tmp_red; \ + *_pdst_green = _tmp_green; \ + *_pdst_blue = _tmp_blue; \ + break; \ + case CD_XOR: \ + *_pdst_red ^= _tmp_red; \ + *_pdst_green ^= _tmp_green; \ + *_pdst_blue ^= _tmp_blue; \ + break; \ + case CD_NOT_XOR: \ + *_pdst_red = (unsigned char)~(_tmp_red ^ *_pdst_red); \ + *_pdst_green = (unsigned char)~(_tmp_green ^ *_pdst_green); \ + *_pdst_blue = (unsigned char)~(_tmp_blue ^ *_pdst_blue); \ + break; \ + } \ +} + +static void sCombineRGBColor(cdCtxCanvas* ctxcanvas, int offset, long color) +{ + unsigned char *dr = ctxcanvas->red + offset; + unsigned char *dg = ctxcanvas->green + offset; + unsigned char *db = ctxcanvas->blue + offset; + unsigned char *da = ctxcanvas->alpha? ctxcanvas->alpha + offset: NULL; + unsigned char *clip = ctxcanvas->clip + offset; + + unsigned char sr = cdRed(color); + unsigned char sg = cdGreen(color); + unsigned char sb = cdBlue(color); + unsigned char sa = cdAlpha(color); + + if (*clip) + RGBA_COLOR_COMBINE(ctxcanvas, dr, dg, db, da, sr, sg, sb, sa); +} + +static void sCombineRGB(cdCtxCanvas* ctxcanvas, int offset, unsigned char sr, unsigned char sg, unsigned char sb, unsigned char sa) +{ + unsigned char *dr = ctxcanvas->red + offset; + unsigned char *dg = ctxcanvas->green + offset; + unsigned char *db = ctxcanvas->blue + offset; + unsigned char *da = ctxcanvas->alpha? ctxcanvas->alpha + offset: NULL; + unsigned char *clip = ctxcanvas->clip + offset; + + if (*clip) + RGBA_COLOR_COMBINE(ctxcanvas, dr, dg, db, da, sr, sg, sb, sa); +} + +static void sCombineRGBLine(cdCtxCanvas* ctxcanvas, int offset, const unsigned char *sr, const unsigned char *sg, const unsigned char *sb, int size) +{ + int c; + unsigned char *dr = ctxcanvas->red + offset; + unsigned char *dg = ctxcanvas->green + offset; + unsigned char *db = ctxcanvas->blue + offset; + unsigned char *da = ctxcanvas->alpha? ctxcanvas->alpha + offset: NULL; + unsigned char *clip = ctxcanvas->clip + offset; + unsigned char src_a = 255; + + if (size > 0) + { + for (c = 0; c < size; c++) + { + if (*clip) + RGBA_COLOR_COMBINE(ctxcanvas, dr, dg, db, da, *sr, *sg, *sb, src_a); + dr++; dg++; db++; clip++; + sr++; sg++; sb++; + if (da) da++; + } + } + else + { + size *= -1; + for (c = 0; c < size; c++) + { + if (*clip) + RGBA_COLOR_COMBINE(ctxcanvas, dr, dg, db, da, *sr, *sg, *sb, src_a); + dr--; dg--; db--; clip--; + sr--; sg--; sb--; + if (da) da--; + } + } +} + +static void sCombineRGBALine(cdCtxCanvas* ctxcanvas, int offset, const unsigned char *sr, const unsigned char *sg, const unsigned char *sb, const unsigned char *sa, int size) +{ + int c; + unsigned char *dr = ctxcanvas->red + offset; + unsigned char *dg = ctxcanvas->green + offset; + unsigned char *db = ctxcanvas->blue + offset; + unsigned char *da = ctxcanvas->alpha? ctxcanvas->alpha + offset: NULL; + unsigned char *clip = ctxcanvas->clip + offset; + + if (size > 0) + { + for (c = 0; c < size; c++) + { + if (*clip) + RGBA_COLOR_COMBINE(ctxcanvas, dr, dg, db, da, *sr, *sg, *sb, *sa); + dr++; dg++; db++; clip++; + sr++; sg++; sb++; sa++; + if (da) da++; + } + } + else + { + size *= -1; + for (c = 0; c < size; c++) + { + if (*clip) + RGBA_COLOR_COMBINE(ctxcanvas, dr, dg, db, da, *sr, *sg, *sb, *sa); + dr--; dg--; db--; clip--; + sr--; sg--; sb--; sa--; + if (da) da--; + } + } +} + +static void irgbSolidLine(cdCanvas* canvas, int xmin, int y, int xmax) +{ + int x; + unsigned long offset = y * canvas->w; + + if (y < 0) + return; + + if (y > (canvas->h-1)) + return; + + if (xmin < 0) /* Arruma limites de acordo com o retangulo de clip */ + xmin = 0; /* so clipa em x */ + if (xmax > (canvas->w-1)) + xmax = (canvas->w-1); + + for (x = xmin; x <= xmax; x++) + sCombineRGBColor(canvas->ctxcanvas, offset + x, canvas->foreground); +} + +static void irgbPatternLine(cdCanvas* canvas, int xmin, int xmax, int y, int pw, const long *pattern) +{ + int x, i; + unsigned long offset = y * canvas->w; + + if (y < 0 || y > (canvas->h-1)) + return; + + if (xmin < 0) /* Arruma limites de acordo com o retangulo de clip */ + xmin = 0; /* so clipa em x */ + if (xmax > (canvas->w-1)) + xmax = (canvas->w-1); + + i = xmin % pw; + + for (x = xmin; x <= xmax; x++,i++) + { + if (i == pw) + i = 0; + + sCombineRGBColor(canvas->ctxcanvas, offset + x, pattern[i]); + } +} + +static void irgbStippleLine(cdCanvas* canvas, int xmin, int xmax, int y, int pw, const unsigned char *stipple) +{ + int x,i; + unsigned long offset = y * canvas->w; + + if (y < 0 || y > (canvas->h-1)) + return; + + if (xmin < 0) /* Arruma limites de acordo com o retangulo de clip */ + xmin = 0; /* so clipa em x */ + if (xmax > (canvas->w-1)) + xmax = (canvas->w-1); + + i = xmin % pw; + + for (x = xmin; x <= xmax; x++,i++) + { + if (i == pw) + i = 0; + if(stipple[i]) + sCombineRGBColor(canvas->ctxcanvas, offset + x, canvas->foreground); + else if (canvas->back_opacity == CD_OPAQUE) + sCombineRGBColor(canvas->ctxcanvas, offset + x, canvas->background); + } +} + +static void irgbHatchLine(cdCanvas* canvas, int xmin, int xmax, int y, unsigned char hatch) +{ + int x; + unsigned long offset = y * canvas->w; + unsigned char n; + + if (y < 0 || y > (canvas->h-1)) + return; + + if (xmin < 0) /* Arruma limites de acordo com o retangulo de clip */ + xmin = 0; /* so clipa em x */ + if (xmax > (canvas->w-1)) + xmax = (canvas->w-1); + + n = (unsigned char)(xmin&7); + simRotateHatchN(hatch, n); + + for (x = xmin; x <= xmax; x++) + { + if (hatch & 0x80) + sCombineRGBColor(canvas->ctxcanvas, offset + x, canvas->foreground); + else if (canvas->back_opacity == CD_OPAQUE) + sCombineRGBColor(canvas->ctxcanvas, offset + x, canvas->background); + + _cdRotateHatch(hatch); + } +} + +/********************/ +/* driver functions */ +/********************/ + +static void cdkillcanvas(cdCtxCanvas* ctxcanvas) +{ + if (!ctxcanvas->user_image) + free(ctxcanvas->red); + + if (ctxcanvas->clip_region) + free(ctxcanvas->clip_region); + + free(ctxcanvas->clip); + + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + free(ctxcanvas); +} + +unsigned char* cdAlphaImage(cdCanvas* canvas) +{ + cdCtxCanvas* ctxcanvas; + assert(canvas); + ctxcanvas = (cdCtxCanvas*)canvas->ctxcanvas; + return ctxcanvas->alpha; +} + +unsigned char* cdRedImage(cdCanvas* canvas) +{ + cdCtxCanvas* ctxcanvas; + assert(canvas); + ctxcanvas = (cdCtxCanvas*)canvas->ctxcanvas; + return ctxcanvas->red; +} + +unsigned char* cdGreenImage(cdCanvas* canvas) +{ + cdCtxCanvas* ctxcanvas; + assert(canvas); + ctxcanvas = (cdCtxCanvas*)canvas->ctxcanvas; + return ctxcanvas->green; +} + +unsigned char* cdBlueImage(cdCanvas* canvas) +{ + cdCtxCanvas* ctxcanvas; + assert(canvas); + ctxcanvas = (cdCtxCanvas*)canvas->ctxcanvas; + return ctxcanvas->blue; +} + +static void cdclear(cdCtxCanvas* ctxcanvas) +{ + int size = ctxcanvas->canvas->w * ctxcanvas->canvas->h; + memset(ctxcanvas->red, cdRed(ctxcanvas->canvas->background), size); + memset(ctxcanvas->green, cdGreen(ctxcanvas->canvas->background), size); + memset(ctxcanvas->blue, cdBlue(ctxcanvas->canvas->background), size); + if (ctxcanvas->alpha) memset(ctxcanvas->alpha, cdAlpha(ctxcanvas->canvas->background), size); +} + +static void irgPostProcessIntersect(unsigned char* clip, int size) +{ + int i; + for(i = 0; i < size; i++) + { + if (*clip == 2) + *clip = 1; + else + *clip = 0; + + clip++; + } +} + +#define _irgSetClipPixel(_clip, _combine_mode) \ +{ \ + switch (_combine_mode) \ + { \ + case CD_INTERSECT: \ + if (_clip) \ + _clip = 2; /* fills the intersection \ + with a value to be post-processed */ \ + break; \ + case CD_DIFFERENCE: \ + if (_clip) \ + _clip = 0; /* clears the intersection */ \ + break; \ + case CD_NOTINTERSECT: /* XOR */ \ + if (_clip) \ + _clip = 0; /* clears the intersection */ \ + else \ + _clip = 1; /* fills the region */ \ + break; \ + default: /* CD_UNION */ \ + _clip = 1; /* fills the region */ \ + break; \ + } \ +} + +static void irgbClipTextBitmap(FT_Bitmap* bitmap, int x, int y, int w, unsigned char* clip, int combine_mode) +{ + unsigned char *bitmap_data; + int width = bitmap->width; + int height = bitmap->rows; + int i, j; + + /* avoid spaces */ + if (width == 0 || height == 0) + return; + + bitmap_data = bitmap->buffer + (height-1)*width; /* bitmap is top down. */ + + clip += y * w + x; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + if (bitmap_data[j] == 255) + _irgSetClipPixel(clip[j], combine_mode); + } + clip += w; + bitmap_data -= width; + } +} + +static void irgbClipText(cdCtxCanvas *ctxcanvas, int x, int y, const char *s) +{ + cdCanvas* canvas = ctxcanvas->canvas; + cdSimulation* simulation = canvas->simulation; + FT_Face face; + FT_GlyphSlot slot; + FT_Matrix matrix; /* transformation matrix */ + FT_Vector pen; /* untransformed origin */ + FT_Error error; + + if (!simulation->tt_text->face) + return; + + face = simulation->tt_text->face; + slot = face->glyph; + + /* move the reference point to the baseline-left */ + simGetPenPos(simulation->canvas, x, y, s, &matrix, &pen); + + while(*s) + { + /* set transformation */ + FT_Set_Transform(face, &matrix, &pen); + + /* load glyph image into the slot (erase previous one) */ + error = FT_Load_Char(face, *(unsigned char*)s, FT_LOAD_RENDER); + if (error) {s++; continue;} /* ignore errors */ + + x = slot->bitmap_left; + y = slot->bitmap_top-slot->bitmap.rows; /* CD image reference point is at bottom-left */ + + /* now, draw to our target surface (convert position) */ + irgbClipTextBitmap(&slot->bitmap, x, y, canvas->w, ctxcanvas->clip_region, canvas->combine_mode); + + /* increment pen position */ + pen.x += slot->advance.x; + pen.y += slot->advance.y; + + s++; + } + + if (canvas->combine_mode == CD_INTERSECT) + irgPostProcessIntersect(ctxcanvas->clip_region, ctxcanvas->canvas->w * ctxcanvas->canvas->h); +} + +static void irgbClipFillLine(unsigned char* clip_line, int combine_mode, int x1, int x2, int width) +{ + int x; + if (x1 < 0) x1 = 0; + if (x2 > width-1) x2 = width-1; + for (x = x1; x <= x2; x++) + { + _irgSetClipPixel(clip_line[x], combine_mode); + } +} + +static int compare_int(const int* xx1, const int* xx2) +{ + return *xx1 - *xx2; +} + +static void irgbClipPoly(cdCtxCanvas* ctxcanvas, unsigned char* clip_region, cdPoint* poly, int n, int combine_mode) +{ + cdCanvas* canvas = ctxcanvas->canvas; + unsigned char* clip_line; + simLineSegment *seg_i; + cdPoint* t_poly = NULL; + int y_max, y_min, i, y, i1, fill_mode, num_lines, + inter_count, width, height; + + int *xx = (int*)malloc((n+1)*sizeof(int)); + simLineSegment *segment = (simLineSegment *)malloc(n*sizeof(simLineSegment)); + + if (canvas->use_matrix) + { + t_poly = malloc(sizeof(cdPoint)*n); + memcpy(t_poly, poly, sizeof(cdPoint)*n); + poly = t_poly; + + for(i = 0; i < n; i++) + cdMatrixTransformPoint(canvas->matrix, poly[i].x, poly[i].y, &poly[i].x, &poly[i].y); + } + + width = canvas->w; + height = canvas->h; + fill_mode = canvas->fill_mode; + + y_max = poly[0].y; + y_min = poly[0].y; + for(i = 0; i < n; i++) + { + i1 = (i+1)%n; /* next point(i+1), next of last(n-1) is first(0) */ + simAddSegment(segment+i, poly[i].x, poly[i].y, poly[i1].x, poly[i1].y, &y_max, &y_min); + } + + if (y_min < 0) + y_min = 0; + + if (y_max > height-1) + num_lines = height-y_min; + else + num_lines = y_max-y_min+1; + + /* for all horizontal lines between y_max and y_min */ + for(y = y_max; y >= y_min; y--) + { + inter_count = 0; + + /* for all segments, calculates the intervals to be filled. */ + for(i = 0; i < n; i++) + { + seg_i = segment + i; + + /* if the minimum Y coordinate of the segment is greater than the current y, then ignore the segment. */ + /* if it is an horizontal line, then ignore the segment. */ + if (seg_i->y1 > y || + seg_i->y1 == seg_i->y2) + continue; + + if (y == seg_i->y1) /* intersection at the start point (x1,y1) */ + { + int i_next = (i==n-1)? 0: i+1; + int i_prev = (i==0)? n-1: i-1; + simLineSegment *seg_i_next = segment + i_next; + simLineSegment *seg_i_prev = segment + i_prev; + + /* always save at least one intersection point for (y1) */ + + xx[inter_count++] = seg_i->x1; /* save the intersection point */ + + /* check for missing bottom-corner points (|_|), must duplicate the intersection */ + if ((seg_i_next->y1 == y && seg_i_next->y2 == seg_i_next->y1) || /* next is an horizontal line */ + (seg_i_prev->y1 == y && seg_i_prev->y2 == seg_i_prev->y1)) /* previous is an horizontal line */ + { + xx[inter_count++] = seg_i->x1; /* save the intersection point */ + } + } + else if ((y > seg_i->y1) && (y < seg_i->y2)) /* intersection inside the segment, do not include y2 */ + { + xx[inter_count++] = simSegmentInc(seg_i, canvas, y); /* save the intersection point */ + } + else if (y == seg_i->y2) /* intersection at the end point (x2,y2) */ + { + int i_next = (i==n-1)? 0: i+1; + int i_prev = (i==0)? n-1: i-1; + simLineSegment *seg_i_next = segment + i_next; + simLineSegment *seg_i_prev = segment + i_prev; + + /* only save the intersection point for (y2) if not handled by (y1) of another segment */ + + /* check for missing top-corner points (^) or (|¯¯|) */ + if ((seg_i_next->y2 == y && seg_i_next->y2 == seg_i_next->y1) || /* next is an horizontal line */ + (seg_i_prev->y2 == y && seg_i_prev->y2 == seg_i_prev->y1) || /* previous is an horizontal line */ + (seg_i_next->y2 == y && seg_i_next->x2 == seg_i->x2 && seg_i_next->x1 != seg_i->x1) || + (seg_i_prev->y2 == y && seg_i_prev->x2 == seg_i->x2 && seg_i_prev->x1 != seg_i->x1)) + { + xx[inter_count++] = seg_i->x2; /* save the intersection point */ + } + } + } + + /* if outside the canvas, ignore the intervals and */ + /* continue since the segments where updated. */ + if (y > height-1 || inter_count == 0) + continue; + + /* sort the intervals */ + qsort(xx, inter_count, sizeof(int), (int (*)(const void*,const void*))compare_int); + + clip_line = clip_region + y*width; + + /* for all intervals, fill the interval */ + for(i = 0; i < inter_count; i += 2) + { + if (fill_mode == CD_EVENODD) + { + /* since it fills only pairs of intervals, */ + /* it is the EVENODD fill rule. */ + irgbClipFillLine(clip_line, combine_mode, xx[i], xx[i+1], width); + } + else + { + irgbClipFillLine(clip_line, combine_mode, xx[i], xx[i+1], width); + if ((i+2 < inter_count) && (xx[i+1] < xx[i+2])) /* avoid point intervals */ + if (simIsPointInPolyWind(poly, n, (xx[i+1]+xx[i+2])/2, y)) /* if the next interval is inside the polygon then fill it */ + irgbClipFillLine(clip_line, combine_mode, xx[i+1], xx[i+2], width); + } + } + } + + if (t_poly) free(t_poly); + free(xx); + free(segment); + + if (combine_mode == CD_INTERSECT) + irgPostProcessIntersect(ctxcanvas->clip_region, ctxcanvas->canvas->w * ctxcanvas->canvas->h); +} + +static void irgbClipElipse(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int height, double angle1, double angle2, int sector) +{ + float c, s, sx, sy, x, y, prev_x, prev_y; + double da; + int i, p; + cdPoint* poly; + + /* number of segments of equivalent poligonal for a full ellipse */ + int n = simCalcEllipseNumSegments(ctxcanvas->canvas, xc, yc, width, height); + + /* number of segments for the arc */ + n = cdRound((fabs(angle2-angle1)*n)/360); + if (n < 1) n = 1; + + poly = (cdPoint*)malloc(sizeof(cdPoint)*(n+2+1)); /* n+1 points +1 center */ + + /* converts degrees into radians */ + angle1 *= CD_DEG2RAD; + angle2 *= CD_DEG2RAD; + + /* generates arc points at origin with axis x and y */ + + da = (angle2-angle1)/n; + c = (float)cos(da); + s = (float)sin(da); + sx = -(width*s)/height; + sy = (height*s)/width; + + x = xc + (width/2.0f)*(float)cos(angle1); + y = yc + (height/2.0f)*(float)sin(angle1); + poly[0].x = _cdRound(x); + poly[0].y = _cdRound(y); + prev_x = x; + prev_y = y; + p = 1; + + for (i = 1; i < n+1; i++) /* n+1 points */ + { + x = xc + c*(prev_x-xc) + sx*(prev_y-yc); + y = yc + sy*(prev_x-xc) + c*(prev_y-yc); + + poly[p].x = _cdRound(x); + poly[p].y = _cdRound(y); + + if (poly[p-1].x != poly[p].x || poly[p-1].y != poly[p].y) + p++; + + prev_x = x; + prev_y = y; + } + + if (poly[p-1].x != poly[0].x || poly[p-1].y != poly[0].y) + { + if (sector) /* cdSector */ + { + /* add center */ + poly[p].x = xc; + poly[p].y = yc; + } + else /* cdChord */ + { + /* add initial point */ + poly[p].x = poly[0].x; + poly[p].y = poly[0].y; + } + p++; + } + + irgbClipPoly(ctxcanvas, ctxcanvas->clip_region, poly, p, ctxcanvas->canvas->combine_mode); + + free(poly); +} + +static void irgbClipBox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + int combine_mode = ctxcanvas->canvas->combine_mode; + unsigned char* clip_line; + int x, y, width; + + if (ctxcanvas->canvas->use_matrix) + { + cdPoint poly[4]; + poly[0].x = xmin; poly[0].y = ymin; + poly[1].x = xmin; poly[1].y = ymax; + poly[2].x = xmax; poly[2].y = ymax; + poly[3].x = xmax; poly[3].y = ymin; + irgbClipPoly(ctxcanvas, ctxcanvas->clip_region, poly, 4, ctxcanvas->canvas->combine_mode); + return; + } + + xmin = _sNormX(ctxcanvas, xmin); + ymin = _sNormY(ctxcanvas, ymin); + xmax = _sNormX(ctxcanvas, xmax); + ymax = _sNormY(ctxcanvas, ymax); + width = ctxcanvas->canvas->w; + + for(y = ymin; y <= ymax; y++) + { + clip_line = ctxcanvas->clip_region + y*width; + for(x = xmin; x <= xmax; x++) + { + _irgSetClipPixel(clip_line[x], combine_mode); + } + } + + if (combine_mode == CD_INTERSECT) + irgPostProcessIntersect(ctxcanvas->clip_region, ctxcanvas->canvas->w * ctxcanvas->canvas->h); +} + +static void irgbClipArea(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + unsigned char* clip_line = ctxcanvas->clip; /* set directly to clip */ + int y, xsize, ysize, height, width, xrigth; + + if (ctxcanvas->canvas->use_matrix) + { + cdPoint poly[4]; + poly[0].x = xmin; poly[0].y = ymin; + poly[1].x = xmin; poly[1].y = ymax; + poly[2].x = xmax; poly[2].y = ymax; + poly[3].x = xmax; poly[3].y = ymin; + memset(ctxcanvas->clip, 0, ctxcanvas->canvas->w * ctxcanvas->canvas->h); + irgbClipPoly(ctxcanvas, ctxcanvas->clip, poly, 4, CD_UNION); + return; + } + + xmin = _sNormX(ctxcanvas, xmin); + ymin = _sNormY(ctxcanvas, ymin); + xmax = _sNormX(ctxcanvas, xmax); + ymax = _sNormY(ctxcanvas, ymax); + xsize = xmax-xmin+1; + ysize = ymax-ymin+1; + height = ctxcanvas->canvas->h; + width = ctxcanvas->canvas->w; + xrigth = width-(xmax+1); + + for(y = 0; y < ymin; y++) + { + memset(clip_line, 0, width); + clip_line += width; + } + + for(y = ymin; y <= ymax; y++) + { + if (xmin) + memset(clip_line, 0, xmin); + + memset(clip_line+xmin, 1, xsize); + + if (xrigth) + memset(clip_line+xmax+1, 0, xrigth); + + clip_line += width; + } + + for(y = ymax+1; y < height; y++) + { + memset(clip_line, 0, width); + clip_line += width; + } +} + +static int cdclip(cdCtxCanvas* ctxcanvas, int mode) +{ + switch(mode) + { + case CD_CLIPAREA: + irgbClipArea(ctxcanvas, ctxcanvas->canvas->clip_rect.xmin, + ctxcanvas->canvas->clip_rect.xmax, + ctxcanvas->canvas->clip_rect.ymin, + ctxcanvas->canvas->clip_rect.ymax); + break; + case CD_CLIPPOLYGON: + memset(ctxcanvas->clip, 0, ctxcanvas->canvas->w * ctxcanvas->canvas->h); + irgbClipPoly(ctxcanvas, ctxcanvas->clip, ctxcanvas->canvas->clip_poly, ctxcanvas->canvas->clip_poly_n, CD_UNION); + break; + case CD_CLIPREGION: + if (ctxcanvas->clip_region) + memcpy(ctxcanvas->clip, ctxcanvas->clip_region, ctxcanvas->canvas->w * ctxcanvas->canvas->h); + break; + default: + memset(ctxcanvas->clip, 1, ctxcanvas->canvas->w * ctxcanvas->canvas->h); /* CD_CLIPOFF */ + break; + } + + return mode; +} + +static void cdcliparea(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + if (ctxcanvas->canvas->clip_mode == CD_CLIPAREA) + irgbClipArea(ctxcanvas, xmin, xmax, ymin, ymax); +} + +static void cdnewregion(cdCtxCanvas* ctxcanvas) +{ + if (ctxcanvas->clip_region) + free(ctxcanvas->clip_region); + ctxcanvas->clip_region = malloc(ctxcanvas->canvas->w * ctxcanvas->canvas->h); + memset(ctxcanvas->clip_region, 0, ctxcanvas->canvas->w * ctxcanvas->canvas->h); +} + +static int cdispointinregion(cdCtxCanvas* ctxcanvas, int x, int y) +{ + if (!ctxcanvas->clip_region) + return 0; + + if (x >= 0 && y >= 0 && x < ctxcanvas->canvas->w && y < ctxcanvas->canvas->h) + { + if (ctxcanvas->clip_region[y*ctxcanvas->canvas->w + x]) + return 1; + } + + return 0; +} + +static void cdoffsetregion(cdCtxCanvas* ctxcanvas, int dx, int dy) +{ + unsigned char* clip_region = ctxcanvas->clip_region; + int x, y, X, Y, old_X, old_Y, width, height; + + if (!ctxcanvas->clip_region) + return; + + height = ctxcanvas->canvas->h; + width = ctxcanvas->canvas->w; + + for (y = 0; y < height; y++) + { + if (dy > 0) + Y = height-1 - y; + else + Y = y; + old_Y = Y - dy; + for(x = 0; x < width; x++) + { + if (dx > 0) + X = width-1 - x; + else + X = x; + old_X = X - dx; + + if (old_X >= 0 && old_Y >= 0 && old_Y < height && old_X < width) + clip_region[Y*width + X] = clip_region[old_Y*width + old_X]; + else + clip_region[Y*width + X] = 0; + } + } +} + +static void cdgetregionbox(cdCtxCanvas* ctxcanvas, int *xmin, int *xmax, int *ymin, int *ymax) +{ + unsigned char* clip_line = ctxcanvas->clip_region; + int x, y, width, height; + + if (!ctxcanvas->clip_region) + return; + + *xmin = ctxcanvas->canvas->w-1; + *xmax = 0; + *ymin = ctxcanvas->canvas->h-1; + *ymax = 0; + height = ctxcanvas->canvas->h; + width = ctxcanvas->canvas->w; + + for (y = 0; y < height; y++) + { + for(x = 0; x < width; x++) + { + if (*clip_line) + { + if (x < *xmin) + *xmin = x; + if (y < *ymin) + *ymin = y; + if (x > *xmax) + *xmax = x; + if (y > *ymax) + *ymax = y; + } + + clip_line++; + } + } +} + +static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + if (ctxcanvas->canvas->new_region) + { + irgbClipBox(ctxcanvas, xmin, xmax, ymin, ymax); + return; + } + + cdboxSIM(ctxcanvas, xmin, xmax, ymin, ymax); +} + +static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + if (ctxcanvas->canvas->new_region) + { + irgbClipElipse(ctxcanvas, xc, yc, w, h, a1, a2, 1); + return; + } + + cdsectorSIM(ctxcanvas, xc, yc, w, h, a1, a2); +} + +static void cdchord(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + if (ctxcanvas->canvas->new_region) + { + irgbClipElipse(ctxcanvas, xc, yc, w, h, a1, a2, 0); + return; + } + + cdchordSIM(ctxcanvas, xc, yc, w, h, a1, a2); +} + +static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *s) +{ + if (ctxcanvas->canvas->new_region) + { + irgbClipText(ctxcanvas, x, y, s); + return; + } + + cdtextSIM(ctxcanvas, x, y, s); +} + +static void cdpoly(cdCtxCanvas* ctxcanvas, int mode, cdPoint* poly, int n) +{ + if (ctxcanvas->canvas->new_region) + { + irgbClipPoly(ctxcanvas, ctxcanvas->clip_region, poly, n, ctxcanvas->canvas->combine_mode); + return; + } + + if (mode == CD_CLIP) + { + /* set directly to clip */ + memset(ctxcanvas->clip, 1, ctxcanvas->canvas->w * ctxcanvas->canvas->h); /* CD_CLIPOFF */ + irgbClipPoly(ctxcanvas, ctxcanvas->clip, poly, n, CD_UNION); + } + else + cdpolySIM(ctxcanvas, mode, poly, n); +} + +static void cdgetimagergb(cdCtxCanvas* ctxcanvas, unsigned char *r, unsigned char *g, unsigned char *b, int x, int y, int w, int h) +{ + int dst_offset, src_offset, l, xsize, ysize, xpos, ypos; + unsigned char *src_red, *src_green, *src_blue; + + if (x >= ctxcanvas->canvas->w || y >= ctxcanvas->canvas->h || + x + w < 0 || y + h < 0) + return; + + /* ajusta parametros de entrada */ + xpos = _sNormX(ctxcanvas, x); + ypos = _sNormY(ctxcanvas, y); + + xsize = w < (ctxcanvas->canvas->w - xpos)? w: ctxcanvas->canvas->w - xpos; + ysize = h < (ctxcanvas->canvas->h - ypos)? h: ctxcanvas->canvas->h - ypos; + + /* ajusta posicao inicial em source */ + src_offset = xpos + ypos * ctxcanvas->canvas->w; + src_red = ctxcanvas->red + src_offset; + src_green = ctxcanvas->green + src_offset; + src_blue = ctxcanvas->blue + src_offset; + + /* offset para source */ + src_offset = ctxcanvas->canvas->w; + + /* ajusta posicao inicial em destine */ + dst_offset = (xpos - x) + (ypos - y) * w; + r += dst_offset; + g += dst_offset; + b += dst_offset; + + for (l = 0; l < ysize; l++) + { + memcpy(r, src_red, xsize); + memcpy(g, src_green, xsize); + memcpy(b, src_blue, xsize); + + src_red += src_offset; + src_green += src_offset; + src_blue += src_offset; + + r += w; + g += w; + b += w; + } +} + +static void cdputimagerectrgba_matrix(cdCtxCanvas* ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, const unsigned char *a, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int t_xmin, t_xmax, t_ymin, t_ymax, + t_x, t_y, img_topdown = 0, dst_offset; + float i_x, i_y, xfactor, yfactor; + unsigned char sr, sg, sb, sa = 255; + double inv_matrix[6]; + + if (h < 0) + { + h = -h; + y -= (h - 1); /* y is at top-left, move it to bottom-left */ + img_topdown = 1; /* image pointer will start at top-left */ + } + + /* calculate the destination limits */ + cdImageRGBCalcDstLimits(ctxcanvas->canvas, x, y, w, h, &t_xmin, &t_xmax, &t_ymin, &t_ymax, NULL); + + /* Setup inverse transform */ + cdImageRGBInitInverseTransform(w, h, xmin, xmax, ymin, ymax, &xfactor, &yfactor, ctxcanvas->canvas->matrix, inv_matrix); + + /* for all pixels in the destiny area */ + for(t_y = t_ymin; t_y <= t_ymax; t_y++) + { + dst_offset = t_y * ctxcanvas->canvas->w; + + for(t_x = t_xmin; t_x <= t_xmax; t_x++) + { + cdImageRGBInverseTransform(t_x, t_y, &i_x, &i_y, xfactor, yfactor, xmin, ymin, x, y, inv_matrix); + + if (i_x > xmin && i_y > ymin && i_x < xmax+1 && i_y < ymax+1) + { + if (img_topdown) /* image is top-bottom */ + i_y = ih-1 - i_y; + + if (t_x == 350 && t_y == 383) + t_x = 350; + + sr = cdBilinearInterpolation(iw, ih, r, i_x, i_y); + sg = cdBilinearInterpolation(iw, ih, g, i_x, i_y); + sb = cdBilinearInterpolation(iw, ih, b, i_x, i_y); + if (a) sa = cdBilinearInterpolation(iw, ih, a, i_x, i_y); + + if (sr > 210 && sg > 210 && sb > 210) + sr = sr; + + sCombineRGB(ctxcanvas, t_x + dst_offset, sr, sg, sb, sa); + } + } + } +} + +static void cdputimagerectmap_matrix(cdCtxCanvas* ctxcanvas, int iw, int ih, const unsigned char *index, const long int *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int t_xmin, t_xmax, t_ymin, t_ymax, + t_x, t_y, img_topdown = 0, dst_offset; + float i_x, i_y, xfactor, yfactor; + unsigned char si; + double inv_matrix[6]; + + if (h < 0) + { + h = -h; + y -= (h - 1); /* y is at top-left, move it to bottom-left */ + img_topdown = 1; /* image pointer will start at top-left (undocumented feature) */ + } + + /* calculate the destination limits */ + cdImageRGBCalcDstLimits(ctxcanvas->canvas, x, y, w, h, &t_xmin, &t_xmax, &t_ymin, &t_ymax, NULL); + + /* Setup inverse transform */ + cdImageRGBInitInverseTransform(w, h, xmin, xmax, ymin, ymax, &xfactor, &yfactor, ctxcanvas->canvas->matrix, inv_matrix); + + /* for all pixels in the destiny area */ + for(t_y = t_ymin; t_y <= t_ymax; t_y++) + { + dst_offset = t_y * ctxcanvas->canvas->w; + + for(t_x = t_xmin; t_x <= t_xmax; t_x++) + { + cdImageRGBInverseTransform(t_x, t_y, &i_x, &i_y, xfactor, yfactor, xmin, ymin, x, y, inv_matrix); + + if (i_x > xmin && i_y > ymin && i_x < xmax+1 && i_y < ymax+1) + { + if (img_topdown) /* image is top-bottom */ + i_y = ih-1 - i_y; + + si = cdZeroOrderInterpolation(iw, ih, index, i_x, i_y); + sCombineRGBColor(ctxcanvas, t_x + dst_offset, colors[si]); + } + } + } +} + +static void cdputimagerectrgb(cdCtxCanvas* ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int l, c, xsize, ysize, xpos, ypos, src_offset, dst_offset, rh, rw, img_topdown = 0; + const unsigned char *src_red, *src_green, *src_blue; + + if (ctxcanvas->canvas->use_matrix) + { + cdputimagerectrgba_matrix(ctxcanvas, iw, ih, r, g, b, NULL, x, y, w, h, xmin, xmax, ymin, ymax); + return; + } + + if (h < 0) + { + h = -h; + y -= (h - 1); /* y is at top-left, move it to bottom-left */ + img_topdown = 1; /* image pointer will start at top-left */ + } + + /* verifica se esta dentro da area de desenho */ + if (x > (ctxcanvas->canvas->w-1) || y > (ctxcanvas->canvas->h-1) || + (x+w) < 0 || (y+h) < 0) + return; + + xpos = x < 0? 0: x; + ypos = y < 0? 0: y; + + xsize = (x+w) < (ctxcanvas->canvas->w-1)+1? (x+w) - xpos: (ctxcanvas->canvas->w-1) - xpos + 1; + ysize = (y+h) < (ctxcanvas->canvas->h-1)+1? (y+h) - ypos: (ctxcanvas->canvas->h-1) - ypos + 1; + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + + /* testa se tem que fazer zoom */ + if (rw != w || rh != h) + { + int* XTab = cdGetZoomTable(w, rw, xmin); + int* YTab = cdGetZoomTable(h, rh, ymin); + + /* ajusta posicao inicial em destine */ + dst_offset = xpos + ypos * ctxcanvas->canvas->w; + + for(l = 0; l < ysize; l++) + { + /* ajusta posicao inicial em source */ + if (img_topdown) + src_offset = YTab[(ih - 1) - (l + (ypos - y))] * iw; + else + src_offset = YTab[l + (ypos - y)] * iw; + + src_red = r + src_offset; + src_green = g + src_offset; + src_blue = b + src_offset; + + for(c = 0; c < xsize; c++) + { + src_offset = XTab[c + (xpos - x)]; + sCombineRGB(ctxcanvas, c + dst_offset, src_red[src_offset], src_green[src_offset], src_blue[src_offset], 255); + } + + dst_offset += ctxcanvas->canvas->w; + } + + free(XTab); + free(YTab); + } + else + { + /* ajusta posicao inicial em destine */ + dst_offset = xpos + ypos * ctxcanvas->canvas->w; + + /* ajusta posicao inicial em source */ + if (img_topdown) + src_offset = (xpos - x + xmin) + ((ih - 1) - (ypos - y + ymin)) * iw; + else + src_offset = (xpos - x + xmin) + (ypos - y + ymin) * iw; + + r += src_offset; + g += src_offset; + b += src_offset; + + for (l = 0; l < ysize; l++) + { + sCombineRGBLine(ctxcanvas, dst_offset, r, g, b, xsize); + + dst_offset += ctxcanvas->canvas->w; + + if (img_topdown) + { + r -= iw; + g -= iw; + b -= iw; + } + else + { + r += iw; + g += iw; + b += iw; + } + } + } +} + +static void cdputimagerectrgba(cdCtxCanvas* ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, const unsigned char *a, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int l, c, xsize, ysize, xpos, ypos, src_offset, dst_offset, rw, rh, img_topdown = 0; + const unsigned char *src_red, *src_green, *src_blue, *src_alpha; + + if (ctxcanvas->canvas->use_matrix) + { + cdputimagerectrgba_matrix(ctxcanvas, iw, ih, r, g, b, a, x, y, w, h, xmin, xmax, ymin, ymax); + return; + } + + if (h < 0) + { + h = -h; + y -= (h - 1); /* y is at top-left, move it to bottom-left */ + img_topdown = 1; /* image pointer will start at top-left */ + } + + /* verifica se esta dentro da area de desenho */ + if (x > (ctxcanvas->canvas->w-1) || y > (ctxcanvas->canvas->h-1) || + (x+w) < 0 || (y+h) < 0) + return; + + xpos = x < 0? 0: x; + ypos = y < 0? 0: y; + + xsize = (x+w) < (ctxcanvas->canvas->w-1)+1? (x+w) - xpos: (ctxcanvas->canvas->w-1) - xpos + 1; + ysize = (y+h) < (ctxcanvas->canvas->h-1)+1? (y+h) - ypos: (ctxcanvas->canvas->h-1) - ypos + 1; + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + + /* testa se tem que fazer zoom */ + if (rw != w || rh != h) + { + int* XTab = cdGetZoomTable(w, rw, xmin); + int* YTab = cdGetZoomTable(h, rh, ymin); + + /* ajusta posicao inicial em destine */ + dst_offset = xpos + ypos * ctxcanvas->canvas->w; + + for(l = 0; l < ysize; l++) + { + /* ajusta posicao inicial em source */ + if (img_topdown) + src_offset = YTab[(ih - 1) - (l + (ypos - y))] * iw; + else + src_offset = YTab[l + (ypos - y)] * iw; + + src_red = r + src_offset; + src_green = g + src_offset; + src_blue = b + src_offset; + src_alpha = a + src_offset; + + for(c = 0; c < xsize; c++) + { + src_offset = XTab[c + (xpos - x)]; + sCombineRGB(ctxcanvas, c + dst_offset, src_red[src_offset], src_green[src_offset], src_blue[src_offset], src_alpha[src_offset]); + } + + dst_offset += ctxcanvas->canvas->w; + } + + free(XTab); + free(YTab); + } + else + { + /* ajusta posicao inicial em destine */ + dst_offset = xpos + ypos * ctxcanvas->canvas->w; + + /* ajusta posicao inicial em source */ + if (img_topdown) + src_offset = (xpos - x + xmin) + ((ih - 1) - (ypos - y + ymin)) * iw; + else + src_offset = (xpos - x + xmin) + (ypos - y + ymin) * iw; + + r += src_offset; + g += src_offset; + b += src_offset; + a += src_offset; + + for (l = 0; l < ysize; l++) + { + sCombineRGBALine(ctxcanvas, dst_offset, r, g, b, a, xsize); + + dst_offset += ctxcanvas->canvas->w; + + if (img_topdown) + { + r -= iw; + g -= iw; + b -= iw; + a -= iw; + } + else + { + r += iw; + g += iw; + b += iw; + a += iw; + } + } + } +} + +static void cdputimagerectmap(cdCtxCanvas* ctxcanvas, int iw, int ih, const unsigned char *index, const long int *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int l, c, xsize, ysize, xpos, ypos, src_offset, dst_offset, rw, rh, pal_size, idx, img_topdown = 0; + const unsigned char *src_index; + + if (ctxcanvas->canvas->use_matrix) + { + cdputimagerectmap_matrix(ctxcanvas, iw, ih, index, colors, x, y, w, h, xmin, xmax, ymin, ymax); + return; + } + + if (h < 0) + { + h = -h; + y -= (h - 1); /* y is at top-left, move it to bottom-left */ + img_topdown = 1; /* image pointer will start at top-left */ + } + + /* verifica se esta dentro da area de desenho */ + if (x > (ctxcanvas->canvas->w-1) || y > (ctxcanvas->canvas->h-1) || + (x+w) < 0 || (y+h) < 0) + return; + + xpos = x < 0? 0: x; + ypos = y < 0? 0: y; + + xsize = (x+w) < (ctxcanvas->canvas->w-1)+1? (x+w) - xpos: (ctxcanvas->canvas->w-1) - xpos + 1; + ysize = (y+h) < (ctxcanvas->canvas->h-1)+1? (y+h) - ypos: (ctxcanvas->canvas->h-1) - ypos + 1; + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + + /* Como nao sabemos o tamanho da palette a priori, + teremos que ver qual o maior indice usado na imagem. */ + pal_size = 0; + + for (l=0; l<ih; l++) + { + for (c=0; c<iw; c++) + { + idx = index[l*iw + c]; + if (idx > pal_size) + pal_size = idx; + } + } + + pal_size++; + + /* testa se tem que fazer zoom */ + if (rw != w || rh != h) + { + int* XTab = cdGetZoomTable(w, rw, xmin); + int* YTab = cdGetZoomTable(h, rh, ymin); + + /* ajusta posicao inicial em destine */ + dst_offset = xpos + ypos * ctxcanvas->canvas->w; + + for(l = 0; l < ysize; l++) + { + /* ajusta posicao inicial em source */ + if (img_topdown) + src_offset = YTab[(ih - 1) - (l + (ypos - y))] * iw; + else + src_offset = YTab[l + (ypos - y)] * iw; + + src_index = index + src_offset; + + for(c = 0; c < xsize; c++) + { + src_offset = XTab[c + (xpos - x)]; + idx = src_index[src_offset]; + sCombineRGBColor(ctxcanvas, c + dst_offset, colors[idx]); + } + + dst_offset += ctxcanvas->canvas->w; + } + + free(XTab); + free(YTab); + } + else + { + /* ajusta posicao inicial em destine */ + dst_offset = xpos + ypos * ctxcanvas->canvas->w; + + /* ajusta posicao inicial em source */ + if (img_topdown) + src_offset = (xpos - x + xmin) + ((ih - 1) - (ypos - y + ymin)) * iw; + else + src_offset = (xpos - x + xmin) + (ypos - y + ymin) * iw; + + index += src_offset; + + for (l = 0; l < ysize; l++) + { + for(c = 0; c < xsize; c++) + { + idx = index[c]; + sCombineRGBColor(ctxcanvas, c + dst_offset, colors[idx]); + } + + dst_offset += ctxcanvas->canvas->w; + + if (img_topdown) + index -= iw; + else + index += iw; + } + } +} + +static void cdpixel(cdCtxCanvas* ctxcanvas, int x, int y, long int color) +{ + int offset; + + if (ctxcanvas->canvas->use_matrix) + cdMatrixTransformPoint(ctxcanvas->canvas->matrix, x, y, &x, &y); + + offset = ctxcanvas->canvas->w * y + x; + + /* verifica se esta dentro da area de desenho */ + if (x < 0 || + x > (ctxcanvas->canvas->w-1) || + y < 0 || + y > (ctxcanvas->canvas->h-1)) + return; + + sCombineRGBColor(ctxcanvas, offset, color); +} + +static cdCtxImage* cdcreateimage(cdCtxCanvas* ctxcanvas, int w, int h) +{ + cdCtxImage* ctximage; + int size = w * h; + int num_c = ctxcanvas->alpha? 4: 3; + + ctximage = (cdCtxImage*)malloc(sizeof(cdCtxImage)); + memset(ctximage, 0, sizeof(cdCtxImage)); + + ctximage->w = w; + ctximage->h = h; + + ctximage->red = (unsigned char*) malloc(num_c*size); + if (!ctximage->red) + { + free(ctximage); + return NULL; + } + + ctximage->green = ctximage->red + size; + ctximage->blue = ctximage->red + 2*size; + if (ctxcanvas->alpha) + ctximage->alpha = ctximage->red + 3*size; + + memset(ctximage->red, 0xFF, 3*size); + if (ctximage->alpha) memset(ctximage->alpha, 0, size); /* transparent */ + + return ctximage; +} + +static void cdgetimage(cdCtxCanvas* ctxcanvas, cdCtxImage* ctximage, int x, int y) +{ + unsigned char *r, *g, *b, *a = NULL; + int w, h, dst_offset, src_offset, l, xsize, ysize, xpos, ypos, do_alpha = 0; + unsigned char *src_red, *src_green, *src_blue, *src_alpha = NULL; + + w = ctximage->w; + h = ctximage->h; + + if (x >= ctxcanvas->canvas->w || y >= ctxcanvas->canvas->h || + x + w < 0 || y + h < 0) + return; + + if (ctximage->alpha && ctxcanvas->alpha) + do_alpha = 1; + + r = ctximage->red; + g = ctximage->green; + b = ctximage->blue; + if (do_alpha) a = ctximage->alpha; + + /* ajusta parametros de entrada */ + xpos = _sNormX(ctxcanvas, x); + ypos = _sNormY(ctxcanvas, y); + + xsize = w < (ctxcanvas->canvas->w - xpos)? w: ctxcanvas->canvas->w - xpos; + ysize = h < (ctxcanvas->canvas->h - ypos)? h: ctxcanvas->canvas->h - ypos; + + /* ajusta posicao inicial em source */ + src_offset = xpos + ypos * ctxcanvas->canvas->w; + src_red = ctxcanvas->red + src_offset; + src_green = ctxcanvas->green + src_offset; + src_blue = ctxcanvas->blue + src_offset; + if (do_alpha) src_alpha = ctxcanvas->alpha + src_offset; + + /* offset para source */ + src_offset = ctxcanvas->canvas->w; + + /* ajusta posicao inicial em destine */ + dst_offset = (xpos - x) + (ypos - y) * w; + r += dst_offset; + g += dst_offset; + b += dst_offset; + if (do_alpha) a += dst_offset; + + for (l = 0; l < ysize; l++) + { + memcpy(r, src_red, xsize); + memcpy(g, src_green, xsize); + memcpy(b, src_blue, xsize); + if (do_alpha) memcpy(a, src_alpha, xsize); + + src_red += src_offset; + src_green += src_offset; + src_blue += src_offset; + if (do_alpha) src_alpha += src_offset; + + r += w; + g += w; + b += w; + if (do_alpha) a += w; + } +} + +static void cdputimagerect(cdCtxCanvas* ctxcanvas, cdCtxImage* ctximage, int x, int y, int xmin, int xmax, int ymin, int ymax) +{ + int iw, ih, w, h; + unsigned char *r, *g, *b, *a; + int l, xsize, ysize, xpos, ypos, src_offset, dst_offset; + + iw = ctximage->w; + ih = ctximage->h; + + r = ctximage->red; + g = ctximage->green; + b = ctximage->blue; + a = ctximage->alpha; + + w = xmax-xmin+1; + h = ymax-ymin+1; + + /* verifica se esta dentro da area de desenho */ + if (x > (ctxcanvas->canvas->w-1) || y > (ctxcanvas->canvas->h-1) || + x + w < 0 || y + h < 0) + return; + + xpos = x; + ypos = y; + + if (ypos < 0) ypos = 0; + if (xpos < 0) xpos = 0; + + xsize = w < ((ctxcanvas->canvas->w-1)+1 - xpos)? w: ((ctxcanvas->canvas->w-1)+1 - xpos); + ysize = h < ((ctxcanvas->canvas->h-1)+1 - ypos)? h: ((ctxcanvas->canvas->h-1)+1 - ypos); + + /* ajusta posicao inicial em destine */ + dst_offset = xpos + ypos * ctxcanvas->canvas->w; + + /* ajusta posicao inicial em source */ + src_offset = ((xpos - x) + xmin) + ((ypos - y) + ymin) * iw; + r += src_offset; + g += src_offset; + b += src_offset; + if (a) a += src_offset; + + for (l = 0; l < ysize; l++) + { + if (a) + sCombineRGBALine(ctxcanvas, dst_offset, r, g, b, a, xsize); + else + sCombineRGBLine(ctxcanvas, dst_offset, r, g, b, xsize); + + dst_offset += ctxcanvas->canvas->w; + + r += iw; + g += iw; + b += iw; + if (a) a += iw; + } +} + +static void cdkillimage(cdCtxImage* ctximage) +{ + free(ctximage->red); + memset(ctximage, 0, sizeof(cdCtxImage)); + free(ctximage); +} + +static void cdscrollarea(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax, int dx, int dy) +{ + int l; + long src_offset, dst_offset; + int incx,incy, xsize, ysize; + int dst_xmin, dst_xmax, dst_ymin, dst_ymax; + + /* corrige valores de entrada */ + + xmin = _sNormX(ctxcanvas, xmin); + ymin = _sNormY(ctxcanvas, ymin); + xmax = _sNormX(ctxcanvas, xmax); + ymax = _sNormY(ctxcanvas, ymax); + + dst_xmin = xmin + dx; + dst_ymin = ymin + dy; + dst_xmax = xmax + dx; + dst_ymax = ymax + dy; + + /* verifica se esta dentro da area de desenho */ + if (dst_xmin > (ctxcanvas->canvas->w-1) || dst_ymin > (ctxcanvas->canvas->h-1) || + dst_xmax < 0 || dst_ymax < 0) + return; + + if (dst_ymin < 0) dst_ymin = 0; + if (dst_xmin < 0) dst_xmin = 0; + + if (dst_ymax > (ctxcanvas->canvas->h-1)) dst_ymax = (ctxcanvas->canvas->h-1); + if (dst_xmax > (ctxcanvas->canvas->w-1)) dst_xmax = (ctxcanvas->canvas->w-1); + + if (dst_xmin > dst_xmax || dst_ymin > dst_ymax) + return; + + /* Decide de onde vai comecar a copiar, isto e' necessario pois pode haver + uma intersecao entre a imagem original e a nova imagem, assim devo + garantir que nao estou colocando um ponto, em cima de um ponto ainda nao + lido da imagem antiga. */ + + xsize = dst_xmax - dst_xmin + 1; + ysize = dst_ymax - dst_ymin + 1; + + /* sentido de copia da direita para a esquerda ou ao contrario. */ + if (dx < 0) + { + incx = 1; + dst_offset = dst_xmin; + src_offset = xmin; + } + else + { + incx = -1; + dst_offset = dst_xmax; + src_offset = xmax; + } + + /* sentido de copia de cima para baixo ou ao contrario. */ + if (dy < 0) + { + incy = ctxcanvas->canvas->w; + dst_offset += dst_ymin * ctxcanvas->canvas->w; + src_offset += ymin * ctxcanvas->canvas->w; + } + else + { + incy = -(ctxcanvas->canvas->w); + dst_offset += dst_ymax * ctxcanvas->canvas->w; + src_offset += ymax * ctxcanvas->canvas->w; + } + + xsize *= incx; + + for (l = 0; l < ysize; l++) + { + sCombineRGBLine(ctxcanvas, dst_offset, ctxcanvas->red + src_offset, ctxcanvas->green + src_offset, ctxcanvas->blue + src_offset, xsize); + dst_offset += incy; + src_offset += incy; + } +} + +static char* get_green_attrib(cdCtxCanvas* ctxcanvas) +{ + return (char*)ctxcanvas->green; +} + +static cdAttribute green_attrib = +{ + "GREENIMAGE", + NULL, + get_green_attrib +}; + +static char* get_blue_attrib(cdCtxCanvas* ctxcanvas) +{ + return (char*)ctxcanvas->blue; +} + +static cdAttribute blue_attrib = +{ + "BLUEIMAGE", + NULL, + get_blue_attrib +}; + +static char* get_red_attrib(cdCtxCanvas* ctxcanvas) +{ + return (char*)ctxcanvas->red; +} + +static cdAttribute red_attrib = +{ + "REDIMAGE", + NULL, + get_red_attrib +}; + +static char* get_alpha_attrib(cdCtxCanvas* ctxcanvas) +{ + return (char*)ctxcanvas->alpha; +} + +static cdAttribute alpha_attrib = +{ + "ALPHAIMAGE", + NULL, + get_alpha_attrib +}; + +static void set_aa_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + if (!data || data[0] == '0') + ctxcanvas->canvas->simulation->antialias = 0; + else + ctxcanvas->canvas->simulation->antialias = 1; +} + +static char* get_aa_attrib(cdCtxCanvas* ctxcanvas) +{ + if (ctxcanvas->canvas->simulation->antialias) + return "0"; + else + return "1"; +} + +static cdAttribute aa_attrib = +{ + "ANTIALIAS", + set_aa_attrib, + get_aa_attrib +}; + +static void set_rotate_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + if (data) + { + sscanf(data, "%g %d %d", &ctxcanvas->rotate_angle, + &ctxcanvas->rotate_center_x, + &ctxcanvas->rotate_center_y); + + cdCanvasTransformTranslate(ctxcanvas->canvas, ctxcanvas->rotate_center_x, ctxcanvas->rotate_center_y); + cdCanvasTransformRotate(ctxcanvas->canvas, ctxcanvas->rotate_angle); + cdCanvasTransformTranslate(ctxcanvas->canvas, -ctxcanvas->rotate_center_x, -ctxcanvas->rotate_center_y); + } + else + { + ctxcanvas->rotate_angle = 0; + ctxcanvas->rotate_center_x = 0; + ctxcanvas->rotate_center_y = 0; + + cdCanvasTransform(ctxcanvas->canvas, NULL); + } +} + +static char* get_rotate_attrib(cdCtxCanvas* ctxcanvas) +{ + static char data[100]; + + if (!ctxcanvas->rotate_angle) + return NULL; + + sprintf(data, "%g %d %d", (double)ctxcanvas->rotate_angle, + ctxcanvas->rotate_center_x, + ctxcanvas->rotate_center_y); + + return data; +} + +static cdAttribute rotate_attrib = +{ + "ROTATE", + set_rotate_attrib, + get_rotate_attrib +}; + +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + cdCtxCanvas* ctxcanvas; + int w = 0, h = 0, use_alpha = 0; + float res = (float)3.78; + unsigned char *r = NULL, *g = NULL, *b = NULL, *a = NULL; + char* str_data = (char*)data; + char* res_ptr = NULL; + + if (strstr(str_data, "-a")) + use_alpha = 1; + + res_ptr = strstr(str_data, "-r"); + if (res_ptr) + sscanf(res_ptr+2, "%g", &res); + + /* size and rgb */ +#ifdef SunOS_OLD + if (use_alpha) + sscanf(str_data, "%dx%d %d %d %d %d", &w, &h, &r, &g, &b, &a); + else + sscanf(str_data, "%dx%d %d %d %d", &w, &h, &r, &g, &b); +#else + if (use_alpha) + sscanf(str_data, "%dx%d %p %p %p %p", &w, &h, &r, &g, &b, &a); + else + sscanf(str_data, "%dx%d %p %p %p", &w, &h, &r, &g, &b); +#endif + + if (w == 0 || h == 0) + return; + + ctxcanvas = (cdCtxCanvas *)malloc(sizeof(cdCtxCanvas)); + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + + canvas->w = w; + canvas->h = h; + canvas->yres = res; + canvas->xres = res; + canvas->w_mm = ((double)w) / res; + canvas->h_mm = ((double)h) / res; + if (use_alpha) + canvas->bpp = 32; + else + canvas->bpp = 24; + + if (r && g && b) + { + ctxcanvas->user_image = 1; + + ctxcanvas->red = r; + ctxcanvas->green = g; + ctxcanvas->blue = b; + ctxcanvas->alpha = a; + } + else + { + int size = w * h; + int num_c = use_alpha? 4: 3; + + ctxcanvas->user_image = 0; + + ctxcanvas->red = (unsigned char*)malloc(num_c*size); + if (!ctxcanvas->red) + { + free(ctxcanvas); + return; + } + + ctxcanvas->green = ctxcanvas->red + size; + ctxcanvas->blue = ctxcanvas->red + 2*size; + if (use_alpha) + ctxcanvas->alpha = ctxcanvas->red + 3*size; + + memset(ctxcanvas->red, 0xFF, 3*size); /* white */ + if (ctxcanvas->alpha) memset(ctxcanvas->alpha, 0, size); /* transparent */ + } + + ctxcanvas->clip = (unsigned char*)malloc(w*h); + memset(ctxcanvas->clip, 1, w*h); /* CD_CLIPOFF */ + + canvas->ctxcanvas = ctxcanvas; + ctxcanvas->canvas = canvas; + + cdSimInitText(canvas->simulation); + /* nao preciso inicializar a fonte, + pois isso sera' feito na inicializacao dos atributos default do driver */ + + canvas->simulation->antialias = 1; + + cdRegisterAttribute(canvas, &red_attrib); + cdRegisterAttribute(canvas, &green_attrib); + cdRegisterAttribute(canvas, &blue_attrib); + cdRegisterAttribute(canvas, &alpha_attrib); + cdRegisterAttribute(canvas, &aa_attrib); + cdRegisterAttribute(canvas, &rotate_attrib); +} + +static void cdinittable(cdCanvas* canvas) +{ + cdSimulation* sim; + + /* initialize function table*/ + canvas->cxClip = cdclip; + canvas->cxClipArea = cdcliparea; + canvas->cxNewRegion = cdnewregion; + canvas->cxIsPointInRegion = cdispointinregion; + canvas->cxOffsetRegion = cdoffsetregion; + canvas->cxGetRegionBox = cdgetregionbox; + + canvas->cxPutImageRectRGB = cdputimagerectrgb; + canvas->cxPutImageRectRGBA = cdputimagerectrgba; + canvas->cxPutImageRectMap = cdputimagerectmap; + canvas->cxGetImageRGB = cdgetimagergb; + + canvas->cxCreateImage = cdcreateimage; + canvas->cxGetImage = cdgetimage; + canvas->cxPutImageRect = cdputimagerect; + canvas->cxKillImage = cdkillimage; + canvas->cxScrollArea = cdscrollarea; + + canvas->cxClear = cdclear; + canvas->cxPixel = cdpixel; + + canvas->cxLine = cdlineSIM; + canvas->cxRect = cdrectSIM; + canvas->cxBox = cdbox; + canvas->cxArc = cdarcSIM; + canvas->cxSector = cdsector; + canvas->cxChord = cdchord; + canvas->cxPoly = cdpoly; + canvas->cxText = cdtext; + + canvas->cxKillCanvas = cdkillcanvas; + + /* use simulation */ + canvas->cxFont = cdfontSIM; + canvas->cxGetFontDim = cdgetfontdimSIM; + canvas->cxGetTextSize = cdgettextsizeSIM; + + sim = canvas->simulation; + + sim->SolidLine = irgbSolidLine; + sim->PatternLine = irgbPatternLine; + sim->StippleLine = irgbStippleLine; + sim->HatchLine = irgbHatchLine; +} + +static cdContext cdImageRGBContext = +{ + CD_CAP_ALL & ~(CD_CAP_FLUSH | CD_CAP_PLAY | CD_CAP_FPRIMTIVES | + CD_CAP_LINECAP | CD_CAP_LINEJOIN | CD_CAP_REGION | + CD_CAP_PALETTE | CD_CAP_TEXTORIENTATION), + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + +cdContext* cdContextImageRGB(void) +{ + return &cdImageRGBContext; +} + +static void cdflushDB(cdCtxCanvas *ctxcanvas) +{ + int old_writemode; + cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer; + + /* this is done in the canvas_dbuffer context */ + + /* Flush can be affected by Origin and Clipping, but not WriteMode */ + + old_writemode = cdCanvasWriteMode(canvas_dbuffer, CD_REPLACE); + cdCanvasPutImageRectRGB(canvas_dbuffer, ctxcanvas->canvas->w, ctxcanvas->canvas->h, ctxcanvas->red, ctxcanvas->green, ctxcanvas->blue, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h, 0, 0, 0, 0); + cdCanvasWriteMode(canvas_dbuffer, old_writemode); +} + +static void cdcreatecanvasDB(cdCanvas* canvas, cdCanvas* canvas_dbuffer) +{ + char rgbdata[100]; + sprintf(rgbdata, "%dx%d -r%g", canvas_dbuffer->w, canvas_dbuffer->h, canvas_dbuffer->xres); + cdcreatecanvas(canvas, rgbdata); + if (canvas->ctxcanvas) + canvas->ctxcanvas->canvas_dbuffer = canvas_dbuffer; +} + +static int cdactivateDB(cdCtxCanvas *ctxcanvas) +{ + cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer; + + /* this is done in the canvas_dbuffer context */ + /* this will update canvas size */ + cdCanvasActivate(canvas_dbuffer); + + /* check if the size changed */ + if (canvas_dbuffer->w != ctxcanvas->canvas->w || + canvas_dbuffer->h != ctxcanvas->canvas->h) + { + cdCanvas* canvas = ctxcanvas->canvas; + /* save the current, if the rebuild fail */ + cdCtxCanvas* old_ctxcanvas = ctxcanvas; + + /* if the image is rebuild, the canvas that uses the image must be also rebuild */ + + /* rebuild the image and the canvas */ + canvas->ctxcanvas = NULL; + cdcreatecanvasDB(canvas, canvas_dbuffer); + if (!canvas->ctxcanvas) + { + canvas->ctxcanvas = old_ctxcanvas; + return CD_ERROR; + } + + /* remove the old image and canvas */ + cdkillcanvas(old_ctxcanvas); + + ctxcanvas = canvas->ctxcanvas; + + /* update canvas attributes */ + if (canvas->cxBackground) canvas->cxBackground(ctxcanvas, canvas->background); + if (canvas->cxForeground) canvas->cxForeground(ctxcanvas, canvas->foreground); + if (canvas->cxBackOpacity) canvas->cxBackOpacity(ctxcanvas, canvas->back_opacity); + if (canvas->cxWriteMode) canvas->cxWriteMode(ctxcanvas, canvas->write_mode); + if (canvas->cxLineStyle) canvas->cxLineStyle(ctxcanvas, canvas->line_style); + if (canvas->cxLineWidth) canvas->cxLineWidth(ctxcanvas, canvas->line_width); + if (canvas->cxLineCap) canvas->cxLineCap(ctxcanvas, canvas->line_cap); + if (canvas->cxLineJoin) canvas->cxLineJoin(ctxcanvas, canvas->line_join); + if (canvas->cxHatch) canvas->cxHatch(ctxcanvas, canvas->hatch_style); + if (canvas->stipple && canvas->cxStipple) canvas->cxStipple(ctxcanvas, canvas->stipple_w, canvas->stipple_h, canvas->stipple); + if (canvas->pattern && canvas->cxPattern) canvas->cxPattern(ctxcanvas, canvas->pattern_w, canvas->pattern_h, canvas->pattern); + if (canvas->cxInteriorStyle) canvas->cxInteriorStyle(ctxcanvas, canvas->interior_style); + if (canvas->native_font[0] && canvas->cxNativeFont) + canvas->cxNativeFont(ctxcanvas, canvas->native_font); + else if (canvas->cxFont) canvas->cxFont(ctxcanvas, canvas->font_type_face, canvas->font_style, canvas->font_size); + if (canvas->cxTextAlignment) canvas->cxTextAlignment(ctxcanvas, canvas->text_alignment); + if (canvas->cxTextOrientation) canvas->cxTextOrientation(ctxcanvas, canvas->text_orientation); + if (canvas->use_matrix && canvas->cxTransform) canvas->cxTransform(ctxcanvas, canvas->matrix); + if (canvas->clip_mode == CD_CLIPAREA && canvas->cxClipArea) canvas->cxClipArea(ctxcanvas, canvas->clip_rect.xmin, canvas->clip_rect.xmax, canvas->clip_rect.ymin, canvas->clip_rect.ymax); + if (canvas->clip_mode == CD_CLIPAREA && canvas->cxFClipArea) canvas->cxFClipArea(ctxcanvas, canvas->clip_frect.xmin, canvas->clip_frect.xmax, canvas->clip_frect.ymin, canvas->clip_frect.ymax); + if (canvas->clip_mode == CD_CLIPPOLYGON && canvas->clip_poly) canvas->cxPoly(ctxcanvas, CD_CLIP, canvas->clip_poly, canvas->clip_poly_n); + if (canvas->clip_mode == CD_CLIPPOLYGON && canvas->clip_fpoly) canvas->cxFPoly(ctxcanvas, CD_CLIP, canvas->clip_fpoly, canvas->clip_poly_n); + if (canvas->clip_mode != CD_CLIPOFF && canvas->cxClip) canvas->cxClip(ctxcanvas, canvas->clip_mode); + } + + return CD_OK; +} + +static void cddeactivateDB(cdCtxCanvas *ctxcanvas) +{ + cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer; + /* this is done in the canvas_dbuffer context */ + cdCanvasDeactivate(canvas_dbuffer); +} + +static void cdinittableDB(cdCanvas* canvas) +{ + cdinittable(canvas); + + canvas->cxActivate = cdactivateDB; + canvas->cxDeactivate = cddeactivateDB; + + canvas->cxFlush = cdflushDB; +} + +static cdContext cdDBufferRGBContext = +{ + CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_FPRIMTIVES | + CD_CAP_LINECAP | CD_CAP_LINEJOIN | CD_CAP_REGION | + CD_CAP_PALETTE | CD_CAP_TEXTORIENTATION), + 0, + cdcreatecanvasDB, + cdinittableDB, + NULL, + NULL, +}; + +cdContext* cdContextDBufferRGB(void) +{ + return &cdDBufferRGBContext; +} diff --git a/src/drv/cdmf.c b/src/drv/cdmf.c new file mode 100644 index 0000000..6c2e711 --- /dev/null +++ b/src/drv/cdmf.c @@ -0,0 +1,1188 @@ +/** \file + * \brief CD Metafile driver + * + * See Copyright Notice in cd.h + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +#include "cd.h" +#include "wd.h" +#include "cd_private.h" +#include "cdmf.h" +#include "cdmf_private.h" + + +/* codes for the primitives and attributes in the metafile + Can NOT be changed, only added for backward compatibility. +*/ +enum +{ + CDMF_FLUSH, /* 0 */ + CDMF_CLEAR, /* 1 */ + CDMF_CLIP, /* 2 */ + CDMF_CLIPAREA, /* 3 */ + CDMF_LINE, /* 4 */ + CDMF_BOX, /* 5 */ + CDMF_ARC, /* 6 */ + CDMF_SECTOR, /* 7 */ + CDMF_TEXT, /* 8 */ + CDMF_BEGIN, /* 9 */ + CDMF_VERTEX, /* 10 */ + CDMF_END, /* 11 */ + CDMF_MARK, /* 12 */ + CDMF_BACKOPACITY, /* 13 */ + CDMF_WRITEMODE, /* 14 */ + CDMF_LINESTYLE, /* 15 */ + CDMF_LINEWIDTH, /* 16 */ + CDMF_INTERIORSTYLE, /* 17 */ + CDMF_HATCH, /* 18 */ + CDMF_STIPPLE, /* 19 */ + CDMF_PATTERN, /* 20 */ + CDMF_OLDFONT, /* 21 */ + CDMF_NATIVEFONT, /* 22 */ + CDMF_TEXTALIGNMENT, /* 23 */ + CDMF_MARKTYPE, /* 24 */ + CDMF_MARKSIZE, /* 25 */ + CDMF_PALETTE, /* 26 */ + CDMF_BACKGROUND, /* 27 */ + CDMF_FOREGROUND, /* 28 */ + CDMF_PUTIMAGERGB, /* 29 */ + CDMF_PUTIMAGEMAP, /* 30 */ + CDMF_PIXEL, /* 31 */ + CDMF_SCROLLAREA, /* 32 */ + CDMF_TEXTORIENTATION, /* 33 */ + CDMF_RECT, /* 34 */ + CDMF_PUTIMAGERGBA, /* 35 */ + CDMF_WLINE, /* 36 */ + CDMF_WRECT, /* 37 */ + CDMF_WBOX, /* 38 */ + CDMF_WARC, /* 39 */ + CDMF_WSECTOR, /* 40 */ + CDMF_WTEXT, /* 41 */ + CDMF_WVERTEX, /* 42 */ + CDMF_WMARK, /* 43 */ + CDMF_VECTORTEXT, /* 44 */ + CDMF_MULTILINEVECTORTEXT, /* 45 */ + CDMF_WVECTORTEXT, /* 46 */ + CDMF_WMULTILINEVECTORTEXT, /* 47 */ + CDMF_WINDOW, /* 48 */ + CDMF_WCLIPAREA, /* 49 */ + CDMF_VECTORFONT, /* 50 */ + CDMF_VECTORTEXTDIRECTION, /* 51 */ + CDMF_VECTORTEXTTRANSFORM, /* 52 */ + CDMF_VECTORTEXTSIZE, /* 53 */ + CDMF_VECTORCHARSIZE, /* 54 */ + CDMF_WVECTORTEXTDIRECTION, /* 55 */ + CDMF_WVECTORTEXTSIZE, /* 56 */ + CDMF_WVECTORCHARSIZE, /* 57 */ + CDMF_FILLMODE, /* 58 */ + CDMF_LINESTYLEDASHES, /* 59 */ + CDMF_LINECAP, /* 60 */ + CDMF_LINEJOIN, /* 61 */ + CDMF_CHORD, /* 62 */ + CDMF_WCHORD, /* 63 */ + CDMF_FLINE, /* 64 */ + CDMF_FRECT, /* 65 */ + CDMF_FBOX, /* 66 */ + CDMF_FARC, /* 67 */ + CDMF_FSECTOR, /* 68 */ + CDMF_FTEXT, /* 69 */ + CDMF_FVERTEX, /* 70 */ + CDMF_MATRIX, /* 71 */ + CDMF_FCHORD, /* 72 */ + CDMF_FCLIPAREA, /* 73 */ + CDMF_FONT, /* 74 */ + CDMF_RESETMATRIX /* 75 */ +}; + +struct _cdCtxCanvas +{ + /* public */ + cdCanvas* canvas; + char* filename; + void* data; /* used by other drivers */ + + /* private */ + int last_line_style; + int last_fill_mode; + FILE* file; +}; + +void cdkillcanvasMF(cdCanvasMF *mfcanvas) +{ + cdCtxCanvas *ctxcanvas = (cdCtxCanvas*)mfcanvas; + free(ctxcanvas->filename); + fclose(ctxcanvas->file); + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + free(ctxcanvas); +} + +static void cdflush(cdCtxCanvas *ctxcanvas) +{ + fflush(ctxcanvas->file); + fprintf(ctxcanvas->file, "%d\n", CDMF_FLUSH); +} + +static void cdclear(cdCtxCanvas *ctxcanvas) +{ + fprintf(ctxcanvas->file, "%d\n", CDMF_CLEAR); +} + +static int cdclip(cdCtxCanvas *ctxcanvas, int mode) +{ + fprintf(ctxcanvas->file, "%d %d\n", CDMF_CLIP, mode); + return mode; +} + +static void cdcliparea(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + fprintf(ctxcanvas->file, "%d %d %d %d %d\n", CDMF_CLIPAREA, xmin, xmax, ymin, ymax); +} + +static void cdfcliparea(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + fprintf(ctxcanvas->file, "%d %g %g %g %g\n", CDMF_FCLIPAREA, xmin, xmax, ymin, ymax); +} + +static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix) +{ + if (matrix) + fprintf(ctxcanvas->file, "%d %g %g %g %g %g %g\n", CDMF_MATRIX, matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]); + else + fprintf(ctxcanvas->file, "%d\n", CDMF_RESETMATRIX); +} + +static void cdline(cdCtxCanvas *ctxcanvas, int x1, int y1, int x2, int y2) +{ + fprintf(ctxcanvas->file, "%d %d %d %d %d\n", CDMF_LINE, x1, y1, x2, y2); +} + +static void cdfline(cdCtxCanvas *ctxcanvas, double x1, double y1, double x2, double y2) +{ + fprintf(ctxcanvas->file, "%d %g %g %g %g\n", CDMF_FLINE, x1, y1, x2, y2); +} + +static void cdrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + fprintf(ctxcanvas->file, "%d %d %d %d %d\n", CDMF_RECT, xmin, xmax, ymin, ymax); +} + +static void cdfrect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + fprintf(ctxcanvas->file, "%d %g %g %g %g\n", CDMF_FRECT, xmin, xmax, ymin, ymax); +} + +static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + fprintf(ctxcanvas->file, "%d %d %d %d %d\n", CDMF_BOX, xmin, xmax, ymin, ymax); +} + +static void cdfbox(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + fprintf(ctxcanvas->file, "%d %g %g %g %g\n", CDMF_FBOX, xmin, xmax, ymin, ymax); +} + +static void cdarc(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + fprintf(ctxcanvas->file, "%d %d %d %d %d %g %g\n", CDMF_ARC, xc, yc, w, h, a1, a2); +} + +static void cdfarc(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + fprintf(ctxcanvas->file, "%d %g %g %g %g %g %g\n", CDMF_FARC, xc, yc, w, h, a1, a2); +} + +static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + fprintf(ctxcanvas->file, "%d %d %d %d %d %g %g\n", CDMF_SECTOR, xc, yc, w, h, a1, a2); +} + +static void cdfsector(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + fprintf(ctxcanvas->file, "%d %g %g %g %g %g %g\n", CDMF_FSECTOR, xc, yc, w, h, a1, a2); +} + +static void cdchord(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + fprintf(ctxcanvas->file, "%d %d %d %d %d %g %g\n", CDMF_CHORD, xc, yc, w, h, a1, a2); +} + +static void cdfchord(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + fprintf(ctxcanvas->file, "%d %g %g %g %g %g %g\n", CDMF_FCHORD, xc, yc, w, h, a1, a2); +} + +static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *text) +{ + fprintf(ctxcanvas->file, "%d %d %d %s\n", CDMF_TEXT, x, y, text); +} + +static void cdftext(cdCtxCanvas *ctxcanvas, double x, double y, const char *text) +{ + fprintf(ctxcanvas->file, "%d %g %g %s\n", CDMF_FTEXT, x, y, text); +} + +static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n) +{ + int i; + + if (mode == CD_FILL && ctxcanvas->canvas->fill_mode != ctxcanvas->last_fill_mode) + { + fprintf(ctxcanvas->file, "%d %d\n", CDMF_FILLMODE, ctxcanvas->canvas->fill_mode); + ctxcanvas->last_fill_mode = ctxcanvas->canvas->fill_mode; + } + + fprintf(ctxcanvas->file, "%d %d\n", CDMF_BEGIN, mode); + + for(i = 0; i<n; i++) + fprintf(ctxcanvas->file, "%d %d %d\n", CDMF_VERTEX, poly[i].x, poly[i].y); + + fprintf(ctxcanvas->file, "%d\n", CDMF_END); +} + +static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n) +{ + int i; + + if (mode == CD_FILL && ctxcanvas->canvas->fill_mode != ctxcanvas->last_fill_mode) + { + fprintf(ctxcanvas->file, "%d %d\n", CDMF_FILLMODE, ctxcanvas->canvas->fill_mode); + ctxcanvas->last_fill_mode = ctxcanvas->canvas->fill_mode; + } + + fprintf(ctxcanvas->file, "%d %d\n", CDMF_BEGIN, mode); + + for(i = 0; i<n; i++) + fprintf(ctxcanvas->file, "%d %g %g\n", CDMF_FVERTEX, poly[i].x, poly[i].y); + + fprintf(ctxcanvas->file, "%d\n", CDMF_END); +} + +static int cdbackopacity(cdCtxCanvas *ctxcanvas, int opacity) +{ + fprintf(ctxcanvas->file, "%d %d\n", CDMF_BACKOPACITY, opacity); + return opacity; +} + +static int cdwritemode(cdCtxCanvas *ctxcanvas, int mode) +{ + fprintf(ctxcanvas->file, "%d %d\n", CDMF_WRITEMODE, mode); + return mode; +} + +static int cdlinestyle(cdCtxCanvas *ctxcanvas, int style) +{ + if (style == CD_CUSTOM && ctxcanvas->canvas->line_style != ctxcanvas->last_line_style) + { + int i; + fprintf(ctxcanvas->file, "%d %d", CDMF_LINESTYLEDASHES, ctxcanvas->canvas->line_dashes_count); + for (i = 0; i < ctxcanvas->canvas->line_dashes_count; i++) + fprintf(ctxcanvas->file, " %d", ctxcanvas->canvas->line_dashes[i]); + fprintf(ctxcanvas->file, "\n"); + ctxcanvas->last_line_style = ctxcanvas->canvas->line_style; + } + + fprintf(ctxcanvas->file, "%d %d\n", CDMF_LINESTYLE, style); + return style; +} + +static int cdlinewidth(cdCtxCanvas *ctxcanvas, int width) +{ + fprintf(ctxcanvas->file, "%d %d\n", CDMF_LINEWIDTH, width); + return width; +} + +static int cdlinecap(cdCtxCanvas *ctxcanvas, int cap) +{ + fprintf(ctxcanvas->file, "%d %d\n", CDMF_LINECAP, cap); + return cap; +} + +static int cdlinejoin(cdCtxCanvas *ctxcanvas, int join) +{ + fprintf(ctxcanvas->file, "%d %d\n", CDMF_LINEJOIN, join); + return join; +} + +static int cdinteriorstyle(cdCtxCanvas *ctxcanvas, int style) +{ + fprintf(ctxcanvas->file, "%d %d\n", CDMF_INTERIORSTYLE, style); + return style; +} + +static int cdhatch(cdCtxCanvas *ctxcanvas, int style) +{ + fprintf(ctxcanvas->file, "%d %d\n", CDMF_HATCH, style); + return style; +} + +static void cdstipple(cdCtxCanvas *ctxcanvas, int w, int h, const unsigned char *stipple) +{ + int c, t; + + fprintf(ctxcanvas->file, "%d %d %d\n", CDMF_STIPPLE, w, h); + + t = w * h; + + for (c = 0; c < t; c++) + { + fprintf(ctxcanvas->file, "%d ", (int)*stipple++); + if ((c + 1) % w == 0) + fprintf(ctxcanvas->file, "\n"); + } +} + +static void cdpattern(cdCtxCanvas *ctxcanvas, int w, int h, const long int *pattern) +{ + int c, t; + unsigned char r, g, b; + + fprintf(ctxcanvas->file, "%d %d %d\n", CDMF_PATTERN, w, h); + + t = w * h; + + /* stores the pattern with separeted RGB values */ + for (c = 0; c < t; c++) + { + cdDecodeColor(*pattern++, &r, &g, &b); + fprintf(ctxcanvas->file, "%d %d %d ", (int)r, (int)g, (int)b); + if (c % w == 0) + fprintf(ctxcanvas->file, "\n"); + } +} + +static int cdfont(cdCtxCanvas *ctxcanvas, const char* type_face, int style, int size) +{ + fprintf(ctxcanvas->file, "%d %d %d %s\n", CDMF_FONT, style, size, type_face); + return 1; +} + +static int cdnativefont(cdCtxCanvas *ctxcanvas, const char* font) +{ + fprintf(ctxcanvas->file, "%d %s\n", CDMF_NATIVEFONT, font); + return 1; +} + +static int cdtextalignment(cdCtxCanvas *ctxcanvas, int alignment) +{ + fprintf(ctxcanvas->file, "%d %d\n", CDMF_TEXTALIGNMENT, alignment); + return alignment; +} + +static double cdtextorientation(cdCtxCanvas *ctxcanvas, double angle) +{ + fprintf(ctxcanvas->file, "%d %g\n", CDMF_TEXTORIENTATION, angle); + return angle; +} + +static void cdpalette(cdCtxCanvas *ctxcanvas, int n, const long int *palette, int mode) +{ + int c; + unsigned char r, g, b; + + fprintf(ctxcanvas->file, "%d %d %d\n", CDMF_PALETTE, n, mode); + + for (c = 0; c < n; c++) + { + cdDecodeColor(*palette++, &r, &g, &b); + fprintf(ctxcanvas->file, "%d %d %d\n", (int)r, (int)g, (int)b); + } +} + +static long cdbackground(cdCtxCanvas *ctxcanvas, long int color) +{ + unsigned char r, g, b; + cdDecodeColor(color, &r, &g, &b); + fprintf(ctxcanvas->file, "%d %d %d %d\n", CDMF_BACKGROUND, (int)r, (int)g, (int)b); + return color; +} + +static long cdforeground(cdCtxCanvas *ctxcanvas, long int color) +{ + unsigned char r, g, b; + cdDecodeColor(color, &r, &g, &b); + fprintf(ctxcanvas->file, "%d %d %d %d\n", CDMF_FOREGROUND, (int)r, (int)g, (int)b); + return color; +} + +static void cdputimagerectrgb(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int c, l, offset; + + fprintf(ctxcanvas->file, "%d %d %d %d %d %d %d\n", CDMF_PUTIMAGERGB, iw, ih, x, y, w, h); + + offset = ymin*iw + xmin; + r += offset; + g += offset; + b += offset; + + offset = iw - (xmax-xmin+1); + + for (l = ymin; l <= ymax; l++) + { + for (c = xmin; c <= xmax; c++) + { + fprintf(ctxcanvas->file, "%d %d %d ", (int)*r++, (int)*g++, (int)*b++); + } + + r += offset; + g += offset; + b += offset; + + fprintf(ctxcanvas->file, "\n"); + } +} + +static void cdputimagerectrgba(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, const unsigned char *a, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int c, l, offset; + + fprintf(ctxcanvas->file, "%d %d %d %d %d %d %d\n", CDMF_PUTIMAGERGBA, iw, ih, x, y, w, h); + + offset = ymin*iw + xmin; + r += offset; + g += offset; + b += offset; + a += offset; + + offset = iw - (xmax-xmin+1); + + for (l = ymin; l <= ymax; l++) + { + for (c = xmin; c <= xmax; c++) + { + fprintf(ctxcanvas->file, "%d %d %d %d ", (int)*r++, (int)*g++, (int)*b++, (int)*a++); + } + + r += offset; + g += offset; + b += offset; + a += offset; + + fprintf(ctxcanvas->file, "\n"); + } +} + +static void cdputimagerectmap(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *index, const long int *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int c, l, n = 0, offset; + unsigned char r, g, b; + + fprintf(ctxcanvas->file, "%d %d %d %d %d %d %d\n", CDMF_PUTIMAGEMAP, iw, ih, x, y, w, h); + + index += ymin*iw + xmin; + offset = iw - (xmax-xmin+1); + + for (l = ymin; l <= ymax; l++) + { + for (c = xmin; c <= xmax; c++) + { + if (*index > n) + n = *index; + + fprintf(ctxcanvas->file, "%d ", (int)*index++); + } + + index += offset; + + fprintf(ctxcanvas->file, "\n"); + } + + n++; + + for (c = 0; c < n; c++) + { + cdDecodeColor(*colors++, &r, &g, &b); + fprintf(ctxcanvas->file, "%d %d %d\n", (int)r, (int)g, (int)b); + } +} + +static void cdpixel(cdCtxCanvas *ctxcanvas, int x, int y, long int color) +{ + unsigned char r, g, b; + cdDecodeColor(color, &r, &g, &b); + fprintf(ctxcanvas->file, "%d %d %d %d %d %d\n", CDMF_PIXEL, x, y, (int)r, (int)g, (int)b); +} + +static void cdscrollarea(cdCtxCanvas *ctxcanvas, int xmin,int xmax, int ymin,int ymax, int dx,int dy) +{ + fprintf(ctxcanvas->file, "%d %d %d %d %d %d %d\n", CDMF_SCROLLAREA, xmin, xmax, ymin, ymax, dx, dy); +} + + +/**********/ +/* cdPlay */ +/**********/ + + +static double factorX = 1; +static double factorY = 1; +static int offsetX = 0; +static int offsetY = 0; +static double factorS = 1; + +static int sScaleX(int x) +{ + return cdRound(x * factorX + offsetX); +} + +static int sScaleY(int y) +{ + return cdRound(y * factorY + offsetY); +} + +static double sfScaleX(double x) +{ + return x * factorX + offsetX; +} + +static double sfScaleY(double y) +{ + return y * factorY + offsetY; +} + +static int sScaleW(int w) +{ + w = (int)(w * factorX + 0.5); /* always positive */ + return w == 0? 1: w; +} + +static double sfScaleH(double h) +{ + h = h * factorY; + return h == 0? 1: h; +} + +static double sfScaleW(double w) +{ + w = w * factorX; /* always positive */ + return w == 0? 1: w; +} + +static int sScaleH(int h) +{ + h = (int)(h * factorY + 0.5); + return h == 0? 1: h; +} + +static int sScaleS(int s) +{ + s = (int)(s * factorS + 0.5); + return s == 0? 1: s; +} + +typedef int(*_cdsizecb)(cdCanvas* canvas, int w, int h, double w_mm, double h_mm); +static _cdsizecb cdsizecb = NULL; + +static int cdregistercallback(int cb, cdCallback func) +{ + switch (cb) + { + case CD_SIZECB: + cdsizecb = (_cdsizecb)func; + return CD_OK; + } + + return CD_ERROR; +} + +static int cdplay(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax, void *data) +{ + char* filename = (char*)data; + FILE* file; + char TextBuffer[512]; + int iparam1, iparam2, iparam3, iparam4, iparam5, iparam6, iparam7, iparam8, iparam9, iparam10; + int c, t, n, w, h, func; + double dparam1, dparam2, dparam3, dparam4, dparam5, dparam6; + unsigned char* stipple, * _stipple, *red, *green, *blue, *_red, *_green, *_blue, *index, *_index, *_alpha, *alpha; + long int *pattern, *palette, *_pattern, *_palette, *colors, *_colors; + int* dashes; + double matrix[6]; + const char * font_family[] = + { + "System", /* CD_SYSTEM */ + "Courier", /* CD_COURIER */ + "Times", /* CD_TIMES_ROMAN */ + "Helvetica" /* CD_HELVETICA */ + }; + + file = fopen(filename, "r"); + if (!file) + return CD_ERROR; + + func = -1; + w = 0; + h = 0; + + factorX = 1; + factorY = 1; + offsetX = 0; + offsetY = 0; + factorS = 1; + + fscanf(file, "%s %d %d", TextBuffer, &w, &h); + + if (strcmp(TextBuffer, "CDMF") != 0) + { + fclose(file); + return CD_ERROR; + } + + if (w>1 && h>1 && xmax!=0 && ymax!=0) + { + offsetX = xmin; + offsetY = ymin; + factorX = ((double)(xmax-xmin)) / (w-1); + factorY = ((double)(ymax-ymin)) / (h-1); + + if (factorX < factorY) + factorS = factorX; + else + factorS = factorY; + } + + if (cdsizecb) + { + int err; + err = cdsizecb(canvas, w, h, w, h); + if (err) + return CD_ERROR; + } + + while (!feof(file)) + { + fscanf(file, "%d", &func); + if (feof(file)) + break; + + switch (func) + { + case CDMF_FLUSH: + cdCanvasFlush(canvas); + break; + case CDMF_CLEAR: + cdCanvasClear(canvas); + break; + case CDMF_CLIP: + fscanf(file, "%d", &iparam1); + cdCanvasClip(canvas, iparam1); + break; + case CDMF_CLIPAREA: + fscanf(file, "%d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4); + cdCanvasClipArea(canvas, sScaleX(iparam1), sScaleX(iparam2), sScaleY(iparam3), sScaleY(iparam4)); + break; + case CDMF_FCLIPAREA: + fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4); + cdfCanvasClipArea(canvas, sfScaleX(dparam1), sfScaleX(dparam2), sfScaleY(dparam3), sfScaleY(dparam4)); + break; + case CDMF_MATRIX: + fscanf(file, "%lg %lg %lg %lg %lg %lg", &matrix[0], &matrix[1], &matrix[2], &matrix[3], &matrix[4], &matrix[5]); + cdCanvasTransform(canvas, matrix); + break; + case CDMF_RESETMATRIX: + cdCanvasTransform(canvas, NULL); + break; + case CDMF_WCLIPAREA: + fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4); + wdCanvasClipArea(canvas, dparam1, dparam2, dparam3, dparam4); + break; + case CDMF_LINE: + fscanf(file, "%d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4); + cdCanvasLine(canvas, sScaleX(iparam1), sScaleY(iparam2), sScaleX(iparam3), sScaleY(iparam4)); + break; + case CDMF_FLINE: + fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4); + cdfCanvasLine(canvas, sfScaleX(dparam1), sfScaleY(dparam2), sfScaleX(dparam3), sfScaleY(dparam4)); + break; + case CDMF_WLINE: + fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4); + wdCanvasLine(canvas, dparam1, dparam2, dparam3, dparam4); + break; + case CDMF_RECT: + fscanf(file, "%d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4); + cdCanvasRect(canvas, sScaleX(iparam1), sScaleX(iparam2), sScaleY(iparam3), sScaleY(iparam4)); + break; + case CDMF_FRECT: + fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4); + cdfCanvasRect(canvas, sfScaleX(dparam1), sfScaleX(dparam2), sfScaleY(dparam3), sfScaleY(dparam4)); + break; + case CDMF_WRECT: + fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4); + wdCanvasRect(canvas, dparam1, dparam2, dparam3, dparam4); + break; + case CDMF_BOX: + fscanf(file, "%d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4); + cdCanvasBox(canvas, sScaleX(iparam1), sScaleX(iparam2), sScaleY(iparam3), sScaleY(iparam4)); + break; + case CDMF_WBOX: + fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4); + wdCanvasBox(canvas, dparam1, dparam2, dparam3, dparam4); + break; + case CDMF_FBOX: + fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4); + cdfCanvasBox(canvas, sfScaleX(dparam1), sfScaleX(dparam2), sfScaleY(dparam3), sfScaleY(dparam4)); + break; + case CDMF_ARC: + fscanf(file, "%d %d %d %d %lg %lg", &iparam1, &iparam2, &iparam3, &iparam4, &dparam1, &dparam2); + cdCanvasArc(canvas, sScaleX(iparam1), sScaleY(iparam2), sScaleW(iparam3), sScaleH(iparam4), dparam1, dparam2); + break; + case CDMF_FARC: + fscanf(file, "%lg %lg %lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4, &dparam5, &dparam6); + cdfCanvasArc(canvas, sfScaleX(dparam1), sfScaleY(dparam2), sfScaleW(dparam3), sfScaleH(dparam4), dparam5, dparam6); + break; + case CDMF_WARC: + fscanf(file, "%lg %lg %lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4, &dparam5, &dparam6); + wdCanvasArc(canvas, dparam1, dparam2, dparam3, dparam4, dparam5, dparam6); + break; + case CDMF_SECTOR: + fscanf(file, "%d %d %d %d %lg %lg", &iparam1, &iparam2, &iparam3, &iparam4, &dparam1, &dparam2); + cdCanvasSector(canvas, sScaleX(iparam1), sScaleY(iparam2), sScaleW(iparam3), sScaleH(iparam4), dparam1, dparam2); + break; + case CDMF_FSECTOR: + fscanf(file, "%lg %lg %lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4, &dparam5, &dparam6); + cdfCanvasSector(canvas, sfScaleX(dparam1), sfScaleY(dparam2), sfScaleW(dparam3), sfScaleH(dparam4), dparam5, dparam6); + break; + case CDMF_WSECTOR: + fscanf(file, "%lg %lg %lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4, &dparam5, &dparam6); + wdCanvasSector(canvas, dparam1, dparam2, dparam3, dparam4, dparam5, dparam6); + break; + case CDMF_CHORD: + fscanf(file, "%d %d %d %d %lg %lg", &iparam1, &iparam2, &iparam3, &iparam4, &dparam1, &dparam2); + cdCanvasChord(canvas, sScaleX(iparam1), sScaleY(iparam2), sScaleW(iparam3), sScaleH(iparam4), dparam1, dparam2); + break; + case CDMF_FCHORD: + fscanf(file, "%lg %lg %lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4, &dparam5, &dparam6); + cdfCanvasChord(canvas, sfScaleX(dparam1), sfScaleY(dparam2), sfScaleW(dparam3), sfScaleH(dparam4), dparam5, dparam6); + break; + case CDMF_WCHORD: + fscanf(file, "%lg %lg %lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4, &dparam5, &dparam6); + wdCanvasChord(canvas, dparam1, dparam2, dparam3, dparam4, dparam5, dparam6); + break; + case CDMF_TEXT: + fscanf(file, "%d %d %[^\n]", &iparam1, &iparam2, TextBuffer); + cdCanvasText(canvas, sScaleX(iparam1), sScaleY(iparam2), TextBuffer); + break; + case CDMF_FTEXT: + fscanf(file, "%lg %lg %[^\n]", &dparam1, &dparam2, TextBuffer); + cdfCanvasText(canvas, sfScaleX(dparam1), sfScaleY(dparam2), TextBuffer); + break; + case CDMF_WTEXT: + fscanf(file, "%lg %lg %[^\n]", &dparam1, &dparam2, TextBuffer); + wdCanvasText(canvas, dparam1, dparam2, TextBuffer); + break; + case CDMF_BEGIN: + fscanf(file, "%d", &iparam1); + cdCanvasBegin(canvas, iparam1); + break; + case CDMF_VERTEX: + fscanf(file, "%d %d", &iparam1, &iparam2); + cdCanvasVertex(canvas, sScaleX(iparam1), sScaleY(iparam2)); + break; + case CDMF_FVERTEX: + fscanf(file, "%lg %lg", &dparam1, &dparam2); + cdfCanvasVertex(canvas, sfScaleX(dparam1), sfScaleY(dparam2)); + break; + case CDMF_WVERTEX: + fscanf(file, "%lg %lg", &dparam1, &dparam2); + wdCanvasVertex(canvas, dparam1, dparam2); + break; + case CDMF_END: + cdCanvasEnd(canvas); + break; + case CDMF_MARK: + fscanf(file, "%d %d", &iparam1, &iparam2); + cdCanvasMark(canvas, sScaleX(iparam1), sScaleY(iparam2)); + break; + case CDMF_WMARK: + fscanf(file, "%lg %lg", &dparam1, &dparam2); + wdCanvasMark(canvas, dparam1, dparam2); + break; + case CDMF_BACKOPACITY: + fscanf(file, "%d", &iparam1); + cdCanvasBackOpacity(canvas, iparam1); + break; + case CDMF_WRITEMODE: + fscanf(file, "%d", &iparam1); + cdCanvasWriteMode(canvas, iparam1); + break; + case CDMF_LINESTYLE: + fscanf(file, "%d", &iparam1); + cdCanvasLineStyle(canvas, iparam1); + break; + case CDMF_LINEWIDTH: + fscanf(file, "%d", &iparam1); + cdCanvasLineWidth(canvas, sScaleS(iparam1)); + break; + case CDMF_LINECAP: + fscanf(file, "%d", &iparam1); + cdCanvasLineCap(canvas, iparam1); + break; + case CDMF_LINEJOIN: + fscanf(file, "%d", &iparam1); + cdCanvasLineJoin(canvas, iparam1); + break; + case CDMF_LINESTYLEDASHES: + fscanf(file, "%d", &iparam1); + dashes = (int*)malloc(iparam1*sizeof(int)); + for (c = 0; c < iparam1; c++) + fscanf(file, "%d", &dashes[c]); + cdCanvasLineStyleDashes(canvas, dashes, iparam1); + free(dashes); + break; + case CDMF_FILLMODE: + fscanf(file, "%d", &iparam1); + cdCanvasFillMode(canvas, iparam1); + break; + case CDMF_INTERIORSTYLE: + fscanf(file, "%d", &iparam1); + cdCanvasInteriorStyle(canvas, iparam1); + break; + case CDMF_HATCH: + fscanf(file, "%d", &iparam1); + cdCanvasHatch(canvas, iparam1); + break; + case CDMF_STIPPLE: + fscanf(file, "%d %d", &iparam1, &iparam2); + t = iparam1 * iparam2; + stipple = (unsigned char*)malloc(t); + _stipple = stipple; + for (c = 0; c < t; c++) + { + fscanf(file, "%d", &iparam3); + *_stipple++ = (unsigned char)iparam3; + } + cdCanvasStipple(canvas, iparam1, iparam2, stipple); + free(stipple); + break; + case CDMF_PATTERN: + fscanf(file, "%d %d", &iparam1, &iparam2); + t = iparam1 * iparam2; + pattern = (long int*)malloc(t * sizeof(long)); + _pattern = pattern; + for (c = 0; c < t; c++) + { + fscanf(file, "%d %d %d", &iparam3, &iparam4, &iparam5); + *_pattern++ = cdEncodeColor((unsigned char)iparam3, (unsigned char)iparam4, (unsigned char)iparam5); + } + cdCanvasPattern(canvas, iparam1, iparam2, pattern); + free(pattern); + break; + case CDMF_OLDFONT: + fscanf(file, "%d %d %d", &iparam1, &iparam2, &iparam3); + if (iparam1 < 0 || iparam1 > 3) break; + if (iparam3 < 0) + { + iparam3 = -sScaleH(abs(iparam3)); + if (iparam3 > -5) iparam3 = -5; + } + else + { + iparam3 = sScaleH(abs(iparam3)); + if (iparam3 < 5) iparam3 = 5; + } + cdCanvasFont(canvas, font_family[iparam1], iparam2, iparam3); + break; + case CDMF_FONT: + fscanf(file, "%d %d %[^\n]", &iparam2, &iparam3, TextBuffer); + if (iparam3 < 0) + { + iparam3 = -sScaleH(abs(iparam3)); + if (iparam3 > -5) iparam3 = -5; + } + else + { + iparam3 = sScaleH(abs(iparam3)); + if (iparam3 < 5) iparam3 = 5; + } + cdCanvasFont(canvas, TextBuffer, iparam2, iparam3); + break; + case CDMF_NATIVEFONT: + fscanf(file, "%[^\n]", TextBuffer); + cdCanvasNativeFont(canvas, TextBuffer); + break; + case CDMF_TEXTALIGNMENT: + fscanf(file, "%d", &iparam1); + cdCanvasTextAlignment(canvas, iparam1); + break; + case CDMF_TEXTORIENTATION: + fscanf(file, "%lg", &dparam1); + cdCanvasTextOrientation(canvas, dparam1); + break; + case CDMF_MARKTYPE: + fscanf(file, "%d", &iparam1); + cdCanvasMarkType(canvas, iparam1); + break; + case CDMF_MARKSIZE: + fscanf(file, "%d", &iparam1); + cdCanvasMarkSize(canvas, sScaleS(iparam1)); + break; + case CDMF_PALETTE: + fscanf(file, "%d %d", &iparam1, &iparam2); + _palette = palette = (long int*)malloc(iparam1); + for (c = 0; c < iparam1; c++) + { + fscanf(file, "%d %d %d", &iparam3, &iparam4, &iparam5); + *_palette++ = cdEncodeColor((unsigned char)iparam3, (unsigned char)iparam4, (unsigned char)iparam5); + } + cdCanvasPalette(canvas, iparam1, palette, iparam2); + free(palette); + break; + case CDMF_BACKGROUND: + fscanf(file, "%d %d %d", &iparam1, &iparam2, &iparam3); + cdCanvasSetBackground(canvas, cdEncodeColor((unsigned char)iparam1, (unsigned char)iparam2, (unsigned char)iparam3)); + break; + case CDMF_FOREGROUND: + fscanf(file, "%d %d %d", &iparam1, &iparam2, &iparam3); + cdCanvasSetForeground(canvas, cdEncodeColor((unsigned char)iparam1, (unsigned char)iparam2, (unsigned char)iparam3)); + break; + case CDMF_PUTIMAGERGB: + fscanf(file, "%d %d %d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4, &iparam5, &iparam6); + t = iparam1 * iparam2; + _red = red = (unsigned char*) malloc(t); + _green = green = (unsigned char*) malloc(t); + _blue = blue = (unsigned char*) malloc(t); + for (c = 0; c < t; c++) + { + fscanf(file, "%d %d %d", &iparam7, &iparam8, &iparam9); + *_red++ = (unsigned char)iparam7; + *_green++ = (unsigned char)iparam8; + *_blue++ = (unsigned char)iparam9; + } + cdCanvasPutImageRectRGB(canvas, iparam1, iparam2, red, green, blue, sScaleX(iparam3), sScaleY(iparam4), sScaleW(iparam5), sScaleH(iparam6), 0, 0, 0, 0); + free(red); + free(green); + free(blue); + break; + case CDMF_PUTIMAGERGBA: + fscanf(file, "%d %d %d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4, &iparam5, &iparam6); + t = iparam1 * iparam2; + _red = red = (unsigned char*) malloc(t); + _green = green = (unsigned char*) malloc(t); + _blue = blue = (unsigned char*) malloc(t); + _alpha = alpha = (unsigned char*) malloc(t); + for (c = 0; c < t; c++) + { + fscanf(file, "%d %d %d %d", &iparam7, &iparam8, &iparam9, &iparam10); + *_red++ = (unsigned char)iparam7; + *_green++ = (unsigned char)iparam8; + *_blue++ = (unsigned char)iparam9; + *_alpha++ = (unsigned char)iparam10; + } + cdCanvasPutImageRectRGBA(canvas, iparam1, iparam2, red, green, blue, alpha, sScaleX(iparam3), sScaleY(iparam4), sScaleW(iparam5), sScaleH(iparam6), 0, 0, 0, 0); + free(red); + free(green); + free(blue); + free(alpha); + break; + case CDMF_PUTIMAGEMAP: + fscanf(file, "%d %d %d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4, &iparam5, &iparam6); + t = iparam1 * iparam2; + n = 0; + _index = index = (unsigned char*) malloc(t); + for (c = 0; c < t; c++) + { + fscanf(file, "%d", &iparam7); + *_index++ = (unsigned char)iparam7; + if (iparam7 > n) + n = iparam7; + } + _colors = colors = (long int*)malloc(n); + for (c = 0; c < n; c++) + { + fscanf(file, "%d %d %d", &iparam7, &iparam8, &iparam9); + *_colors++ = cdEncodeColor((unsigned char)iparam7, (unsigned char)iparam8, (unsigned char)iparam9); + } + cdCanvasPutImageRectMap(canvas, iparam1, iparam2, index, colors, sScaleX(iparam3), sScaleY(iparam4), sScaleW(iparam5), sScaleH(iparam6), 0, 0, 0, 0); + free(index); + free(colors); + break; + case CDMF_PIXEL: + fscanf(file, "%d %d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4, &iparam5); + cdCanvasPixel(canvas, sScaleX(iparam1), sScaleY(iparam2), cdEncodeColor((unsigned char)iparam3, (unsigned char)iparam4, (unsigned char)iparam5)); + break; + case CDMF_SCROLLAREA: + fscanf(file, "%d %d %d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4, &iparam5, &iparam6); + cdCanvasScrollArea(canvas, sScaleX(iparam1), sScaleX(iparam2), sScaleY(iparam3), sScaleY(iparam4), sScaleX(iparam5), sScaleY(iparam6)); + break; + case CDMF_WVECTORTEXT: + fscanf(file, "%lg %lg %[^\n]", &dparam1, &dparam2, TextBuffer); + wdCanvasVectorText(canvas, dparam1, dparam2, TextBuffer); + break; + case CDMF_WMULTILINEVECTORTEXT: + fscanf(file, "%lg %lg %[^\n]", &dparam1, &dparam2, TextBuffer); + wdCanvasVectorText(canvas, dparam1, dparam2, TextBuffer); + break; + case CDMF_VECTORTEXT: + fscanf(file, "%d %d %[^\n]", &iparam1, &iparam2, TextBuffer); + cdCanvasVectorText(canvas, iparam1, iparam2, TextBuffer); + break; + case CDMF_MULTILINEVECTORTEXT: + fscanf(file, "%d %d %[^\n]", &iparam1, &iparam2, TextBuffer); + cdCanvasVectorText(canvas, iparam1, iparam2, TextBuffer); + break; + case CDMF_WVECTORCHARSIZE: + fscanf(file, "%lg", &dparam1); + wdCanvasVectorCharSize(canvas, dparam1); + break; + case CDMF_WVECTORTEXTSIZE: + fscanf(file, "%lg %lg %[^\n]", &dparam1, &dparam2, TextBuffer); + wdCanvasVectorTextSize(canvas, dparam1, dparam2, TextBuffer); + break; + case CDMF_WVECTORTEXTDIRECTION: + fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4); + wdCanvasVectorTextDirection(canvas, dparam1, dparam2, dparam3, dparam4); + break; + case CDMF_VECTORCHARSIZE: + fscanf(file, "%d", &iparam1); + cdCanvasVectorCharSize(canvas, iparam1); + break; + case CDMF_VECTORTEXTSIZE: + fscanf(file, "%d %d %[^\n]", &iparam1, &iparam2, TextBuffer); + cdCanvasVectorTextSize(canvas, iparam1, iparam2, TextBuffer); + break; + case CDMF_VECTORTEXTDIRECTION: + fscanf(file, "%d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4); + cdCanvasVectorTextDirection(canvas, iparam1, iparam2, iparam3, iparam4); + break; + case CDMF_VECTORFONT: + fscanf(file, "%[^\n]", TextBuffer); + cdCanvasVectorFont(canvas, TextBuffer); + break; + case CDMF_VECTORTEXTTRANSFORM: + fscanf(file, "%lg %lg %lg %lg %lg %lg", &matrix[0], &matrix[1], &matrix[2], &matrix[3], &matrix[4], &matrix[5]); + cdCanvasVectorTextTransform(canvas, matrix); + break; + case CDMF_WINDOW: + fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4); + wdCanvasWindow(canvas, dparam1, dparam2, dparam3, dparam4); + break; + default: + fclose(file); + return CD_ERROR; + } + } + + fclose(file); + + return CD_OK; +} + +/*******************/ +/* Canvas Creation */ +/*******************/ + +void cdcreatecanvasMF(cdCanvas *canvas, void *data) +{ + char filename[10240] = ""; + char* strdata = (char*)data; + double w_mm = INT_MAX*3.78, h_mm = INT_MAX*3.78, res = 3.78; + cdCtxCanvas* ctxcanvas; + int size; + + strdata += cdGetFileName(strdata, filename); + if (filename[0] == 0) + return; + + sscanf(strdata, "%lgx%lg %lg", &w_mm, &h_mm, &res); + + ctxcanvas = (cdCtxCanvas *)malloc(sizeof(cdCtxCanvas)); + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + + ctxcanvas->file = fopen(filename, "w"); + if (!ctxcanvas->file) + { + free(ctxcanvas); + return; + } + + size = strlen(filename); + ctxcanvas->filename = malloc(size+1); + memcpy(ctxcanvas->filename, filename, size+1); + + ctxcanvas->canvas = canvas; + + /* update canvas context */ + canvas->w = (int)(w_mm * res); + canvas->h = (int)(h_mm * res); + canvas->w_mm = w_mm; + canvas->h_mm = h_mm; + canvas->bpp = 24; + canvas->xres = res; + canvas->yres = res; + canvas->ctxcanvas = ctxcanvas; + + ctxcanvas->last_line_style = -1; + ctxcanvas->last_fill_mode = -1; + + fprintf(ctxcanvas->file, "CDMF %d %d\n", canvas->w, canvas->h); +} + +void cdinittableMF(cdCanvas* canvas) +{ + canvas->cxFlush = cdflush; + canvas->cxClear = cdclear; + canvas->cxPixel = cdpixel; + canvas->cxLine = cdline; + canvas->cxPoly = cdpoly; + canvas->cxRect = cdrect; + canvas->cxBox = cdbox; + canvas->cxArc = cdarc; + canvas->cxSector = cdsector; + canvas->cxChord = cdchord; + canvas->cxText = cdtext; + canvas->cxPutImageRectRGB = cdputimagerectrgb; + canvas->cxPutImageRectRGBA = cdputimagerectrgba; + canvas->cxPutImageRectMap = cdputimagerectmap; + canvas->cxScrollArea = cdscrollarea; + canvas->cxFLine = cdfline; + canvas->cxFPoly = cdfpoly; + canvas->cxFRect = cdfrect; + canvas->cxFBox = cdfbox; + canvas->cxFArc = cdfarc; + canvas->cxFSector = cdfsector; + canvas->cxFChord = cdfchord; + canvas->cxFText = cdftext; + canvas->cxClip = cdclip; + canvas->cxClipArea = cdcliparea; + canvas->cxBackOpacity = cdbackopacity; + canvas->cxWriteMode = cdwritemode; + canvas->cxLineStyle = cdlinestyle; + canvas->cxLineWidth = cdlinewidth; + canvas->cxLineCap = cdlinecap; + canvas->cxLineJoin = cdlinejoin; + canvas->cxInteriorStyle = cdinteriorstyle; + canvas->cxHatch = cdhatch; + canvas->cxStipple = cdstipple; + canvas->cxPattern = cdpattern; + canvas->cxFont = cdfont; + canvas->cxNativeFont = cdnativefont; + canvas->cxTextAlignment = cdtextalignment; + canvas->cxTextOrientation = cdtextorientation; + canvas->cxPalette = cdpalette; + canvas->cxBackground = cdbackground; + canvas->cxForeground = cdforeground; + canvas->cxFClipArea = cdfcliparea; + canvas->cxTransform = cdtransform; + + canvas->cxKillCanvas = (void (*)(cdCtxCanvas*))cdkillcanvasMF; +} + +static cdContext cdMetafileContext = +{ + CD_CAP_ALL & ~(CD_CAP_GETIMAGERGB | CD_CAP_IMAGESRV | + CD_CAP_REGION | CD_CAP_FONTDIM | CD_CAP_TEXTSIZE), + 0, + cdcreatecanvasMF, + cdinittableMF, + cdplay, + cdregistercallback, +}; + +cdContext* cdContextMetafile(void) +{ + return &cdMetafileContext; +} diff --git a/src/drv/cdpdf.c b/src/drv/cdpdf.c new file mode 100644 index 0000000..24509f6 --- /dev/null +++ b/src/drv/cdpdf.c @@ -0,0 +1,1491 @@ +/** \file + * \brief PDF Driver + * + * See Copyright Notice in cd.h + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <math.h> + +#include "cd.h" +#include "cd_private.h" +#include "cdpdf.h" + +#include "pdflib.h" + + +/* +** dada uma cor do CD, obtem uma de suas componentes, na faixa 0-1. +*/ +#define get_red(_) (((double)cdRed(_))/255.) +#define get_green(_) (((double)cdGreen(_))/255.) +#define get_blue(_) (((double)cdBlue(_))/255.) + +struct _cdCtxCanvas +{ + cdCanvas* canvas; + + PDF *pdf; /* Arquivo PDF */ + int res; /* Resolucao - DPI */ + int pages; /* Numero total de paginas */ + double width_pt; /* Largura do papel (points) */ + double height_pt; /* Altura do papel (points) */ + double width_mm; /* Largura do papel (mm) */ + double height_mm; /* Altura do papel (mm) */ + double scale; /* Fator de conversao de coordenadas (pixel2points) */ + int landscape; /* page orientation */ + float rotate_angle; + int rotate_center_x, + rotate_center_y; + + int font; + int underline; + int strikeover; + + int hatchboxsize; + int pattern; + int opacity; + int opacity_states[256]; + + int poly_holes[500]; + int holes; +}; + + +/* +%F Ajusta o tamanho do papel em points. +*/ +static void setpdfpapersize(cdCtxCanvas* ctxcanvas, int size) +{ + static struct + { + int width; + int height; + } paper[] = + { + { 2393, 3391 }, /* A0 */ + { 1689, 2393 }, /* A1 */ + { 1192, 1689 }, /* A2 */ + { 842, 1192 }, /* A3 */ + { 595, 842 }, /* A4 */ + { 420, 595 }, /* A5 */ + { 612, 792 }, /* LETTER */ + { 612, 1008 } /* LEGAL */ + }; + + if (size<CD_A0 || size>CD_LEGAL) + return; + + ctxcanvas->width_pt = paper[size].width; + ctxcanvas->height_pt = paper[size].height; + ctxcanvas->width_mm = ctxcanvas->width_pt/CD_MM2PT; + ctxcanvas->height_mm = ctxcanvas->height_pt/CD_MM2PT; +} + +/* +%F Registra os valores default para impressao. +*/ +static void setpdfdefaultvalues(cdCtxCanvas* ctxcanvas) +{ + int i; + + /* all the other values are set to 0 */ + setpdfpapersize(ctxcanvas, CD_A4); + ctxcanvas->res = 300; + ctxcanvas->hatchboxsize = 8; + ctxcanvas->opacity = 255; /* full opaque */ + + for (i=0; i<256; i++) + ctxcanvas->opacity_states[i] = -1; +} + +static void update_state(cdCtxCanvas *ctxcanvas) +{ + cdCanvas* canvas = ctxcanvas->canvas; + + if (!canvas->cxFont) /* just check if the first time */ + return; + + /* must set the current transform and line style if different from the default */ + + if (canvas->line_style != CD_CONTINUOUS) + canvas->cxLineStyle(ctxcanvas, canvas->line_style); + if (canvas->line_width != 1) + canvas->cxLineWidth(ctxcanvas, canvas->line_width); + if (canvas->line_cap != CD_CAPFLAT) + canvas->cxLineCap(ctxcanvas, canvas->line_cap); + if (canvas->line_join != CD_MITER) + canvas->cxLineJoin(ctxcanvas, canvas->line_join); + if (canvas->use_matrix) + canvas->cxTransform(ctxcanvas, canvas->matrix); + canvas->cxFont(ctxcanvas, canvas->font_type_face, canvas->font_style, canvas->font_size); +} + +static void begin_page(cdCtxCanvas *ctxcanvas) +{ + PDF_begin_page_ext(ctxcanvas->pdf, ctxcanvas->width_pt, ctxcanvas->height_pt, ""); + + /* default coordinate system is in points, change it to pixels. */ + PDF_scale(ctxcanvas->pdf, ctxcanvas->scale, ctxcanvas->scale); + + PDF_save(ctxcanvas->pdf); /* save the initial configuration, to be used when clipping is reset. */ + + update_state(ctxcanvas); +} + +static void init_pdf(cdCtxCanvas *ctxcanvas) +{ + ctxcanvas->scale = 72.0/ctxcanvas->res; + + /* Converte p/ unidades do usuario */ + ctxcanvas->canvas->w = (int)(ctxcanvas->width_pt/ctxcanvas->scale + 0.5); + ctxcanvas->canvas->h = (int)(ctxcanvas->height_pt/ctxcanvas->scale + 0.5); + + /* Passa o valor em milimetros para o canvas CD */ + ctxcanvas->canvas->w_mm = ctxcanvas->width_mm; + ctxcanvas->canvas->h_mm = ctxcanvas->height_mm; + + ctxcanvas->canvas->bpp = 24; + ctxcanvas->canvas->xres = ctxcanvas->canvas->w / ctxcanvas->canvas->w_mm; + ctxcanvas->canvas->yres = ctxcanvas->canvas->h / ctxcanvas->canvas->h_mm; + + begin_page(ctxcanvas); +} + +static void cdkillcanvas(cdCtxCanvas *ctxcanvas) +{ + PDF_restore(ctxcanvas->pdf); /* restore to match the save of the initial configuration. */ + PDF_end_page_ext(ctxcanvas->pdf, ""); + PDF_end_document(ctxcanvas->pdf, ""); + PDF_delete(ctxcanvas->pdf); + + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + free(ctxcanvas); +} + +static void update_fill(cdCtxCanvas *ctxcanvas, int fill) +{ + if (fill == 0) + { + /* called before a NON filled primitive */ + PDF_setcolor(ctxcanvas->pdf, "stroke", "rgb", get_red(ctxcanvas->canvas->foreground), + get_green(ctxcanvas->canvas->foreground), + get_blue(ctxcanvas->canvas->foreground), 0); + + } + else + { + /* called before a filled primitive */ + if (ctxcanvas->canvas->interior_style == CD_SOLID) + { + PDF_setcolor(ctxcanvas->pdf, "fill", "rgb", get_red(ctxcanvas->canvas->foreground), + get_green(ctxcanvas->canvas->foreground), + get_blue(ctxcanvas->canvas->foreground), 0); + } + else + PDF_setcolor(ctxcanvas->pdf, "fill", "pattern", (float)ctxcanvas->pattern, 0, 0, 0); + } +} + +/* +%F Comeca uma nova pagina. +*/ +static void cdflush(cdCtxCanvas *ctxcanvas) +{ + PDF_restore(ctxcanvas->pdf); /* restore to match the save of the initial configuration */ + + PDF_end_page_ext(ctxcanvas->pdf, ""); + + begin_page(ctxcanvas); +} + + +/******************************************************/ +/* coordinate transformation */ +/******************************************************/ + +static void resetcliprect(cdCtxCanvas* ctxcanvas) +{ + /* clipping is reset, by restoring the initial state */ + /* this will also reset the current transformation and line style */ + PDF_restore(ctxcanvas->pdf); + PDF_save(ctxcanvas->pdf); + + update_state(ctxcanvas); +} + +static void setcliprect(cdCtxCanvas* ctxcanvas, double xmin, double ymin, double xmax, double ymax) +{ + resetcliprect(ctxcanvas); + + PDF_moveto(ctxcanvas->pdf, xmin, ymin); + PDF_lineto(ctxcanvas->pdf, xmax, ymin); + PDF_lineto(ctxcanvas->pdf, xmax, ymax); + PDF_lineto(ctxcanvas->pdf, xmin, ymax); + + PDF_clip(ctxcanvas->pdf); +} + +static void cdfcliparea(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + if (ctxcanvas->canvas->clip_mode != CD_CLIPAREA) + return; + + setcliprect(ctxcanvas, xmin, ymin, xmax, ymax); +} + +static void cdcliparea(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + cdfcliparea(ctxcanvas, (double)xmin, (double)xmax, (double)ymin, (double)ymax); +} + +static int cdclip(cdCtxCanvas *ctxcanvas, int mode) +{ + if (mode == CD_CLIPAREA) + { + ctxcanvas->canvas->clip_mode = CD_CLIPAREA; + + setcliprect(ctxcanvas, (double)ctxcanvas->canvas->clip_rect.xmin, + (double)ctxcanvas->canvas->clip_rect.ymin, + (double)ctxcanvas->canvas->clip_rect.xmax, + (double)ctxcanvas->canvas->clip_rect.ymax); + } + else if (mode == CD_CLIPPOLYGON) + { + int hole_index = 0; + int i; + + resetcliprect(ctxcanvas); + + if (ctxcanvas->canvas->clip_poly) + { + cdPoint *poly = ctxcanvas->canvas->clip_poly; + + PDF_moveto(ctxcanvas->pdf, poly[0].x, poly[0].y); + + for (i=1; i<ctxcanvas->canvas->clip_poly_n; i++) + { + if (ctxcanvas->holes && i == ctxcanvas->poly_holes[hole_index]) + { + PDF_moveto(ctxcanvas->pdf, poly[i].x, poly[i].y); + hole_index++; + } + else + PDF_lineto(ctxcanvas->pdf, poly[i].x, poly[i].y); + } + } + else if (ctxcanvas->canvas->clip_fpoly) + { + cdfPoint *poly = ctxcanvas->canvas->clip_fpoly; + + PDF_moveto(ctxcanvas->pdf, poly[0].x, poly[0].y); + + for (i=1; i<ctxcanvas->canvas->clip_poly_n; i++) + { + if (ctxcanvas->holes && i == ctxcanvas->poly_holes[hole_index]) + { + PDF_moveto(ctxcanvas->pdf, poly[i].x, poly[i].y); + hole_index++; + } + else + PDF_lineto(ctxcanvas->pdf, poly[i].x, poly[i].y); + } + } + + PDF_clip(ctxcanvas->pdf); + } + else if (mode == CD_CLIPOFF) + { + resetcliprect(ctxcanvas); + } + + return mode; +} + +/******************************************************/ +/* primitives */ +/******************************************************/ + +static void cdfline(cdCtxCanvas *ctxcanvas, double x1, double y1, double x2, double y2) +{ + update_fill(ctxcanvas, 0); + + PDF_moveto(ctxcanvas->pdf, x1, y1); + PDF_lineto(ctxcanvas->pdf, x2, y2); + PDF_stroke(ctxcanvas->pdf); +} + +static void cdline(cdCtxCanvas *ctxcanvas, int x1, int y1, int x2, int y2) +{ + cdfline(ctxcanvas, (double)x1, (double)y1, (double)x2, (double)y2); +} + +static void cdfrect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + update_fill(ctxcanvas, 0); + + PDF_rect(ctxcanvas->pdf, xmin, ymin, xmax-xmin, ymax-ymin); + PDF_stroke(ctxcanvas->pdf); +} + +static void cdrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + cdfrect(ctxcanvas, (double)xmin, (double)xmax, (double)ymin, (double)ymax); +} + +static void cdfbox(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + update_fill(ctxcanvas, 1); + + PDF_moveto(ctxcanvas->pdf, xmin, ymin); + PDF_lineto(ctxcanvas->pdf, xmax, ymin); + PDF_lineto(ctxcanvas->pdf, xmax, ymax); + PDF_lineto(ctxcanvas->pdf, xmin, ymax); + PDF_fill(ctxcanvas->pdf); +} + +static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + cdfbox(ctxcanvas, (double)xmin, (double)xmax, (double)ymin, (double)ymax); +} + +static void cdfarc(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + update_fill(ctxcanvas, 0); + + if (w==h) + { + PDF_arc(ctxcanvas->pdf, xc, yc, 0.5*w, a1, a2); + PDF_stroke(ctxcanvas->pdf); + } + else /* Elipse: mudar a escala p/ criar a partir do circulo */ + { + PDF_save(ctxcanvas->pdf); /* save to use the local transform */ + + PDF_translate(ctxcanvas->pdf, xc, yc); + PDF_scale(ctxcanvas->pdf, w/h, 1); + PDF_translate(ctxcanvas->pdf, -xc, -yc); + + PDF_arc(ctxcanvas->pdf, xc, yc, 0.5*h, a1, a2); + PDF_stroke(ctxcanvas->pdf); + + PDF_restore(ctxcanvas->pdf); /* restore from local */ + } +} + +static void cdarc(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + cdfarc(ctxcanvas, (double)xc, (double)yc, (double)w, (double)h, a1, a2); +} + +static void cdfsector(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + update_fill(ctxcanvas, 1); + + if (w==h) + { + PDF_moveto(ctxcanvas->pdf, xc, yc); + PDF_arc(ctxcanvas->pdf, xc, yc, 0.5*w, a1, a2); + PDF_fill(ctxcanvas->pdf); + } + else /* Elipse: mudar a escala p/ criar a partir do circulo */ + { + PDF_save(ctxcanvas->pdf); /* save to use the local transform */ + + PDF_translate(ctxcanvas->pdf, xc, yc); + PDF_scale(ctxcanvas->pdf, w/h, 1); + PDF_translate(ctxcanvas->pdf, -xc, -yc); + + PDF_moveto(ctxcanvas->pdf, xc, yc); + PDF_arc(ctxcanvas->pdf, xc, yc, 0.5*h, a1, a2); + + if (ctxcanvas->canvas->interior_style == CD_SOLID || + ctxcanvas->canvas->interior_style == CD_PATTERN) + PDF_fill(ctxcanvas->pdf); + else + { + PDF_lineto(ctxcanvas->pdf, xc, yc); + PDF_stroke(ctxcanvas->pdf); + } + + PDF_restore(ctxcanvas->pdf); /* restore from local */ + } +} + +static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + cdfsector(ctxcanvas, (double)xc, (double)yc, (double)w, (double)h, a1, a2); +} + +static void cdfchord(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + update_fill(ctxcanvas, 1); + + if (w==h) + { + PDF_arc(ctxcanvas->pdf, xc, yc, 0.5*w, a1, a2); + PDF_fill_stroke(ctxcanvas->pdf); + } + else /* Elipse: mudar a escala p/ criar a partir do circulo */ + { + PDF_save(ctxcanvas->pdf); /* save to use the local transform */ + + /* local transform */ + PDF_translate(ctxcanvas->pdf, xc, yc); + PDF_scale(ctxcanvas->pdf, 1, w/h); + + PDF_arc(ctxcanvas->pdf, xc, yc, 0.5*w, a1, a2); + PDF_fill_stroke(ctxcanvas->pdf); + + PDF_restore(ctxcanvas->pdf); /* restore from local */ + } +} + +static void cdchord(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + cdfchord(ctxcanvas, (double)xc, (double)yc, (double)w, (double)h, a1, a2); +} + +static void cdgetfontdim(cdCtxCanvas *ctxcanvas, int *max_width, int *height, int *ascent, int *descent) +{ + double fontsize, a, d, linegap; + + if (ctxcanvas->font<0) + return; + + fontsize = PDF_get_value(ctxcanvas->pdf, "fontsize", 0); + a = PDF_get_value(ctxcanvas->pdf, "ascender", 0); + d = PDF_get_value(ctxcanvas->pdf, "descender", 0); + + /* linegap = PDF_info_font(ctxcanvas->pdf, 1, "linegap", ""); - not supported call */ + linegap = 0.23 * a; /* use default value for linegap */ + a += linegap; + d += linegap; /* since d<0, it is a subtraction */ + + a *= fontsize; + d *= fontsize; + + if (ascent) *ascent = (int)a; + if (descent) *descent = (int)(-d); + if (height) *height = (int)(a - d); + if (max_width) *max_width = (int)(PDF_info_textline(ctxcanvas->pdf, "W", 0, "width", "")/ctxcanvas->scale); +} + +static void cdgettextsize(cdCtxCanvas *ctxcanvas, const char *s, int *width, int *height) +{ + if (ctxcanvas->font<0) + return; + if (height) cdgetfontdim(ctxcanvas, NULL, height, NULL, NULL); + if (width) *width = (int)(PDF_info_textline(ctxcanvas->pdf, s, 0, "width", "")/ctxcanvas->scale); +} + +static void cdftext(cdCtxCanvas *ctxcanvas, double x, double y, const char *s) +{ + char temp[200], options[200]; + + PDF_setcolor(ctxcanvas->pdf, "fill", "rgb", get_red(ctxcanvas->canvas->foreground), + get_green(ctxcanvas->canvas->foreground), + get_blue(ctxcanvas->canvas->foreground), 0); + + strcpy(options, ""); + + sprintf(temp, "rotate=%g ", ctxcanvas->canvas->text_orientation); + strcat(options, temp); + + if (ctxcanvas->underline != 0) + strcat(options, "underline=true "); + else + strcat(options, "underline=false "); + + if (ctxcanvas->strikeover != 0) + strcat(options, "strikeout=true "); + else + strcat(options, "strikeout=false "); + + switch (ctxcanvas->canvas->text_alignment) + { + case CD_NORTH: + sprintf(temp, "position={50 100} matchbox { boxheight={ascender descender} }"); + strcat(options, temp); + break; + case CD_NORTH_EAST: + sprintf(temp, "position={100 100} matchbox { boxheight={ascender descender} }"); + strcat(options, temp); + break; + case CD_NORTH_WEST: + sprintf(temp, "position={0 100} matchbox { boxheight={ascender descender} }"); + strcat(options, temp); + break; + case CD_EAST: + sprintf(temp, "position={100 50} matchbox { boxheight={ascender descender} }"); + strcat(options, temp); + break; + case CD_WEST: + sprintf(temp, "position={0 50} matchbox { boxheight={ascender descender} }"); + strcat(options, temp); + break; + case CD_CENTER: + sprintf(temp, "position={50 50} matchbox { boxheight={ascender descender} }"); + strcat(options, temp); + break; + case CD_SOUTH_EAST: + sprintf(temp, "position={100 0} matchbox { boxheight={ascender descender} }"); + strcat(options, temp); + break; + case CD_SOUTH: + sprintf(temp, "position={50 0} matchbox { boxheight={ascender descender} }"); + strcat(options, temp); + break; + case CD_SOUTH_WEST: + sprintf(temp, "position={0 0} matchbox { boxheight={ascender descender} }"); + strcat(options, temp); + break; + case CD_BASE_RIGHT: + sprintf(temp, "position={100 0} matchbox { boxheight={ascender none} }"); + strcat(options, temp); + break; + case CD_BASE_CENTER: + sprintf(temp, "position={50 0} matchbox { boxheight={ascender none} }"); + strcat(options, temp); + break; + case CD_BASE_LEFT: + sprintf(temp, "position={0 0} matchbox { boxheight={ascender none} }"); + strcat(options, temp); + break; + } + + PDF_fit_textline(ctxcanvas->pdf, s, 0, x, y, options); +} + +static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *s) +{ + cdftext(ctxcanvas, (double)x, (double)y, s); +} + +static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n) +{ + int i; + + if (mode == CD_CLIP) + return; + + if (mode == CD_FILL) + update_fill(ctxcanvas, 1); + else + update_fill(ctxcanvas, 0); + + if (mode==CD_FILL) + { + if (ctxcanvas->holes || ctxcanvas->canvas->fill_mode==CD_EVENODD) + PDF_set_parameter(ctxcanvas->pdf, "fillrule", "evenodd"); + else + PDF_set_parameter(ctxcanvas->pdf, "fillrule", "winding"); + } + + PDF_moveto(ctxcanvas->pdf, poly[0].x, poly[0].y); + + if (mode == CD_BEZIER) + { + for (i=1; i<n; i+=3) + PDF_curveto(ctxcanvas->pdf, poly[i].x, poly[i].y, + poly[i+1].x, poly[i+1].y, + poly[i+2].x, poly[i+2].y); + } + else + { + int hole_index = 0; + + for (i=1; i<n; i++) + { + if (ctxcanvas->holes && i == ctxcanvas->poly_holes[hole_index]) + { + PDF_moveto(ctxcanvas->pdf, poly[i].x, poly[i].y); + hole_index++; + } + else + PDF_lineto(ctxcanvas->pdf, poly[i].x, poly[i].y); + } + } + + switch (mode) + { + case CD_CLOSED_LINES : + PDF_closepath_stroke(ctxcanvas->pdf); + break; + case CD_OPEN_LINES : + PDF_stroke(ctxcanvas->pdf); + break; + case CD_BEZIER : + PDF_stroke(ctxcanvas->pdf); + break; + case CD_FILL : + PDF_fill(ctxcanvas->pdf); + break; + } +} + +static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n) +{ + int i; + + if (mode == CD_CLIP) + return; + + if (mode == CD_FILL) + update_fill(ctxcanvas, 1); + else + update_fill(ctxcanvas, 0); + + if (mode==CD_FILL) + { + if (ctxcanvas->holes || ctxcanvas->canvas->fill_mode==CD_EVENODD) + PDF_set_parameter(ctxcanvas->pdf, "fillrule", "evenodd"); + else + PDF_set_parameter(ctxcanvas->pdf, "fillrule", "winding"); + } + + PDF_moveto(ctxcanvas->pdf, poly[0].x, poly[0].y); + + if (mode == CD_BEZIER) + { + for (i=1; i<n; i+=3) + PDF_curveto(ctxcanvas->pdf, poly[i].x, poly[i].y, + poly[i+1].x, poly[i+1].y, + poly[i+2].x, poly[i+2].y); + } + else + { + int hole_index = 0; + + for (i=1; i<n; i++) + { + if (ctxcanvas->holes && i == ctxcanvas->poly_holes[hole_index]) + { + PDF_moveto(ctxcanvas->pdf, poly[i].x, poly[i].y); + hole_index++; + } + else + PDF_lineto(ctxcanvas->pdf, poly[i].x, poly[i].y); + } + } + + switch (mode) + { + case CD_CLOSED_LINES : + PDF_closepath_stroke(ctxcanvas->pdf); + break; + case CD_OPEN_LINES : + PDF_stroke(ctxcanvas->pdf); + break; + case CD_BEZIER : + PDF_stroke(ctxcanvas->pdf); + break; + case CD_FILL : + PDF_fill(ctxcanvas->pdf); + break; + } +} + +/******************************************************/ +/* attributes */ +/******************************************************/ + +static int cdlinestyle(cdCtxCanvas *ctxcanvas, int style) +{ + double mm = (72.0/25.4) / ctxcanvas->scale; + char options[80]; + + switch (style) + { + case CD_CONTINUOUS : /* empty dash */ + PDF_setdash(ctxcanvas->pdf, 0, 0); + break; + case CD_DASHED : + PDF_setdash(ctxcanvas->pdf, 3*mm, mm); + break; + case CD_DOTTED : + PDF_setdash(ctxcanvas->pdf, mm, mm); + break; + case CD_DASH_DOT : + sprintf(options, "dasharray={%g %g %g %g}", 3*mm, mm, mm, mm); + PDF_setdashpattern(ctxcanvas->pdf, options); + break; + case CD_DASH_DOT_DOT : + sprintf(options, "dasharray={%g %g %g %g %g %g}", 3*mm, mm, mm, mm, mm, mm); + PDF_setdashpattern(ctxcanvas->pdf, options); + break; + case CD_CUSTOM : + { + int i; + + strcpy(options, "dasharray={"); + for (i = 0; i < ctxcanvas->canvas->line_dashes_count; i++) + { + char tmp[80]; + sprintf(tmp, "%g ", ctxcanvas->canvas->line_dashes[i]*mm); + strcat(options, tmp); + } + strcat(options, "}"); + PDF_setdashpattern(ctxcanvas->pdf, options); + } + break; + } + + return style; +} + +static int cdlinewidth(cdCtxCanvas *ctxcanvas, int width) +{ + if (width==0) width = 1; + + PDF_setlinewidth(ctxcanvas->pdf, width); + + return width; +} + +static int cdlinejoin(cdCtxCanvas *ctxcanvas, int join) +{ + int cd2ps_join[] = {0, 2, 1}; + PDF_setlinejoin(ctxcanvas->pdf, cd2ps_join[join]); + return join; +} + +static int cdlinecap(cdCtxCanvas *ctxcanvas, int cap) +{ + int cd2pdf_cap[] = {0, 2, 1}; + PDF_setlinecap(ctxcanvas->pdf, cd2pdf_cap[cap]); + return cap; +} + +static void make_pattern(cdCtxCanvas *ctxcanvas, int n, int m, void* data, int (*data2rgb)(cdCtxCanvas *ctxcanvas, int n, int i, int j, void* data, unsigned char*r, unsigned char*g, unsigned char*b)) +{ + int i, j; + unsigned char r, g, b; + + PDF_suspend_page(ctxcanvas->pdf, ""); + ctxcanvas->pattern = PDF_begin_pattern(ctxcanvas->pdf, n, m, + ((double)n)*ctxcanvas->scale, ((double)m)*ctxcanvas->scale, 1); + + PDF_scale(ctxcanvas->pdf, ctxcanvas->scale, ctxcanvas->scale); + + for (j=0; j<m; j++) + { + for (i=0; i<n; i++) + { + int ret = data2rgb(ctxcanvas, n, i, j, data, &r, &g, &b); + if (ret==-1) continue; + PDF_setcolor(ctxcanvas->pdf, "fill", "rgb", ((double)r)/255, ((double)g)/255, ((double)b)/255, 0); + PDF_rect(ctxcanvas->pdf, i, j, 1, 1); + PDF_fill(ctxcanvas->pdf); + } + } + + PDF_end_pattern(ctxcanvas->pdf); + PDF_resume_page(ctxcanvas->pdf, ""); +} + +static int long2rgb(cdCtxCanvas *ctxcanvas, int n, int i, int j, void* data, unsigned char*r, unsigned char*g, unsigned char*b) +{ + long* long_data = (long*)data; + (void)ctxcanvas; + cdDecodeColor(long_data[j*n+i], r, g, b); + return 1; +} + +static void cdpattern(cdCtxCanvas *ctxcanvas, int n, int m, const long int *pattern) +{ + make_pattern(ctxcanvas, n, m, (void*)pattern, long2rgb); +} + +static int uchar2rgb(cdCtxCanvas *ctxcanvas, int n, int i, int j, void* data, unsigned char*r, unsigned char*g, unsigned char*b) +{ + int ret = 1; + unsigned char* uchar_data = (unsigned char*)data; + if (uchar_data[j*n+i]) + { + cdDecodeColor(ctxcanvas->canvas->foreground, r, g, b); + ret = 1; + } + else + { + cdDecodeColor(ctxcanvas->canvas->background, r, g, b); + if (ctxcanvas->canvas->back_opacity==CD_TRANSPARENT) + ret = -1; + } + + return ret; +} + +static void cdstipple(cdCtxCanvas *ctxcanvas, int n, int m, const unsigned char *stipple) +{ + make_pattern(ctxcanvas, n, m, (void*)stipple, uchar2rgb); +} + +static void make_hatch(cdCtxCanvas *ctxcanvas, int style) +{ + unsigned char r, g, b; + int hsize = ctxcanvas->hatchboxsize - 1; + int hhalf = hsize / 2; + + PDF_suspend_page(ctxcanvas->pdf, ""); + ctxcanvas->pattern = PDF_begin_pattern(ctxcanvas->pdf, hsize + 1, hsize + 1, + ((double)hsize)*ctxcanvas->scale, ((double)hsize)*ctxcanvas->scale, 1); + + PDF_scale(ctxcanvas->pdf, ctxcanvas->scale, ctxcanvas->scale); + + if (ctxcanvas->canvas->back_opacity==CD_OPAQUE) + { + cdDecodeColor(ctxcanvas->canvas->background, &r, &g, &b); + PDF_setcolor(ctxcanvas->pdf, "fill", "rgb", ((double)r)/255, ((double)g)/255, ((double)b)/255, 0); + PDF_rect(ctxcanvas->pdf, 0, 0, hsize, hsize); + PDF_fill(ctxcanvas->pdf); + } + + cdDecodeColor(ctxcanvas->canvas->foreground, &r, &g, &b); + PDF_setcolor(ctxcanvas->pdf, "stroke", "rgb", ((double)r)/255, ((double)g)/255, ((double)b)/255, 0); + + switch(style) + { + case CD_HORIZONTAL: + PDF_moveto(ctxcanvas->pdf, 0, hhalf); + PDF_lineto(ctxcanvas->pdf, hsize, hhalf); + break; + case CD_VERTICAL: + PDF_moveto(ctxcanvas->pdf, hhalf, 0); + PDF_lineto(ctxcanvas->pdf, hhalf, hsize); + break; + case CD_BDIAGONAL: + PDF_moveto(ctxcanvas->pdf, 0, hsize); + PDF_lineto(ctxcanvas->pdf, hsize, 0); + break; + case CD_FDIAGONAL: + PDF_moveto(ctxcanvas->pdf, 0, 0); + PDF_lineto(ctxcanvas->pdf, hsize, hsize); + break; + case CD_CROSS: + PDF_moveto(ctxcanvas->pdf, hsize, 0); + PDF_lineto(ctxcanvas->pdf, hsize, hsize); + PDF_moveto(ctxcanvas->pdf, 0, hhalf); + PDF_lineto(ctxcanvas->pdf, hsize, hhalf); + break; + case CD_DIAGCROSS: + PDF_moveto(ctxcanvas->pdf, 0, 0); + PDF_lineto(ctxcanvas->pdf, hsize, hsize); + PDF_moveto(ctxcanvas->pdf, hsize, 0); + PDF_lineto(ctxcanvas->pdf, 0, hsize); + break; + } + + PDF_stroke(ctxcanvas->pdf); + + PDF_end_pattern(ctxcanvas->pdf); + PDF_resume_page(ctxcanvas->pdf, ""); +} + +static int cdhatch(cdCtxCanvas *ctxcanvas, int style) +{ + make_hatch(ctxcanvas, style); + return style; +} + +static int cdfont(cdCtxCanvas *ctxcanvas, const char *type_face, int style, int size) +{ + int newfont, sizepixel; + char nativefontname[1024]; + const char* options = ""; + + if (cdStrEqualNoCase(type_face, "System")) + type_face = "Courier"; + + strcpy(nativefontname, type_face); + + if (cdStrEqualNoCase(type_face, "Courier") || + cdStrEqualNoCase(type_face, "Helvetica")) + { + if (style&CD_BOLD && style&CD_ITALIC) + strcat(nativefontname, "-BoldOblique"); + else + { + if (style&CD_BOLD) + strcat(nativefontname, "-Bold"); + + if (style&CD_ITALIC) + strcat(nativefontname, "-Oblique"); + } + } + else if (cdStrEqualNoCase(type_face, "Times")) + { + if ((style&3) == CD_PLAIN) + strcat(nativefontname, "-Roman"); + if (style&CD_BOLD && style&CD_ITALIC) + strcat(nativefontname, "-BoldItalic"); + else + { + if (style&CD_BOLD) + strcat(nativefontname, "-Bold"); + + if (style&CD_ITALIC) + strcat(nativefontname, "-Italic"); + } + } + else + { + switch(style&3) + { + case CD_PLAIN: + options = "fontstyle=normal"; + break; + case CD_BOLD: + options = "fontstyle=bold"; + break; + case CD_ITALIC: + options = "fontstyle=italic"; + break; + case CD_BOLD_ITALIC: + options = "fontstyle=bolditalic"; + break; + } + } + + newfont = PDF_load_font(ctxcanvas->pdf, nativefontname, 0, "auto", options); + if (newfont<0) + { + /* must reload the previous one */ + return 0; + } + ctxcanvas->font = newfont; + + sizepixel = cdGetFontSizePixels(ctxcanvas->canvas, size); + PDF_setfont(ctxcanvas->pdf, ctxcanvas->font, sizepixel); + + if (style&CD_UNDERLINE) + ctxcanvas->underline = 1; + else + ctxcanvas->underline = 0; + + if (style&CD_STRIKEOUT) + ctxcanvas->strikeover = 1; + else + ctxcanvas->strikeover = 0; + + return 1; +} + +static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix) +{ + PDF_setmatrix(ctxcanvas->pdf, 1, 0, 0, 1, 0, 0); + + /* default coordinate system is in points, change it to pixels. */ + PDF_scale(ctxcanvas->pdf, ctxcanvas->scale, ctxcanvas->scale); + + if (matrix) + { + PDF_concat(ctxcanvas->pdf, matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]); + } + else if (ctxcanvas->rotate_angle) + { + /* rotation = translate to point + rotation + translate back */ + PDF_translate(ctxcanvas->pdf, ctxcanvas->rotate_center_x, ctxcanvas->rotate_center_y); + PDF_rotate(ctxcanvas->pdf, (double)ctxcanvas->rotate_angle); + PDF_translate(ctxcanvas->pdf, -ctxcanvas->rotate_center_x, -ctxcanvas->rotate_center_y); + } +} + +/******************************************************/ +/* client images */ +/******************************************************/ + +static void cdputimagerectrgb(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int i, j, d, image, rw, rh, rgb_size; + char options[80]; + unsigned char* rgb_data; + + if (xmin<0 || ymin<0 || xmax-xmin+1>iw || ymax-ymin+1>ih) return; + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + + rgb_size = 3*rw*rh; + rgb_data = (unsigned char*)malloc(rgb_size); + if (!rgb_data) return; + + d = 0; + for (i=ymax; i>=ymin; i--) + for (j=xmin; j<=xmax; j++) + { + rgb_data[d] = r[i*iw+j]; d++; + rgb_data[d] = g[i*iw+j]; d++; + rgb_data[d] = b[i*iw+j]; d++; + } + + PDF_create_pvf(ctxcanvas->pdf, "cd_raw_rgb", 0, rgb_data, rgb_size, ""); + + sprintf(options, "width=%d height=%d components=3 bpc=8", rw, rh); + image = PDF_load_image(ctxcanvas->pdf, "raw", "cd_raw_rgb", 0, options); + + sprintf(options, "boxsize={%d %d} fitmethod=meet", w, h); + PDF_fit_image(ctxcanvas->pdf, image, x, y, options); + + PDF_delete_pvf(ctxcanvas->pdf, "cd_raw_rgb", 0); + free(rgb_data); +} + +static void cdputimagerectrgba(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, const unsigned char *a, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int i, j, d, image, image_mask, rw, rh, alpha_size, rgb_size; + char options[80]; + unsigned char *rgb_data, *alpha_data; + + if (xmin<0 || ymin<0 || xmax-xmin+1>iw || ymax-ymin+1>ih) return; + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + + rgb_size = 3*rw*rh; + rgb_data = (unsigned char*)malloc(rgb_size); + if (!rgb_data) return; + + d = 0; + for (i=ymax; i>=ymin; i--) + for (j=xmin; j<=xmax; j++) + { + rgb_data[d] = r[i*iw+j]; d++; + rgb_data[d] = g[i*iw+j]; d++; + rgb_data[d] = b[i*iw+j]; d++; + } + + alpha_size = rw*rh; + alpha_data = (unsigned char*)malloc(alpha_size); + if (!alpha_data) return; + + d = 0; + for (i=ymax; i>=ymin; i--) + for (j=xmin; j<=xmax; j++) + { + alpha_data[d] = a[i*iw+j]; d++; + } + + PDF_create_pvf(ctxcanvas->pdf, "cd_raw_rgb", 0, rgb_data, rgb_size, ""); + PDF_create_pvf(ctxcanvas->pdf, "cd_raw_alpha", 0, alpha_data, alpha_size, ""); + + sprintf(options, "width=%d height=%d components=1 bpc=8 imagewarning=true", rw, rh); + image_mask = PDF_load_image(ctxcanvas->pdf, "raw", "cd_raw_alpha", 0, options); + + sprintf(options, "width=%d height=%d components=3 bpc=8 masked=%d", rw, rh, image_mask); + image = PDF_load_image(ctxcanvas->pdf, "raw", "cd_raw_rgb", 0, options); + + sprintf(options, "boxsize={%d %d} fitmethod=meet", w, h); + PDF_fit_image(ctxcanvas->pdf, image, x, y, options); + + PDF_delete_pvf(ctxcanvas->pdf, "cd_raw_alpha", 0); + free(alpha_data); + PDF_delete_pvf(ctxcanvas->pdf, "cd_raw_rgb", 0); + free(rgb_data); +} + +static void cdputimagerectmap(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *index, const long int *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int i, j, d, rw, rh, image, rgb_size; + char options[80]; + unsigned char* rgb_data; + + if (xmin<0 || ymin<0 || xmax-xmin+1>iw || ymax-ymin+1>ih) return; + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + + rgb_size = 3*rw*rh; + rgb_data = (unsigned char*)malloc(rgb_size); + if (!rgb_data) return; + + d = 0; + for (i=ymax; i>=ymin; i--) + for (j=xmin; j<=xmax; j++) + { + unsigned char r, g, b; + cdDecodeColor(colors[index[i*iw+j]], &r, &g, &b); + rgb_data[d] = r; d++; + rgb_data[d] = g; d++; + rgb_data[d] = b; d++; + } + + PDF_create_pvf(ctxcanvas->pdf, "cd_raw_rgb", 0, rgb_data, rgb_size, ""); + + sprintf(options, "width=%d height=%d components=3 bpc=8", rw, rh); + image = PDF_load_image(ctxcanvas->pdf, "raw", "cd_raw_rgb", 0, options); + + sprintf(options, "boxsize={%d %d} fitmethod=meet", w, h); + PDF_fit_image(ctxcanvas->pdf, image, x, y, options); + + PDF_delete_pvf(ctxcanvas->pdf, "cd_raw_rgb", 0); + free(rgb_data); +} + +/******************************************************/ +/* server images */ +/******************************************************/ + +static void cdpixel(cdCtxCanvas *ctxcanvas, int x, int y, long int color) +{ + PDF_setcolor(ctxcanvas->pdf, "fill", "rgb", get_red(color), get_green(color), get_blue(color), 0); + + PDF_moveto(ctxcanvas->pdf, x, y); + PDF_circle(ctxcanvas->pdf, x, y, .5); + + PDF_fill(ctxcanvas->pdf); +} + +/******************************************************/ +/* custom attributes */ +/******************************************************/ + +static void set_poly_attrib(cdCtxCanvas *ctxcanvas, char* data) +{ + int hole; + + if (data == NULL) + { + ctxcanvas->holes = 0; + return; + } + + sscanf(data, "%d", &hole); + ctxcanvas->poly_holes[ctxcanvas->holes] = hole; + ctxcanvas->holes++; +} + +static char* get_poly_attrib(cdCtxCanvas *ctxcanvas) +{ + static char holes[10]; + sprintf(holes, "%d", ctxcanvas->holes); + return holes; +} + +static cdAttribute poly_attrib = +{ + "POLYHOLE", + set_poly_attrib, + get_poly_attrib +}; + +static void set_hatchboxsize_attrib(cdCtxCanvas *ctxcanvas, char* data) +{ + int hatchboxsize; + + if (data == NULL) + { + ctxcanvas->hatchboxsize = 8; + return; + } + + sscanf(data, "%d", &hatchboxsize); + ctxcanvas->hatchboxsize = hatchboxsize; +} + +static char* get_hatchboxsize_attrib(cdCtxCanvas *ctxcanvas) +{ + static char size[10]; + sprintf(size, "%d", ctxcanvas->hatchboxsize); + return size; +} + +static cdAttribute hatchboxsize_attrib = +{ + "HATCHBOXSIZE", + set_hatchboxsize_attrib, + get_hatchboxsize_attrib +}; + +static void set_rotate_attrib(cdCtxCanvas *ctxcanvas, char* data) +{ + /* ignore ROTATE if transform is set */ + if (ctxcanvas->canvas->use_matrix) + return; + + if (data) + { + sscanf(data, "%g %d %d", &ctxcanvas->rotate_angle, + &ctxcanvas->rotate_center_x, + &ctxcanvas->rotate_center_y); + } + else + { + ctxcanvas->rotate_angle = 0; + ctxcanvas->rotate_center_x = 0; + ctxcanvas->rotate_center_y = 0; + } + + PDF_setmatrix(ctxcanvas->pdf, 1, 0, 0, 1, 0, 0); + + if (ctxcanvas->rotate_angle) + { + /* rotation = translate to point + rotation + translate back */ + PDF_translate(ctxcanvas->pdf, ctxcanvas->rotate_center_x, ctxcanvas->rotate_center_y); + PDF_rotate(ctxcanvas->pdf, (double)ctxcanvas->rotate_angle); + PDF_translate(ctxcanvas->pdf, -ctxcanvas->rotate_center_x, -ctxcanvas->rotate_center_y); + } +} + +static char* get_rotate_attrib(cdCtxCanvas *ctxcanvas) +{ + static char data[100]; + + if (!ctxcanvas->rotate_angle) + return NULL; + + sprintf(data, "%g %d %d", (double)ctxcanvas->rotate_angle, + ctxcanvas->rotate_center_x, + ctxcanvas->rotate_center_y); + + return data; +} + +static cdAttribute rotate_attrib = +{ + "ROTATE", + set_rotate_attrib, + get_rotate_attrib +}; + +static void set_pattern_attrib(cdCtxCanvas *ctxcanvas, char* data) +{ + if (data) + { + int n, m; + sscanf(data, "%dx%d", &n, &m); + + PDF_suspend_page(ctxcanvas->pdf, ""); + ctxcanvas->pattern = PDF_begin_pattern(ctxcanvas->pdf, n, m, + ((double)n)*ctxcanvas->scale, ((double)m)*ctxcanvas->scale, 1); + PDF_scale(ctxcanvas->pdf, ctxcanvas->scale, ctxcanvas->scale); + } + else + { + PDF_end_pattern(ctxcanvas->pdf); + PDF_resume_page(ctxcanvas->pdf, ""); + ctxcanvas->canvas->interior_style = CD_PATTERN; + } +} + +static cdAttribute pattern_attrib = +{ + "PATTERN", + set_pattern_attrib, + NULL +}; + +static void set_opacity_attrib(cdCtxCanvas *ctxcanvas, char* data) +{ + int state; + + if (data) + { + sscanf(data, "%d", &ctxcanvas->opacity); + if (ctxcanvas->opacity < 0) ctxcanvas->opacity = 0; + if (ctxcanvas->opacity > 255) ctxcanvas->opacity = 255; + } + else + ctxcanvas->opacity = 255; + + /* reuse the extended graphics state if the opacity is the same */ + if (ctxcanvas->opacity_states[ctxcanvas->opacity] == -1) + { + char options[50]; + sprintf(options, "opacityfill=%g opacitystroke=%g", ctxcanvas->opacity/255.0, ctxcanvas->opacity/255.0); + state = PDF_create_gstate(ctxcanvas->pdf, options); + ctxcanvas->opacity_states[ctxcanvas->opacity] = state; + } + else + state = ctxcanvas->opacity_states[ctxcanvas->opacity]; + + PDF_set_gstate(ctxcanvas->pdf, state); +} + +static char* get_opacity_attrib(cdCtxCanvas *ctxcanvas) +{ + static char data[50]; + sprintf(data, "%d", ctxcanvas->opacity); + return data; +} + +static cdAttribute opacity_attrib = +{ + "OPACITY", + set_opacity_attrib, + get_opacity_attrib +}; + +static char* get_pdf_attrib(cdCtxCanvas *ctxcanvas) +{ + return (char*)ctxcanvas->pdf; +} + +static cdAttribute pdf_attrib = +{ + "PDF", + NULL, + get_pdf_attrib +}; + +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + char *line = (char *)data; + cdCtxCanvas *ctxcanvas; + char filename[10240] = ""; + + ctxcanvas = (cdCtxCanvas *)malloc(sizeof(cdCtxCanvas)); + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + + line += cdGetFileName(line, filename); + if (filename[0] == 0) + return; + + ctxcanvas->pdf = PDF_new(); + if (!ctxcanvas->pdf) + { + free(ctxcanvas); + return; + } + + if (PDF_begin_document(ctxcanvas->pdf, filename, 0, "") == -1) + { + PDF_delete(ctxcanvas->pdf); + free(ctxcanvas); + return; + } + + PDF_set_parameter(ctxcanvas->pdf, "fontwarning", "false"); + PDF_set_parameter(ctxcanvas->pdf, "errorpolicy", "return"); + + cdRegisterAttribute(canvas, &poly_attrib); + cdRegisterAttribute(canvas, &hatchboxsize_attrib); + cdRegisterAttribute(canvas, &rotate_attrib); + cdRegisterAttribute(canvas, &opacity_attrib); + cdRegisterAttribute(canvas, &pattern_attrib); + cdRegisterAttribute(canvas, &pdf_attrib); + + setpdfdefaultvalues(ctxcanvas); + + while (*line != '\0') + { + while (*line != '\0' && *line != '-') + line++; + + if (*line != '\0') + { + float num; + line++; + switch (*line++) + { + case 'p': + { + int paper; + sscanf(line, "%d", &paper); + setpdfpapersize(ctxcanvas, paper); + break; + } + case 'w': + sscanf(line, "%g", &num); + ctxcanvas->width_mm = num; + ctxcanvas->width_pt = CD_MM2PT*ctxcanvas->width_mm; + break; + case 'h': + sscanf(line, "%g", &num); + ctxcanvas->height_mm = num; + ctxcanvas->height_pt = CD_MM2PT*ctxcanvas->height_mm; + break; + case 's': + sscanf(line, "%d", &(ctxcanvas->res)); + break; + case 'o': + ctxcanvas->landscape = 1; + break; + } + } + + while (*line != '\0' && *line != ' ') + line++; + } + + /* store the base canvas */ + ctxcanvas->canvas = canvas; + + /* update canvas context */ + canvas->ctxcanvas = ctxcanvas; + + if (ctxcanvas->landscape == 1) + { + _cdSwapDouble(ctxcanvas->width_pt, ctxcanvas->height_pt); + _cdSwapDouble(ctxcanvas->width_mm, ctxcanvas->height_mm); + } + + init_pdf(ctxcanvas); +} + +static void cdinittable(cdCanvas* canvas) +{ + canvas->cxFlush = cdflush; + canvas->cxPixel = cdpixel; + canvas->cxLine = cdline; + canvas->cxPoly = cdpoly; + canvas->cxRect = cdrect; + canvas->cxBox = cdbox; + canvas->cxArc = cdarc; + canvas->cxSector = cdsector; + canvas->cxChord = cdchord; + canvas->cxText = cdtext; + canvas->cxFLine = cdfline; + canvas->cxFPoly = cdfpoly; + canvas->cxFRect = cdfrect; + canvas->cxFBox = cdfbox; + canvas->cxFArc = cdfarc; + canvas->cxFSector = cdfsector; + canvas->cxFChord = cdfchord; + canvas->cxFText = cdftext; + canvas->cxGetFontDim = cdgetfontdim; + canvas->cxGetTextSize = cdgettextsize; + canvas->cxPutImageRectRGB = cdputimagerectrgb; + canvas->cxPutImageRectMap = cdputimagerectmap; + canvas->cxPutImageRectRGBA = cdputimagerectrgba; + + canvas->cxClip = cdclip; + canvas->cxClipArea = cdcliparea; + canvas->cxFClipArea = cdfcliparea; + canvas->cxLineStyle = cdlinestyle; + canvas->cxLineWidth = cdlinewidth; + canvas->cxLineCap = cdlinecap; + canvas->cxLineJoin = cdlinejoin; + canvas->cxPattern = cdpattern; + canvas->cxStipple = cdstipple; + canvas->cxHatch = cdhatch; + canvas->cxFont = cdfont; + canvas->cxTransform = cdtransform; + + canvas->cxKillCanvas = cdkillcanvas; +} + +static cdContext cdPDFContext = +{ + CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_PLAY | CD_CAP_PALETTE | + CD_CAP_REGION | CD_CAP_IMAGESRV | CD_CAP_TEXTSIZE | + CD_CAP_BACKGROUND | CD_CAP_BACKOPACITY | CD_CAP_WRITEMODE | + CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB), + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + +cdContext* cdContextPDF(void) +{ + return &cdPDFContext; +} + +/* +p.set_info("Creator", "PDFlib Cookbook") +*/ diff --git a/src/drv/cdpicture.c b/src/drv/cdpicture.c new file mode 100644 index 0000000..9bc5104 --- /dev/null +++ b/src/drv/cdpicture.c @@ -0,0 +1,1133 @@ +/** \file + * \brief CD Picture driver + * + * See Copyright Notice in cd.h + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <math.h> + +#include "cd.h" +#include "cd_private.h" +#include "cdpicture.h" + + +/* codes for the primitives. +*/ +typedef enum _tPrim +{ + CDPIC_LINE, + CDPIC_RECT, + CDPIC_BOX, + CDPIC_ARC, + CDPIC_SECTOR, + CDPIC_CHORD, + CDPIC_TEXT, + CDPIC_POLY, + CDPIC_FLINE, + CDPIC_FRECT, + CDPIC_FBOX, + CDPIC_FARC, + CDPIC_FSECTOR, + CDPIC_FCHORD, + CDPIC_FTEXT, + CDPIC_FPOLY, + CDPIC_PIXEL, + CDPIC_IMAGEMAP, + CDPIC_IMAGERGB, + CDPIC_IMAGERGBA, +} tPrim; + +typedef struct _tFillAttrib +{ + long foreground, background; + int back_opacity; + int interior_style, hatch_style; + int fill_mode; + int pattern_w, pattern_h; + long* pattern; + int stipple_w, stipple_h; + unsigned char* stipple; +} tFillAttrib; + +typedef struct _tLineAttrib +{ + long foreground, background; + int back_opacity; + int line_style, line_width; + int line_cap, line_join; + int* line_dashes; + int line_dashes_count; +} tLineAttrib; + +typedef struct _tTextAttrib +{ + long foreground; + char* font_type_face; + int font_style, font_size; + int text_alignment; + double text_orientation; + char* native_font; +} tTextAttrib; + +typedef struct _tLBR +{ + int x1, y1, x2, y2; +} tLBR; /* Line or Box or Rect */ + +typedef struct _tfLBR +{ + double x1, y1, x2, y2; +} tfLBR; /* Line or Box or Rect */ + +typedef struct _tASC +{ + int xc, yc, w, h; + double angle1, angle2; +} tASC; /* Arc or Sector or Chord */ + +typedef struct _tfASC +{ + double xc, yc, w, h; + double angle1, angle2; +} tfASC; /* Arc or Sector or Chord */ + +typedef struct _tPoly +{ + int mode; + int n; + cdPoint* points; +} tPoly; /* Begin, Vertex and End */ + +typedef struct _tfPoly +{ + int mode; + int n; + cdfPoint* points; +} tfPoly; /* Begin, Vertex and End */ + +typedef struct _tText +{ + int x, y; + char *s; +} tText; /* Text */ + +typedef struct _tfText +{ + double x, y; + char *s; +} tfText; /* Text */ + +typedef struct _tPixel +{ + int x, y; + long color; +} tPixel; /* Pixel */ + +typedef struct _tImageMap +{ + int iw, ih; + unsigned char *index; + long int *colors; + int x, y, w, h; +} tImageMap; + +typedef struct _tImageRGBA +{ + int iw, ih; + unsigned char *r; + unsigned char *g; + unsigned char *b; + unsigned char *a; + int x, y, w, h; +} tImageRGBA; + +typedef struct _tPrimNode +{ + tPrim type; + void* param_buffer; /* dinamically allocated memory for the parameter */ + union { + tLBR lineboxrect; + tfLBR lineboxrectf; + tASC arcsectorchord; + tfASC arcsectorchordf; + tPoly poly; + tfPoly polyf; + tText text; + tfText textf; + tPixel pixel; + tImageMap imagemap; + tImageRGBA imagergba; + } param; + void* attrib_buffer; /* dinamically allocated memory for the attributes */ + union { + tLineAttrib line; + tFillAttrib fill; + tTextAttrib text; + } attrib; + struct _tPrimNode *next; +} tPrimNode; + +struct _cdCtxCanvas +{ + cdCanvas* canvas; + + /* primitives list */ + tPrimNode *prim_first, + *prim_last; + int prim_n; + + /* bounding box */ + int xmin, xmax, + ymin, ymax; +}; + +static void picUpdateSize(cdCtxCanvas *ctxcanvas) +{ + ctxcanvas->canvas->w = ctxcanvas->xmax-ctxcanvas->xmin+1; + ctxcanvas->canvas->h = ctxcanvas->ymax-ctxcanvas->ymin+1; + ctxcanvas->canvas->w_mm = ((double)ctxcanvas->canvas->w) / ctxcanvas->canvas->xres; + ctxcanvas->canvas->h_mm = ((double)ctxcanvas->canvas->h) / ctxcanvas->canvas->yres; +} + +static void picUpdateBBox(cdCtxCanvas *ctxcanvas, int x, int y, int ew) +{ + if (x+ew > ctxcanvas->xmax) + ctxcanvas->xmax = x+ew; + if (y+ew > ctxcanvas->ymax) + ctxcanvas->ymax = y+ew; + if (x-ew < ctxcanvas->xmin) + ctxcanvas->xmin = x-ew; + if (y-ew < ctxcanvas->ymin) + ctxcanvas->ymin = y-ew; + + picUpdateSize(ctxcanvas); +} + +static void picUpdateBBoxF(cdCtxCanvas *ctxcanvas, double x, double y, int ew) +{ + if ((int)ceil(x+ew) > ctxcanvas->xmax) + ctxcanvas->xmax = (int)ceil(x+ew); + if ((int)ceil(y+ew) > ctxcanvas->ymax) + ctxcanvas->ymax = (int)ceil(y+ew); + if ((int)floor(x-ew) < ctxcanvas->xmin) + ctxcanvas->xmin = (int)floor(x-ew); + if ((int)floor(y-ew) < ctxcanvas->ymin) + ctxcanvas->ymin = (int)floor(y-ew); + + picUpdateSize(ctxcanvas); +} + +static void picAddPrim(cdCtxCanvas *ctxcanvas, tPrimNode *prim) +{ + if (ctxcanvas->prim_n == 0) + ctxcanvas->prim_first = prim; + else + ctxcanvas->prim_last->next = prim; + + ctxcanvas->prim_last = prim; + ctxcanvas->prim_n++; +} + +static tPrimNode* primCreate(tPrim type) +{ + tPrimNode *prim = malloc(sizeof(tPrimNode)); + memset(prim, 0, sizeof(tPrimNode)); + prim->type = type; + return prim; +} + +static void primDestroy(tPrimNode *prim) +{ + if (prim->param_buffer) + free(prim->param_buffer); + if (prim->attrib_buffer) + free(prim->attrib_buffer); + free(prim); +} + +static void primAddAttrib_Line(tPrimNode *prim, cdCanvas *canvas) +{ + prim->attrib.line.foreground = canvas->foreground; + prim->attrib.line.background = canvas->background; + prim->attrib.line.back_opacity = canvas->back_opacity; + prim->attrib.line.line_style = canvas->line_style; + prim->attrib.line.line_width = canvas->line_width; + prim->attrib.line.line_cap = canvas->line_cap; + prim->attrib.line.line_join = canvas->line_join; + + if (canvas->line_style==CD_CUSTOM && canvas->line_dashes) + { + prim->attrib.line.line_dashes_count = canvas->line_dashes_count; + prim->attrib_buffer = malloc(canvas->line_dashes_count*sizeof(int)); + prim->attrib.line.line_dashes = prim->attrib_buffer; + memcpy(prim->attrib.line.line_dashes, canvas->line_dashes, canvas->line_dashes_count*sizeof(int)); + } +} + +static void primAddAttrib_Fill(tPrimNode *prim, cdCanvas *canvas) +{ + prim->attrib.fill.foreground = canvas->foreground; + prim->attrib.fill.background = canvas->background; + prim->attrib.fill.back_opacity = canvas->back_opacity; + prim->attrib.fill.interior_style = canvas->interior_style; + prim->attrib.fill.hatch_style = canvas->hatch_style; + prim->attrib.fill.fill_mode = canvas->fill_mode; + prim->attrib.fill.pattern_w = canvas->pattern_w; + prim->attrib.fill.pattern_h = canvas->pattern_h; + prim->attrib.fill.stipple_w = canvas->stipple_w; + prim->attrib.fill.stipple_h = canvas->stipple_h; + + if (canvas->interior_style==CD_PATTERN && canvas->pattern) + { + prim->attrib_buffer = malloc(canvas->pattern_size*sizeof(long)); + prim->attrib.fill.pattern = prim->attrib_buffer; + memcpy(prim->attrib.fill.pattern, canvas->pattern, canvas->pattern_size*sizeof(long)); + } + + if (canvas->interior_style==CD_STIPPLE && canvas->stipple) + { + prim->attrib_buffer = malloc(canvas->stipple_size*sizeof(long)); + prim->attrib.fill.stipple = prim->attrib_buffer; + memcpy(prim->attrib.fill.stipple, canvas->stipple, canvas->stipple_size*sizeof(long)); + } +} + +static void primAddAttrib_Text(tPrimNode *prim, cdCanvas *canvas) +{ + prim->attrib.text.foreground = canvas->foreground; + + prim->attrib.text.font_style = canvas->font_style; + prim->attrib.text.font_size = canvas->font_size; + prim->attrib.text.text_alignment = canvas->text_alignment; + prim->attrib.text.text_orientation = canvas->text_orientation; + + if (canvas->native_font[0]) + { + prim->attrib_buffer = strdup(canvas->native_font); + prim->attrib.text.native_font = prim->attrib_buffer; + } + else + { + prim->attrib_buffer = strdup(canvas->font_type_face); + prim->attrib.text.font_type_face = prim->attrib_buffer; + } +} + +static void primUpdateAttrib_Line(tPrimNode *prim, cdCanvas *canvas) +{ + cdCanvasSetBackground(canvas, prim->attrib.line.background); + cdCanvasSetForeground(canvas, prim->attrib.line.foreground); + cdCanvasBackOpacity(canvas, prim->attrib.line.back_opacity); + cdCanvasLineStyle(canvas, prim->attrib.line.line_style); + cdCanvasLineWidth(canvas, prim->attrib.line.line_width); + cdCanvasLineCap(canvas, prim->attrib.line.line_cap); + cdCanvasLineJoin(canvas, prim->attrib.line.line_join); + + if (prim->attrib.line.line_style==CD_CUSTOM && prim->attrib.line.line_dashes) + cdCanvasLineStyleDashes(canvas, prim->attrib.line.line_dashes, prim->attrib.line.line_dashes_count); +} + +void primUpdateAttrib_Fill(tPrimNode *prim, cdCanvas *canvas) +{ + cdCanvasSetBackground(canvas, prim->attrib.fill.background); + cdCanvasSetForeground(canvas, prim->attrib.fill.foreground); + cdCanvasBackOpacity(canvas, prim->attrib.fill.back_opacity); + cdCanvasFillMode(canvas, prim->attrib.fill.fill_mode); + + if (prim->attrib.fill.interior_style==CD_HATCH) + cdCanvasHatch(canvas, prim->attrib.fill.hatch_style); + else if (prim->attrib.fill.interior_style==CD_PATTERN && prim->attrib.fill.pattern) + cdCanvasPattern(canvas, prim->attrib.fill.pattern_w, prim->attrib.fill.pattern_h, prim->attrib.fill.pattern); + else if (prim->attrib.fill.interior_style==CD_STIPPLE && prim->attrib.fill.stipple) + cdCanvasStipple(canvas, prim->attrib.fill.stipple_w, prim->attrib.fill.stipple_h, prim->attrib.fill.stipple); + + cdCanvasInteriorStyle(canvas, prim->attrib.fill.interior_style); +} + +void primUpdateAttrib_Text(tPrimNode *prim, cdCanvas *canvas) +{ + cdCanvasSetForeground(canvas, prim->attrib.text.foreground); + cdCanvasTextAlignment(canvas, prim->attrib.text.text_alignment); + cdCanvasTextOrientation(canvas, prim->attrib.text.text_orientation); + + if (canvas->native_font[0]) + cdCanvasNativeFont(canvas, prim->attrib.text.native_font); + else + cdCanvasFont(canvas, prim->attrib.text.font_type_face, prim->attrib.text.font_style, prim->attrib.text.font_size); +} + +static void cdclear(cdCtxCanvas *ctxcanvas) +{ + tPrimNode *prim; + int i; + for (i = 0; i < ctxcanvas->prim_n; i++) + { + prim = ctxcanvas->prim_first; + ctxcanvas->prim_first = prim->next; + + primDestroy(prim); + } + + ctxcanvas->prim_n = 0; + ctxcanvas->prim_first = NULL; + ctxcanvas->prim_last = NULL; +} + +static void cdpixel(cdCtxCanvas *ctxcanvas, int x, int y, long int color) +{ + tPrimNode *prim = primCreate(CDPIC_PIXEL); + prim->param.pixel.x = x; + prim->param.pixel.y = y; + prim->param.pixel.color = color; + picAddPrim(ctxcanvas, prim); + picUpdateBBox(ctxcanvas, x, y, 0); +} + +static void cdline(cdCtxCanvas *ctxcanvas, int x1, int y1, int x2, int y2) +{ + tPrimNode *prim = primCreate(CDPIC_LINE); + primAddAttrib_Line(prim, ctxcanvas->canvas); + prim->param.lineboxrect.x1 = x1; + prim->param.lineboxrect.y1 = y1; + prim->param.lineboxrect.x2 = x2; + prim->param.lineboxrect.y2 = y2; + picAddPrim(ctxcanvas, prim); + picUpdateBBox(ctxcanvas, x1, y1, ctxcanvas->canvas->line_width); + picUpdateBBox(ctxcanvas, x2, y2, ctxcanvas->canvas->line_width); +} + +static void cdfline(cdCtxCanvas *ctxcanvas, double x1, double y1, double x2, double y2) +{ + tPrimNode *prim = primCreate(CDPIC_FLINE); + primAddAttrib_Line(prim, ctxcanvas->canvas); + prim->param.lineboxrectf.x1 = x1; + prim->param.lineboxrectf.y1 = y1; + prim->param.lineboxrectf.x2 = x2; + prim->param.lineboxrectf.y2 = y2; + picAddPrim(ctxcanvas, prim); + picUpdateBBoxF(ctxcanvas, x1, y1, ctxcanvas->canvas->line_width); + picUpdateBBoxF(ctxcanvas, x2, y2, ctxcanvas->canvas->line_width); +} + +static void cdrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + tPrimNode *prim = primCreate(CDPIC_RECT); + primAddAttrib_Line(prim, ctxcanvas->canvas); + prim->param.lineboxrect.x1 = xmin; + prim->param.lineboxrect.y1 = ymin; + prim->param.lineboxrect.x2 = xmax; + prim->param.lineboxrect.y2 = ymax; + picAddPrim(ctxcanvas, prim); + picUpdateBBox(ctxcanvas, xmin, ymin, ctxcanvas->canvas->line_width); + picUpdateBBox(ctxcanvas, xmax, ymax, ctxcanvas->canvas->line_width); +} + +static void cdfrect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + tPrimNode *prim = primCreate(CDPIC_FRECT); + primAddAttrib_Line(prim, ctxcanvas->canvas); + prim->param.lineboxrectf.x1 = xmin; + prim->param.lineboxrectf.y1 = ymin; + prim->param.lineboxrectf.x2 = xmax; + prim->param.lineboxrectf.y2 = ymax; + picAddPrim(ctxcanvas, prim); + picUpdateBBoxF(ctxcanvas, xmin, ymin, ctxcanvas->canvas->line_width); + picUpdateBBoxF(ctxcanvas, xmax, ymax, ctxcanvas->canvas->line_width); +} + +static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + tPrimNode *prim = primCreate(CDPIC_BOX); + primAddAttrib_Fill(prim, ctxcanvas->canvas); + prim->param.lineboxrect.x1 = xmin; + prim->param.lineboxrect.y1 = ymin; + prim->param.lineboxrect.x2 = xmax; + prim->param.lineboxrect.y2 = ymax; + picAddPrim(ctxcanvas, prim); + picUpdateBBox(ctxcanvas, xmin, ymin, 0); + picUpdateBBox(ctxcanvas, xmax, ymax, 0); +} + +static void cdfbox(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + tPrimNode *prim = primCreate(CDPIC_FBOX); + primAddAttrib_Fill(prim, ctxcanvas->canvas); + prim->param.lineboxrectf.x1 = xmin; + prim->param.lineboxrectf.y1 = ymin; + prim->param.lineboxrectf.x2 = xmax; + prim->param.lineboxrectf.y2 = ymax; + picAddPrim(ctxcanvas, prim); + picUpdateBBoxF(ctxcanvas, xmin, ymin, 0); + picUpdateBBoxF(ctxcanvas, xmax, ymax, 0); +} + +static void cdarc(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + int xmin, xmax, ymin, ymax; + tPrimNode *prim = primCreate(CDPIC_ARC); + primAddAttrib_Line(prim, ctxcanvas->canvas); + prim->param.arcsectorchord.xc = xc; + prim->param.arcsectorchord.yc = yc; + prim->param.arcsectorchord.w = w; + prim->param.arcsectorchord.h = h; + prim->param.arcsectorchord.angle1 = a1; + prim->param.arcsectorchord.angle2 = a2; + picAddPrim(ctxcanvas, prim); + cdCanvasGetEllipseBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax); + picUpdateBBox(ctxcanvas, xmin, ymin, ctxcanvas->canvas->line_width); + picUpdateBBox(ctxcanvas, xmax, ymax, ctxcanvas->canvas->line_width); +} + +static void cdfarc(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + int xmin, xmax, ymin, ymax; + tPrimNode *prim = primCreate(CDPIC_FARC); + primAddAttrib_Line(prim, ctxcanvas->canvas); + prim->param.arcsectorchordf.xc = xc; + prim->param.arcsectorchordf.yc = yc; + prim->param.arcsectorchordf.w = w; + prim->param.arcsectorchordf.h = h; + prim->param.arcsectorchordf.angle1 = a1; + prim->param.arcsectorchordf.angle2 = a2; + picAddPrim(ctxcanvas, prim); + cdCanvasGetEllipseBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax); + picUpdateBBox(ctxcanvas, xmin, ymin, ctxcanvas->canvas->line_width); + picUpdateBBox(ctxcanvas, xmax, ymax, ctxcanvas->canvas->line_width); +} + +static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + int xmin, xmax, ymin, ymax; + tPrimNode *prim = primCreate(CDPIC_SECTOR); + primAddAttrib_Fill(prim, ctxcanvas->canvas); + prim->param.arcsectorchord.xc = xc; + prim->param.arcsectorchord.yc = yc; + prim->param.arcsectorchord.w = w; + prim->param.arcsectorchord.h = h; + prim->param.arcsectorchord.angle1 = a1; + prim->param.arcsectorchord.angle2 = a2; + picAddPrim(ctxcanvas, prim); + cdCanvasGetEllipseBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax); + picUpdateBBox(ctxcanvas, xmin, ymin, 0); + picUpdateBBox(ctxcanvas, xmax, ymax, 0); + picUpdateBBox(ctxcanvas, xc, yc, 0); +} + +static void cdfsector(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + int xmin, xmax, ymin, ymax; + tPrimNode *prim = primCreate(CDPIC_FSECTOR); + primAddAttrib_Fill(prim, ctxcanvas->canvas); + prim->param.arcsectorchordf.xc = xc; + prim->param.arcsectorchordf.yc = yc; + prim->param.arcsectorchordf.w = w; + prim->param.arcsectorchordf.h = h; + prim->param.arcsectorchordf.angle1 = a1; + prim->param.arcsectorchordf.angle2 = a2; + picAddPrim(ctxcanvas, prim); + cdCanvasGetEllipseBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax); + picUpdateBBox(ctxcanvas, xmin, ymin, 0); + picUpdateBBox(ctxcanvas, xmax, ymax, 0); + picUpdateBBox(ctxcanvas, _cdRound(xc), _cdRound(yc), 0); +} + +static void cdchord(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + int xmin, xmax, ymin, ymax; + tPrimNode *prim = primCreate(CDPIC_CHORD); + primAddAttrib_Fill(prim, ctxcanvas->canvas); + prim->param.arcsectorchord.xc = xc; + prim->param.arcsectorchord.yc = yc; + prim->param.arcsectorchord.w = w; + prim->param.arcsectorchord.h = h; + prim->param.arcsectorchord.angle1 = a1; + prim->param.arcsectorchord.angle2 = a2; + picAddPrim(ctxcanvas, prim); + cdCanvasGetEllipseBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax); + picUpdateBBox(ctxcanvas, xmin, ymin, 0); + picUpdateBBox(ctxcanvas, xmax, ymax, 0); +} + +static void cdfchord(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + int xmin, xmax, ymin, ymax; + tPrimNode *prim = primCreate(CDPIC_FCHORD); + primAddAttrib_Fill(prim, ctxcanvas->canvas); + prim->param.arcsectorchordf.xc = xc; + prim->param.arcsectorchordf.yc = yc; + prim->param.arcsectorchordf.w = w; + prim->param.arcsectorchordf.h = h; + prim->param.arcsectorchordf.angle1 = a1; + prim->param.arcsectorchordf.angle2 = a2; + picAddPrim(ctxcanvas, prim); + cdCanvasGetEllipseBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax); + picUpdateBBox(ctxcanvas, xmin, ymin, 0); + picUpdateBBox(ctxcanvas, xmax, ymax, 0); +} + +static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *text) +{ + int xmin, xmax, ymin, ymax; + tPrimNode *prim = primCreate(CDPIC_TEXT); + primAddAttrib_Text(prim, ctxcanvas->canvas); + prim->param.text.x = x; + prim->param.text.y = y; + prim->param.text.s = strdup(text); + prim->param_buffer = prim->param.text.s; + picAddPrim(ctxcanvas, prim); + cdCanvasGetTextBox(ctxcanvas->canvas, x, y, text, &xmin, &xmax, &ymin, &ymax); + picUpdateBBox(ctxcanvas, xmin, ymin, 0); + picUpdateBBox(ctxcanvas, xmax, ymax, 0); +} + +static void cdftext(cdCtxCanvas *ctxcanvas, double x, double y, const char *text) +{ + int xmin, xmax, ymin, ymax; + tPrimNode *prim = primCreate(CDPIC_FTEXT); + primAddAttrib_Text(prim, ctxcanvas->canvas); + prim->param.textf.x = x; + prim->param.textf.y = y; + prim->param.textf.s = strdup(text); + prim->param_buffer = prim->param.textf.s; + picAddPrim(ctxcanvas, prim); + cdCanvasGetTextBox(ctxcanvas->canvas, _cdRound(x), _cdRound(y), text, &xmin, &xmax, &ymin, &ymax); + picUpdateBBox(ctxcanvas, xmin, ymin, 0); + picUpdateBBox(ctxcanvas, xmax, ymax, 0); +} + +static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n) +{ + int i; + tPrimNode *prim; + if (mode == CD_CLIP || mode == CD_REGION) return; + prim = primCreate(CDPIC_POLY); + if (mode == CD_FILL) + primAddAttrib_Fill(prim, ctxcanvas->canvas); + else + primAddAttrib_Line(prim, ctxcanvas->canvas); + prim->param.poly.n = n; + prim->param.poly.points = malloc(n * sizeof(cdPoint)); + memcpy(prim->param.poly.points, poly, n * sizeof(cdPoint)); + prim->param_buffer = prim->param.poly.points; + picAddPrim(ctxcanvas, prim); + + for (i = 0; i < n; i++) + { + if (mode == CD_FILL) + picUpdateBBox(ctxcanvas, poly[i].x, poly[i].y, 0); + else + picUpdateBBox(ctxcanvas, poly[i].x, poly[i].y, ctxcanvas->canvas->line_width); + } +} + +static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n) +{ + int i; + tPrimNode *prim; + if (mode == CD_CLIP || mode == CD_REGION) return; + prim = primCreate(CDPIC_FPOLY); + if (mode == CD_FILL) + primAddAttrib_Fill(prim, ctxcanvas->canvas); + else + primAddAttrib_Line(prim, ctxcanvas->canvas); + prim->param.polyf.n = n; + prim->param.polyf.points = malloc(n * sizeof(cdPoint)); + memcpy(prim->param.polyf.points, poly, n * sizeof(cdPoint)); + prim->param_buffer = prim->param.polyf.points; + picAddPrim(ctxcanvas, prim); + + for (i = 0; i < n; i++) + { + if (mode == CD_FILL) + picUpdateBBox(ctxcanvas, _cdRound(poly[i].x), _cdRound(poly[i].y), 0); + else + picUpdateBBox(ctxcanvas, _cdRound(poly[i].x), _cdRound(poly[i].y), ctxcanvas->canvas->line_width); + } +} + +static void cdputimagerectrgb(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int l, offset, size; + unsigned char *dr, *dg, *db; + + tPrimNode *prim = primCreate(CDPIC_IMAGERGB); + prim->param.imagergba.iw = xmax-xmin+1; + prim->param.imagergba.ih = ymax-ymin+1; + prim->param.imagergba.x = x; + prim->param.imagergba.y = y; + prim->param.imagergba.w = w; + prim->param.imagergba.h = h; + + size = prim->param.imagergba.iw*prim->param.imagergba.ih; + prim->param_buffer = malloc(3*size); + prim->param.imagergba.r = prim->param_buffer; + prim->param.imagergba.g = prim->param.imagergba.r + size; + prim->param.imagergba.b = prim->param.imagergba.g + size; + + offset = ymin*iw + xmin; + r += offset; + g += offset; + b += offset; + + dr = prim->param.imagergba.r; + dg = prim->param.imagergba.g; + db = prim->param.imagergba.b; + offset = prim->param.imagergba.iw; + + for (l = ymin; l <= ymax; l++) + { + memcpy(dr, r, offset); + memcpy(dg, g, offset); + memcpy(db, b, offset); + + r += iw; + g += iw; + b += iw; + dr += offset; + dg += offset; + db += offset; + } + + picUpdateBBox(ctxcanvas, x, y, 0); + picUpdateBBox(ctxcanvas, x+prim->param.imagergba.iw-1, y+prim->param.imagergba.ih-1, 0); +} + +static void cdputimagerectrgba(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, const unsigned char *a, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int l, offset, size; + unsigned char *dr, *dg, *db, *da; + + tPrimNode *prim = primCreate(CDPIC_IMAGERGBA); + prim->param.imagergba.iw = xmax-xmin+1; + prim->param.imagergba.ih = ymax-ymin+1; + prim->param.imagergba.x = x; + prim->param.imagergba.y = y; + prim->param.imagergba.w = w; + prim->param.imagergba.h = h; + + size = prim->param.imagergba.iw*prim->param.imagergba.ih; + prim->param_buffer = malloc(4*size); + prim->param.imagergba.r = prim->param_buffer; + prim->param.imagergba.g = prim->param.imagergba.r + size; + prim->param.imagergba.b = prim->param.imagergba.g + size; + prim->param.imagergba.a = prim->param.imagergba.b + size; + + offset = ymin*iw + xmin; + r += offset; + g += offset; + b += offset; + a += offset; + + dr = prim->param.imagergba.r; + dg = prim->param.imagergba.g; + db = prim->param.imagergba.b; + da = prim->param.imagergba.a; + offset = prim->param.imagergba.iw; + + for (l = ymin; l <= ymax; l++) + { + memcpy(dr, r, offset); + memcpy(dg, g, offset); + memcpy(db, b, offset); + memcpy(da, a, offset); + + r += iw; + g += iw; + b += iw; + a += iw; + dr += offset; + dg += offset; + db += offset; + da += offset; + } + + picUpdateBBox(ctxcanvas, x, y, 0); + picUpdateBBox(ctxcanvas, x+prim->param.imagergba.iw-1, y+prim->param.imagergba.ih-1, 0); +} + +static void cdputimagerectmap(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *index, const long int *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int c, l, n = 0, offset, size; + unsigned char *dindex; + long *dcolors; + + tPrimNode *prim = primCreate(CDPIC_IMAGEMAP); + prim->param.imagemap.iw = xmax-xmin+1; + prim->param.imagemap.ih = ymax-ymin+1; + prim->param.imagemap.x = x; + prim->param.imagemap.y = y; + prim->param.imagemap.w = w; + prim->param.imagemap.h = h; + + size = prim->param.imagemap.iw*prim->param.imagemap.ih; + prim->param_buffer = malloc(size + 256); + prim->param.imagemap.index = prim->param_buffer; + prim->param.imagemap.colors = (long*)(prim->param.imagemap.index + size); + + offset = ymin*iw + xmin; + index += offset; + + dindex = prim->param.imagemap.index; + dcolors = prim->param.imagemap.colors; + offset = iw - prim->param.imagemap.iw; + + for (l = ymin; l <= ymax; l++) + { + for (c = xmin; c <= xmax; c++) + { + if (*index > n) + n = *index; + + *dindex++ = *index++; + } + + index += offset; + } + + n++; + + for (c = 0; c < n; c++) + dcolors[c] = colors[c]; + + picUpdateBBox(ctxcanvas, x, y, 0); + picUpdateBBox(ctxcanvas, x+prim->param.imagemap.iw-1, y+prim->param.imagemap.ih-1, 0); +} + + +/**********/ +/* cdPlay */ +/**********/ + +typedef int(*_cdsizecb)(cdCanvas* canvas, int w, int h, double w_mm, double h_mm); +static _cdsizecb cdsizecb = NULL; + +static int cdregistercallback(int cb, cdCallback func) +{ + switch (cb) + { + case CD_SIZECB: + cdsizecb = (_cdsizecb)func; + return CD_OK; + } + + return CD_ERROR; +} + +#define sMin1(_v) (_v == 0? 1: _v) + +#define sScaleX(_x) cdRound((_x - pic_xmin) * factorX + xmin) +#define sScaleY(_y) cdRound((_y - pic_ymin) * factorY + ymin) +#define sScaleW(_w) sMin1(cdRound(_w * factorX)) +#define sScaleH(_h) sMin1(cdRound(_h * factorY)) + +#define sfScaleX(_x) ((_x - pic_xmin) * factorX + xmin) +#define sfScaleY(_y) ((_y - pic_ymin) * factorY + ymin) +#define sfScaleW(_w) (_w * factorX) +#define sfScaleH(_h) (_h * factorY) + +static int cdplay(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax, void *data) +{ + tPrimNode *prim; + cdCanvas* pic_canvas = (cdCanvas*)data; + cdCtxCanvas* ctxcanvas = pic_canvas->ctxcanvas; + int p, i, scale = 0, + pic_xmin = ctxcanvas->xmin, + pic_ymin = ctxcanvas->ymin; + double factorX = 1, factorY = 1; + + if ((ctxcanvas->xmax-ctxcanvas->xmin)!=0 && + (ctxcanvas->ymax-ctxcanvas->ymin)!=0 && + (xmax-xmin)!=0 && + (ymax-ymin)!=0) + { + scale = 1; + factorX = ((double)(xmax-xmin)) / (ctxcanvas->xmax-ctxcanvas->xmin); + factorY = ((double)(ymax-ymin)) / (ctxcanvas->ymax-ctxcanvas->ymin); + } + + if (cdsizecb) + { + int err; + err = cdsizecb(canvas, pic_canvas->w, pic_canvas->h, pic_canvas->w_mm, pic_canvas->h_mm); + if (err) + return CD_ERROR; + } + + prim = ctxcanvas->prim_first; + for (i = 0; i < ctxcanvas->prim_n; i++) + { + if (scale) + { + switch (prim->type) + { + case CDPIC_LINE: + primUpdateAttrib_Line(prim, canvas); + cdCanvasLine(canvas, sScaleX(prim->param.lineboxrect.x1), sScaleY(prim->param.lineboxrect.y1), sScaleX(prim->param.lineboxrect.x2), sScaleY(prim->param.lineboxrect.y2)); + break; + case CDPIC_FLINE: + primUpdateAttrib_Line(prim, canvas); + cdfCanvasLine(canvas, sfScaleX(prim->param.lineboxrectf.x1), sfScaleY(prim->param.lineboxrectf.y1), sfScaleX(prim->param.lineboxrectf.x2), sfScaleY(prim->param.lineboxrectf.y2)); + break; + case CDPIC_RECT: + primUpdateAttrib_Line(prim, canvas); + cdCanvasRect(canvas, sScaleX(prim->param.lineboxrect.x1), sScaleX(prim->param.lineboxrect.x2), sScaleY(prim->param.lineboxrect.y1), sScaleY(prim->param.lineboxrect.y2)); + break; + case CDPIC_FRECT: + primUpdateAttrib_Line(prim, canvas); + cdfCanvasRect(canvas, sfScaleX(prim->param.lineboxrectf.x1), sfScaleX(prim->param.lineboxrectf.x2), sfScaleY(prim->param.lineboxrectf.y1), sfScaleY(prim->param.lineboxrectf.y2)); + break; + case CDPIC_BOX: + primUpdateAttrib_Fill(prim, canvas); + cdCanvasBox(canvas, sScaleX(prim->param.lineboxrect.x1), sScaleX(prim->param.lineboxrect.x2), sScaleY(prim->param.lineboxrect.y1), sScaleY(prim->param.lineboxrect.y2)); + break; + case CDPIC_FBOX: + primUpdateAttrib_Fill(prim, canvas); + cdfCanvasBox(canvas, sfScaleX(prim->param.lineboxrectf.x1), sfScaleX(prim->param.lineboxrectf.x2), sfScaleY(prim->param.lineboxrectf.y1), sfScaleY(prim->param.lineboxrectf.y2)); + break; + case CDPIC_ARC: + primUpdateAttrib_Line(prim, canvas); + cdCanvasArc(canvas, sScaleX(prim->param.arcsectorchord.xc), sScaleY(prim->param.arcsectorchord.yc), sScaleW(prim->param.arcsectorchord.w), sScaleH(prim->param.arcsectorchord.h), prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2); + break; + case CDPIC_FARC: + primUpdateAttrib_Line(prim, canvas); + cdfCanvasArc(canvas, sfScaleX(prim->param.arcsectorchordf.xc), sfScaleY(prim->param.arcsectorchordf.yc), sfScaleW(prim->param.arcsectorchordf.w), sfScaleH(prim->param.arcsectorchordf.h), prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2); + break; + case CDPIC_SECTOR: + primUpdateAttrib_Fill(prim, canvas); + cdCanvasSector(canvas, sScaleX(prim->param.arcsectorchord.xc), sScaleY(prim->param.arcsectorchord.yc), sScaleW(prim->param.arcsectorchord.w), sScaleH(prim->param.arcsectorchord.h), prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2); + break; + case CDPIC_FSECTOR: + primUpdateAttrib_Fill(prim, canvas); + cdfCanvasSector(canvas, sfScaleX(prim->param.arcsectorchordf.xc), sfScaleY(prim->param.arcsectorchordf.yc), sfScaleW(prim->param.arcsectorchordf.w), sfScaleH(prim->param.arcsectorchordf.h), prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2); + break; + case CDPIC_CHORD: + primUpdateAttrib_Fill(prim, canvas); + cdCanvasChord(canvas, sScaleX(prim->param.arcsectorchord.xc), sScaleY(prim->param.arcsectorchord.yc), sScaleW(prim->param.arcsectorchord.w), sScaleH(prim->param.arcsectorchord.h), prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2); + break; + case CDPIC_FCHORD: + primUpdateAttrib_Fill(prim, canvas); + cdfCanvasChord(canvas, sfScaleX(prim->param.arcsectorchordf.xc), sfScaleY(prim->param.arcsectorchordf.yc), sfScaleW(prim->param.arcsectorchordf.w), sfScaleH(prim->param.arcsectorchordf.h), prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2); + break; + case CDPIC_TEXT: + primUpdateAttrib_Text(prim, canvas); + cdCanvasText(canvas, sScaleX(prim->param.text.x), sScaleY(prim->param.text.y), prim->param.text.s); + break; + case CDPIC_FTEXT: + primUpdateAttrib_Text(prim, canvas); + cdfCanvasText(canvas, sfScaleX(prim->param.textf.x), sfScaleY(prim->param.textf.y), prim->param.text.s); + break; + case CDPIC_POLY: + if (prim->param.poly.mode == CD_FILL) + primUpdateAttrib_Fill(prim, canvas); + else + primUpdateAttrib_Line(prim, canvas); + cdCanvasBegin(canvas, prim->param.poly.mode); + for (p = 0; p < prim->param.poly.n; p++) + cdCanvasVertex(canvas, sScaleX(prim->param.poly.points[p].x), sScaleY(prim->param.poly.points[p].y)); + cdCanvasEnd(canvas); + break; + case CDPIC_FPOLY: + if (prim->param.poly.mode == CD_FILL) + primUpdateAttrib_Fill(prim, canvas); + else + primUpdateAttrib_Line(prim, canvas); + cdCanvasBegin(canvas, prim->param.polyf.mode); + for (p = 0; p < prim->param.polyf.n; p++) + cdfCanvasVertex(canvas, sfScaleX(prim->param.polyf.points[p].x), sfScaleY(prim->param.polyf.points[p].y)); + cdCanvasEnd(canvas); + break; + case CDPIC_IMAGERGB: + cdCanvasPutImageRectRGB(canvas, prim->param.imagergba.iw, prim->param.imagergba.ih, prim->param.imagergba.r, prim->param.imagergba.g, prim->param.imagergba.b, sScaleX(prim->param.imagergba.x), sScaleY(prim->param.imagergba.y), sScaleW(prim->param.imagergba.w), sScaleH(prim->param.imagergba.h), 0, 0, 0, 0); + break; + case CDPIC_IMAGERGBA: + cdCanvasPutImageRectRGBA(canvas, prim->param.imagergba.iw, prim->param.imagergba.ih, prim->param.imagergba.r, prim->param.imagergba.g, prim->param.imagergba.b, prim->param.imagergba.a, sScaleX(prim->param.imagergba.x), sScaleY(prim->param.imagergba.y), sScaleW(prim->param.imagergba.w), sScaleH(prim->param.imagergba.h), 0, 0, 0, 0); + break; + case CDPIC_IMAGEMAP: + cdCanvasPutImageRectMap(canvas, prim->param.imagemap.iw, prim->param.imagemap.ih, prim->param.imagemap.index, prim->param.imagemap.colors, sScaleX(prim->param.imagemap.x), sScaleY(prim->param.imagemap.y), sScaleW(prim->param.imagemap.w), sScaleH(prim->param.imagemap.h), 0, 0, 0, 0); + break; + case CDPIC_PIXEL: + cdCanvasPixel(canvas, sScaleX(prim->param.pixel.x), sScaleY(prim->param.pixel.y), prim->param.pixel.color); + break; + } + } + else + { + switch (prim->type) + { + case CDPIC_LINE: + primUpdateAttrib_Line(prim, canvas); + cdCanvasLine(canvas, prim->param.lineboxrect.x1, prim->param.lineboxrect.y1, prim->param.lineboxrect.x2, prim->param.lineboxrect.y2); + break; + case CDPIC_FLINE: + primUpdateAttrib_Line(prim, canvas); + cdfCanvasLine(canvas, prim->param.lineboxrectf.x1, prim->param.lineboxrectf.y1, prim->param.lineboxrectf.x2, prim->param.lineboxrectf.y2); + break; + case CDPIC_RECT: + primUpdateAttrib_Line(prim, canvas); + cdCanvasRect(canvas, prim->param.lineboxrect.x1, prim->param.lineboxrect.x2, prim->param.lineboxrect.y1, prim->param.lineboxrect.y2); + break; + case CDPIC_FRECT: + primUpdateAttrib_Line(prim, canvas); + cdfCanvasRect(canvas, prim->param.lineboxrectf.x1, prim->param.lineboxrectf.x2, prim->param.lineboxrectf.y1, prim->param.lineboxrectf.y2); + break; + case CDPIC_BOX: + primUpdateAttrib_Fill(prim, canvas); + cdCanvasBox(canvas, prim->param.lineboxrect.x1, prim->param.lineboxrect.x2, prim->param.lineboxrect.y1, prim->param.lineboxrect.y2); + break; + case CDPIC_FBOX: + primUpdateAttrib_Fill(prim, canvas); + cdfCanvasBox(canvas, prim->param.lineboxrectf.x1, prim->param.lineboxrectf.x2, prim->param.lineboxrectf.y1, prim->param.lineboxrectf.y2); + break; + case CDPIC_ARC: + primUpdateAttrib_Line(prim, canvas); + cdCanvasArc(canvas, prim->param.arcsectorchord.xc, prim->param.arcsectorchord.yc, prim->param.arcsectorchord.w, prim->param.arcsectorchord.h, prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2); + break; + case CDPIC_FARC: + primUpdateAttrib_Line(prim, canvas); + cdfCanvasArc(canvas, prim->param.arcsectorchordf.xc, prim->param.arcsectorchordf.yc, prim->param.arcsectorchordf.w, prim->param.arcsectorchordf.h, prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2); + break; + case CDPIC_SECTOR: + primUpdateAttrib_Fill(prim, canvas); + cdCanvasSector(canvas, prim->param.arcsectorchord.xc, prim->param.arcsectorchord.yc, prim->param.arcsectorchord.w, prim->param.arcsectorchord.h, prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2); + break; + case CDPIC_FSECTOR: + primUpdateAttrib_Fill(prim, canvas); + cdfCanvasSector(canvas, prim->param.arcsectorchordf.xc, prim->param.arcsectorchordf.yc, prim->param.arcsectorchordf.w, prim->param.arcsectorchordf.h, prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2); + break; + case CDPIC_CHORD: + primUpdateAttrib_Fill(prim, canvas); + cdCanvasChord(canvas, prim->param.arcsectorchord.xc, prim->param.arcsectorchord.yc, prim->param.arcsectorchord.w, prim->param.arcsectorchord.h, prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2); + break; + case CDPIC_FCHORD: + primUpdateAttrib_Fill(prim, canvas); + cdfCanvasChord(canvas, prim->param.arcsectorchordf.xc, prim->param.arcsectorchordf.yc, prim->param.arcsectorchordf.w, prim->param.arcsectorchordf.h, prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2); + break; + case CDPIC_TEXT: + primUpdateAttrib_Text(prim, canvas); + cdCanvasText(canvas, prim->param.text.x, prim->param.text.y, prim->param.text.s); + break; + case CDPIC_FTEXT: + primUpdateAttrib_Text(prim, canvas); + cdfCanvasText(canvas, prim->param.textf.x, prim->param.textf.y, prim->param.text.s); + break; + case CDPIC_POLY: + if (prim->param.poly.mode == CD_FILL) + primUpdateAttrib_Fill(prim, canvas); + else + primUpdateAttrib_Line(prim, canvas); + cdCanvasBegin(canvas, prim->param.poly.mode); + for (p = 0; p < prim->param.poly.n; p++) + cdCanvasVertex(canvas, prim->param.poly.points[p].x, prim->param.poly.points[p].y); + cdCanvasEnd(canvas); + break; + case CDPIC_FPOLY: + if (prim->param.poly.mode == CD_FILL) + primUpdateAttrib_Fill(prim, canvas); + else + primUpdateAttrib_Line(prim, canvas); + cdCanvasBegin(canvas, prim->param.polyf.mode); + for (p = 0; p < prim->param.polyf.n; p++) + cdfCanvasVertex(canvas, prim->param.polyf.points[p].x, prim->param.polyf.points[p].y); + cdCanvasEnd(canvas); + break; + case CDPIC_IMAGERGB: + cdCanvasPutImageRectRGB(canvas, prim->param.imagergba.iw, prim->param.imagergba.ih, prim->param.imagergba.r, prim->param.imagergba.g, prim->param.imagergba.b, prim->param.imagergba.x, prim->param.imagergba.y, prim->param.imagergba.w, prim->param.imagergba.h, 0, 0, 0, 0); + break; + case CDPIC_IMAGERGBA: + cdCanvasPutImageRectRGBA(canvas, prim->param.imagergba.iw, prim->param.imagergba.ih, prim->param.imagergba.r, prim->param.imagergba.g, prim->param.imagergba.b, prim->param.imagergba.a, prim->param.imagergba.x, prim->param.imagergba.y, prim->param.imagergba.w, prim->param.imagergba.h, 0, 0, 0, 0); + break; + case CDPIC_IMAGEMAP: + cdCanvasPutImageRectMap(canvas, prim->param.imagemap.iw, prim->param.imagemap.ih, prim->param.imagemap.index, prim->param.imagemap.colors, prim->param.imagemap.x, prim->param.imagemap.y, prim->param.imagemap.w, prim->param.imagemap.h, 0, 0, 0, 0); + break; + case CDPIC_PIXEL: + cdCanvasPixel(canvas, prim->param.pixel.x, prim->param.pixel.y, prim->param.pixel.color); + break; + } + } + + prim = prim->next; + } + + return CD_OK; +} + +static void cdkillcanvas(cdCtxCanvas *ctxcanvas) +{ + cdclear(ctxcanvas); + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + free(ctxcanvas); +} + +/*******************/ +/* Canvas Creation */ +/*******************/ + +static void cdcreatecanvas(cdCanvas *canvas, void *data) +{ + char* strdata = (char*)data; + double res = 3.78; + cdCtxCanvas* ctxcanvas; + + sscanf(strdata, "%lg", &res); + + ctxcanvas = (cdCtxCanvas *)malloc(sizeof(cdCtxCanvas)); + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + + ctxcanvas->canvas = canvas; + canvas->ctxcanvas = ctxcanvas; + + /* update canvas context */ + canvas->w = 0; + canvas->h = 0; + canvas->w_mm = 0; + canvas->h_mm = 0; + canvas->bpp = 24; + canvas->xres = res; + canvas->yres = res; +} + +static void cdinittable(cdCanvas* canvas) +{ + canvas->cxClear = cdclear; + canvas->cxPixel = cdpixel; + canvas->cxLine = cdline; + canvas->cxFLine = cdfline; + canvas->cxRect = cdrect; + canvas->cxFRect = cdfrect; + canvas->cxBox = cdbox; + canvas->cxFBox = cdfbox; + canvas->cxArc = cdarc; + canvas->cxFArc = cdfarc; + canvas->cxSector = cdsector; + canvas->cxFSector = cdfsector; + canvas->cxChord = cdchord; + canvas->cxFChord = cdfchord; + canvas->cxText = cdtext; + canvas->cxFText = cdftext; + canvas->cxPoly = cdpoly; + canvas->cxFPoly = cdfpoly; + canvas->cxPutImageRectRGB = cdputimagerectrgb; + canvas->cxPutImageRectRGBA = cdputimagerectrgba; + canvas->cxPutImageRectMap = cdputimagerectmap; + canvas->cxKillCanvas = cdkillcanvas; +} + +static cdContext cdPictureContext = +{ + CD_CAP_ALL & ~(CD_CAP_GETIMAGERGB | CD_CAP_IMAGESRV | + CD_CAP_REGION | CD_CAP_FONTDIM | CD_CAP_TEXTSIZE), + 0, + cdcreatecanvas, + cdinittable, + cdplay, + cdregistercallback, +}; + +cdContext* cdContextPicture(void) +{ + return &cdPictureContext; +} diff --git a/src/drv/cdps.c b/src/drv/cdps.c new file mode 100644 index 0000000..0d23608 --- /dev/null +++ b/src/drv/cdps.c @@ -0,0 +1,1836 @@ +/** \file + * \brief PS driver + * + * See Copyright Notice in cd.h + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <math.h> + +#include "cd.h" +#include "cd_private.h" +#include "cdps.h" + + +#define mm2pt(x) (CD_MM2PT*(x)) + +#ifndef min +#define min(a, b) ((a)<(b)?(a):(b)) +#endif +#ifndef max +#define max(a, b) ((a)>(b)?(a):(b)) +#endif + +/* +** dada uma cor do CD, obtem uma de suas componentes, na faixa 0-1. +*/ +#define get_red(_) (((double)cdRed(_))/255.) +#define get_green(_) (((double)cdGreen(_))/255.) +#define get_blue(_) (((double)cdBlue(_))/255.) + +/* ATENTION: currentmatrix/setmatrix + Remeber that there is a tranformation set just after file open, to define margins and pixel scale. + So use transformations carefully. +*/ + +static unsigned char HatchBits[6][8] = { /* [style][y] (8x8) */ + {0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00}, /* CD_HORIZONTAL */ + {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, /* CD_VERTICAL */ + {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}, /* CD_BDIAGONAL */ + {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}, /* CD_FDIAGONAL */ + {0x10, 0x10, 0x10, 0xFF, 0x10, 0x10, 0x10, 0x10}, /* CD_CROSS */ + {0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81}};/* CD_DIAGCROSS */ + + +struct _cdCtxCanvas +{ + cdCanvas* canvas; + + FILE *file; /* Arquivo PS */ + int res; /* Resolucao */ + int pages; /* Numero total de paginas */ + double width; /* Largura do papel (points) */ + double height; /* Altura do papel (points) */ + double xmin, ymin; /* Definem as margens esquerda e inferior (points) */ + double xmax, ymax; /* Definem as margens direita e superior (points) */ + double bbxmin, bbymin; /* Definem a bounding box */ + double bbxmax, bbymax; /* Definem a bounding box */ + double bbmargin; /* Define a margem para a bounding box */ + double scale; /* Fator de conversao de coordenadas (pixel2points) */ + int eps; /* Postscrip encapsulado? */ + int level1; /* if true generates level 1 only function calls */ + int landscape; /* page orientation */ + int debug; /* print debug strings in the file */ + float rotate_angle; + int rotate_center_x, + rotate_center_y; + + char *nativefontname[100]; /* Registra as fontes usadas */ + int num_native_font; + + int poly_holes[500]; + int holes; + +}; + + +/* +%F Ajusta o tamanho do papel em points. +*/ +static void setpspapersize(cdCtxCanvas *ctxcanvas, int size) +{ + static struct + { + int width; + int height; + } paper[] = + { + { 2393, 3391 }, /* A0 */ + { 1689, 2393 }, /* A1 */ + { 1192, 1689 }, /* A2 */ + { 842, 1192 }, /* A3 */ + { 595, 842 }, /* A4 */ + { 420, 595 }, /* A5 */ + { 612, 792 }, /* LETTER */ + { 612, 1008 } /* LEGAL */ + }; + + if (size<CD_A0 || size>CD_LEGAL) + return; + + ctxcanvas->width = (double)paper[size].width; + ctxcanvas->height = (double)paper[size].height; +} + +/* +%F Registra os valores default para impressao. +*/ +static void setpsdefaultvalues(cdCtxCanvas *ctxcanvas) +{ + /* all the other values are set to 0 */ + setpspapersize(ctxcanvas, CD_A4); + ctxcanvas->xmin = 25.4; /* ainda em mm, sera' convertido para points na init_ps */ + ctxcanvas->xmax = 25.4; + ctxcanvas->ymin = 25.4; + ctxcanvas->ymax = 25.4; + ctxcanvas->res = 300; +} + +/* +%F Insere o ponto (x, y) na BoundingBox corrente. +Nao leva em consideracao a espessura das linhas. +*/ +static void insertpoint(cdCtxCanvas *ctxcanvas, int x, int y) +{ + double xmin = x*ctxcanvas->scale + ctxcanvas->xmin - ctxcanvas->bbmargin; + double ymin = y*ctxcanvas->scale + ctxcanvas->ymin - ctxcanvas->bbmargin; + + double xmax = x*ctxcanvas->scale + ctxcanvas->xmin + ctxcanvas->bbmargin; + double ymax = y*ctxcanvas->scale + ctxcanvas->ymin + ctxcanvas->bbmargin; + + if (!ctxcanvas->bbxmin && !ctxcanvas->bbxmax && !ctxcanvas->bbymin && !ctxcanvas->bbymax) + { + ctxcanvas->bbxmin = xmin; + ctxcanvas->bbymin = ymin; + + ctxcanvas->bbxmax = xmax; + ctxcanvas->bbymax = ymax; + } + else + { + if (ctxcanvas->canvas->clip_mode == CD_CLIPAREA) + { + ctxcanvas->bbxmin = max(ctxcanvas->canvas->clip_rect.xmin*ctxcanvas->scale + ctxcanvas->xmin, min(ctxcanvas->bbxmin, xmin)); + ctxcanvas->bbymin = max(ctxcanvas->canvas->clip_rect.ymin*ctxcanvas->scale + ctxcanvas->ymin, min(ctxcanvas->bbymin, ymin)); + + ctxcanvas->bbxmax = min(ctxcanvas->canvas->clip_rect.xmax*ctxcanvas->scale + ctxcanvas->xmax, max(ctxcanvas->bbxmax, xmax)); + ctxcanvas->bbymax = min(ctxcanvas->canvas->clip_rect.ymax*ctxcanvas->scale + ctxcanvas->ymax, max(ctxcanvas->bbymax, ymax)); + } + else + { + ctxcanvas->bbxmin = max(ctxcanvas->xmin, min(ctxcanvas->bbxmin, xmin)); + ctxcanvas->bbymin = max(ctxcanvas->ymin, min(ctxcanvas->bbymin, ymin)); + + ctxcanvas->bbxmax = min(ctxcanvas->xmax, max(ctxcanvas->bbxmax, xmax)); + ctxcanvas->bbymax = min(ctxcanvas->ymax, max(ctxcanvas->bbymax, ymax)); + } + } +} + +/* +%F Ajusta a BoundingBox para conter o ponto (x,y). +Leva em consideracao a espessura das linhas. +*/ +static void bbox(cdCtxCanvas *ctxcanvas, int x, int y) +{ + if (ctxcanvas->canvas->line_width > 1) + { + insertpoint(ctxcanvas, x-ctxcanvas->canvas->line_width, y-ctxcanvas->canvas->line_width); + insertpoint(ctxcanvas, x+ctxcanvas->canvas->line_width, y+ctxcanvas->canvas->line_width); + } + else + insertpoint(ctxcanvas, x, y); +} + +static void fbbox(cdCtxCanvas *ctxcanvas, double x, double y) +{ + if (ctxcanvas->canvas->line_width > 1) + { + insertpoint(ctxcanvas, (int)(x-ctxcanvas->canvas->line_width), (int)(y-ctxcanvas->canvas->line_width)); + insertpoint(ctxcanvas, (int)(x+ctxcanvas->canvas->line_width), (int)(y+ctxcanvas->canvas->line_width)); + } + else + insertpoint(ctxcanvas, (int)x, (int)y); +} + +static char new_codes[] = {"\ +/newcodes % foreign character encodings\n\ +[\n\ +160/space 161/exclamdown 162/cent 163/sterling 164/currency\n\ +165/yen 166/brokenbar 167/section 168/dieresis 169/copyright\n\ +170/ordfeminine 171/guillemotleft 172/logicalnot 173/hyphen 174/registered\n\ +175/macron 176/degree 177/plusminus 178/twosuperior 179/threesuperior\n\ +180/acute 181/mu 182/paragraph 183/periodcentered 184/cedilla\n\ +185/onesuperior 186/ordmasculine 187/guillemotright 188/onequarter\n\ +189/onehalf 190/threequarters 191/questiondown 192/Agrave 193/Aacute\n\ +194/Acircumflex 195/Atilde 196/Adieresis 197/Aring 198/AE 199/Ccedilla\n\ +200/Egrave 201/Eacute 202/Ecircumflex 203/Edieresis 204/Igrave 205/Iacute\n\ +206/Icircumflex 207/Idieresis 208/Eth 209/Ntilde 210/Ograve 211/Oacute\n\ +212/Ocircumflex 213/Otilde 214/Odieresis 215/multiply 216/Oslash\n\ +217/Ugrave 218/Uacute 219/Ucircumflex 220/Udieresis 221/Yacute 222/Thorn\n\ +223/germandbls 224/agrave 225/aacute 226/acircumflex 227/atilde\n\ +228/adieresis 229/aring 230/ae 231/ccedilla 232/egrave 233/eacute\n\ +234/ecircumflex 235/edieresis 236/igrave 237/iacute 238/icircumflex\n\ +239/idieresis 240/eth 241/ntilde 242/ograve 243/oacute 244/ocircumflex\n\ +245/otilde 246/odieresis 247/divide 248/oslash 249/ugrave 250/uacute\n\ +251/ucircumflex 252/udieresis 253/yacute 254/thorn 255/ydieresis\n\ +] def\n\ +"}; + +static char change_font[] = {"\ +% change fonts using ISO Latin1 characters\n\ +/ChgFnt % size psname natname => font\n\ +{\n\ + dup FontDirectory exch known % is re-encoded name known?\n\ + { exch pop } % yes, get rid of long name\n\ + { dup 3 1 roll ReEncode } ifelse % no, re-encode it\n\ + findfont exch scalefont setfont\n\ +} def\n\ +"}; + +static char re_encode[] = {"\ +/ReEncode %\n\ +{\n\ + 12 dict begin\n\ + /newname exch def\n\ + /basename exch def\n\ + /basedict basename findfont def\n\ + /newfont basedict maxlength dict def\n\ + basedict\n\ + { exch dup /FID ne\n\ + { dup /Encoding eq\n\ + { exch dup length array copy newfont 3 1 roll put }\n\ + { exch newfont 3 1 roll put } ifelse\n\ + }\n\ + { pop pop } ifelse\n\ + } forall\n\ + newfont /FontName newname put\n\ + newcodes aload pop newcodes length 2 idiv\n\ + { newfont /Encoding get 3 1 roll put } repeat\n\ + newname newfont definefont pop\n\ + end\n\ +} def\n\ +"}; + +static void setcliprect(cdCtxCanvas* ctxcanvas, double xmin, double ymin, double xmax, double ymax) +{ + if (ctxcanvas->eps) /* initclip not allowed in EPS */ + return; + + fprintf(ctxcanvas->file, "initclip\n"); + + /* cliping geral para a margem */ + if (ctxcanvas->level1) + { + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "%g %g M\n", xmin, ymin); + fprintf(ctxcanvas->file, "%g %g L\n", xmin, ymax); + fprintf(ctxcanvas->file, "%g %g L\n", xmax, ymax); + fprintf(ctxcanvas->file, "%g %g L\n", xmax, ymin); + fprintf(ctxcanvas->file, "C\n"); + fprintf(ctxcanvas->file, "clip\n"); + fprintf(ctxcanvas->file, "N\n"); + } + else + fprintf(ctxcanvas->file, "%g %g %g %g rectclip\n", xmin, ymin, xmax-xmin, ymax-ymin); +} + +static void set_default_matrix(cdCtxCanvas *ctxcanvas) +{ + if (ctxcanvas->eps) + fprintf(ctxcanvas->file, "oldmatrix setmatrix\n"); /* reset to current */ + else + { + fprintf(ctxcanvas->file, "[0 0 0 0 0 0] defaultmatrix\n"); /* reset to default */ + fprintf(ctxcanvas->file, "setmatrix\n"); + } + + /* margin and scale */ + fprintf(ctxcanvas->file, "%g %g translate\n", ctxcanvas->xmin, ctxcanvas->ymin); + fprintf(ctxcanvas->file, "%g %g scale\n", ctxcanvas->scale, ctxcanvas->scale); +} + +/* +%F Inicializa o arquivo PS. +*/ +static void init_ps(cdCtxCanvas *ctxcanvas) +{ + double w, h; + + time_t now = time(NULL); + + ctxcanvas->scale = 72.0/ctxcanvas->res; + ctxcanvas->xmin = mm2pt(ctxcanvas->xmin); + ctxcanvas->xmax = ctxcanvas->width - mm2pt(ctxcanvas->xmax); + ctxcanvas->ymin = mm2pt(ctxcanvas->ymin); + ctxcanvas->ymax = ctxcanvas->height - mm2pt(ctxcanvas->ymax); + ctxcanvas->bbmargin = mm2pt(ctxcanvas->bbmargin); + + fprintf(ctxcanvas->file, "%%!PS-Adobe-3.0 %s\n", ctxcanvas->eps ? "EPSF-3.0":""); + fprintf(ctxcanvas->file, "%%%%Title: CanvasDraw\n"); + fprintf(ctxcanvas->file, "%%%%Creator: CanvasDraw\n"); + fprintf(ctxcanvas->file, "%%%%CreationDate: %s", asctime(localtime(&now))); + fprintf(ctxcanvas->file, "%%%%DocumentFonts: (atend)\n"); /* attend means at the end of the file, */ + fprintf(ctxcanvas->file, "%%%%Pages: (atend)\n"); /* see killcanvas */ + fprintf(ctxcanvas->file, "%%%%PageOrder: Ascend\n"); + fprintf(ctxcanvas->file, "%%%%LanguageLevel: %d\n", ctxcanvas->level1 ? 1: 2); + fprintf(ctxcanvas->file, "%%%%Orientation: %s\n", ctxcanvas->landscape ? "Landscape": "Portrait"); + + if (ctxcanvas->eps) + { + fprintf(ctxcanvas->file, "%%%%BoundingBox: (atend)\n"); + ctxcanvas->bbxmin = ctxcanvas->bbxmax = ctxcanvas->bbymin = ctxcanvas->bbymax = 0; + /* BoundingBox==Empty */ + } + + fprintf(ctxcanvas->file, "%%%%EndComments\n"); + fprintf(ctxcanvas->file, "%%%%BeginProlog\n"); + + fprintf(ctxcanvas->file, "/N {newpath} bind def\n"); + fprintf(ctxcanvas->file, "/C {closepath} bind def\n"); + fprintf(ctxcanvas->file, "/M {moveto} bind def\n"); + fprintf(ctxcanvas->file, "/L {lineto} bind def\n"); + fprintf(ctxcanvas->file, "/B {curveto} bind def\n"); + fprintf(ctxcanvas->file, "/S {stroke} bind def\n"); + fprintf(ctxcanvas->file, "/LL {moveto lineto stroke} bind def\n"); + + if (!ctxcanvas->level1) + { + fprintf(ctxcanvas->file, "/RF {rectfill} bind def\n"); + fprintf(ctxcanvas->file, "/RS {rectstroke} bind def\n"); + } + + fprintf(ctxcanvas->file, "%%%%EndProlog\n"); + fprintf(ctxcanvas->file, "%%%%BeginSetup\n"); + + if (!ctxcanvas->eps && !ctxcanvas->level1) + { + fprintf(ctxcanvas->file, "%%%%IncludeFeature: *Resolution %d\n", ctxcanvas->res); + fprintf(ctxcanvas->file, "%%%%BeginFeature: *PageSize\n"); + fprintf(ctxcanvas->file, "<< /PageSize [%g %g] >> setpagedevice\n", ctxcanvas->width, ctxcanvas->height); /* setpagedevice not allowed in EPS */ + fprintf(ctxcanvas->file, "%%%%EndFeature\n"); + } + + fprintf(ctxcanvas->file, "%%%%EndSetup\n"); + + fputs(new_codes, ctxcanvas->file); + fputs(change_font, ctxcanvas->file); + fputs(re_encode, ctxcanvas->file); + + w = ctxcanvas->xmax - ctxcanvas->xmin; + h = ctxcanvas->ymax - ctxcanvas->ymin; + + ctxcanvas->canvas->w = (int)(w/ctxcanvas->scale + 0.5); /* Converte p/ unidades do usuario */ + ctxcanvas->canvas->h = (int)(h/ctxcanvas->scale + 0.5); /* Converte p/ unidades do usuario */ + ctxcanvas->canvas->w_mm = w/CD_MM2PT; /* Converte p/ milimetros */ + ctxcanvas->canvas->h_mm = h/CD_MM2PT; /* Converte p/ milimetros */ + ctxcanvas->canvas->bpp = 24; + ctxcanvas->canvas->xres = ctxcanvas->canvas->w / ctxcanvas->canvas->w_mm; + ctxcanvas->canvas->yres = ctxcanvas->canvas->h / ctxcanvas->canvas->h_mm; + + fprintf(ctxcanvas->file, "%%%%Page: 1 1\n"); + ctxcanvas->pages = 1; + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdCreateCanvas: Margin Begin\n"); + + if (ctxcanvas->eps) + fprintf(ctxcanvas->file, "/oldmatrix [0 0 0 0 0 0] currentmatrix def\n"); /* save current matrix */ + + set_default_matrix(ctxcanvas); + + /* cliping geral para a margem */ + setcliprect(ctxcanvas, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdCreateCanvas: MarginEnd\n"); +} + + +static void cdkillcanvas(cdCtxCanvas *ctxcanvas) +{ + int i; + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdKillCanvas\n"); + + fprintf(ctxcanvas->file, "showpage\n"); + fprintf(ctxcanvas->file, "%%%%Trailer\n"); + fprintf(ctxcanvas->file, "%%%%Pages: %d 1\n", ctxcanvas->pages); + + if (ctxcanvas->eps) + { + int xmin = (int)ctxcanvas->bbxmin; + int xmax = (int)ctxcanvas->bbxmax; + int ymin = (int)ctxcanvas->bbymin; + int ymax = (int)ctxcanvas->bbymax; + if (xmax < ctxcanvas->bbxmax) xmax++; + if (ymax < ctxcanvas->bbymax) ymax++; + fprintf(ctxcanvas->file,"%%%%BoundingBox: %5d %5d %5d %5d\n",xmin,ymin,xmax,ymax); + } + + fprintf(ctxcanvas->file, "%%%%DocumentFonts:"); + + for (i = 0; i < ctxcanvas->num_native_font; i++) + { + fprintf(ctxcanvas->file, " %s", ctxcanvas->nativefontname[i]); + free(ctxcanvas->nativefontname[i]); + } + + putc('\n', ctxcanvas->file); + fprintf(ctxcanvas->file,"%%%%EOF"); + + fclose(ctxcanvas->file); + + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + free(ctxcanvas); +} + +static void cddeactivate(cdCtxCanvas *ctxcanvas) +{ + fflush(ctxcanvas->file); +} + +static int cdhatch(cdCtxCanvas *ctxcanvas, int style); +static void cdstipple(cdCtxCanvas *ctxcanvas, int n, int m, const unsigned char *stipple); +static void cdpattern(cdCtxCanvas *ctxcanvas, int n, int m, const long int *pattern); + +static void update_fill(cdCtxCanvas *ctxcanvas, int fill) +{ + if (fill == 0) + { + /* called before a NON filled primitive */ + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdPsUpdateFill %d Begin\n", fill); + + fprintf(ctxcanvas->file, "%g %g %g setrgbcolor\n", get_red(ctxcanvas->canvas->foreground), + get_green(ctxcanvas->canvas->foreground), + get_blue(ctxcanvas->canvas->foreground)); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPsUpdateFill %dEnd\n", fill); + } + else + { + /* called before a filled primitive */ + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdPsUpdateFill %d Begin\n", fill); + + if (ctxcanvas->canvas->interior_style == CD_SOLID) + { + fprintf(ctxcanvas->file, "%g %g %g setrgbcolor\n", get_red(ctxcanvas->canvas->foreground), + get_green(ctxcanvas->canvas->foreground), + get_blue(ctxcanvas->canvas->foreground)); + } + else if (!ctxcanvas->level1) + { + fprintf(ctxcanvas->file, "cd_pattern\n"); + fprintf(ctxcanvas->file, "setpattern\n"); + } + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPsUpdateFill %dEnd\n", fill); + } +} + +/* +%F Comeca uma nova pagina. +*/ +static void cdflush(cdCtxCanvas *ctxcanvas) +{ + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdFlush Begin\n"); + + if (!ctxcanvas->eps) + { + fprintf(ctxcanvas->file, "gsave\n"); + + fprintf(ctxcanvas->file, "showpage\n"); + ctxcanvas->pages++; + fprintf(ctxcanvas->file, "%%%%Page: %d %d\n", ctxcanvas->pages, ctxcanvas->pages); + + fprintf(ctxcanvas->file, "grestore\n"); + } + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdFlushEnd\n"); +} + + +/******************************************************/ +/* coordinate transformation */ +/******************************************************/ + +static void cdfcliparea(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + if (ctxcanvas->canvas->clip_mode != CD_CLIPAREA) + return; + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdfClipArea Begin\n"); + + setcliprect(ctxcanvas, xmin, ymin, xmax, ymax); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdfClipAreaEnd\n"); +} + +static int cdclip(cdCtxCanvas *ctxcanvas, int mode) +{ + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdClip %d Begin\n", mode); + + if (mode == CD_CLIPAREA) + { + ctxcanvas->canvas->clip_mode = CD_CLIPAREA; + + setcliprect(ctxcanvas, (double)ctxcanvas->canvas->clip_rect.xmin, + (double)ctxcanvas->canvas->clip_rect.ymin, + (double)ctxcanvas->canvas->clip_rect.xmax, + (double)ctxcanvas->canvas->clip_rect.ymax); + } + else if (mode == CD_CLIPPOLYGON) + { + fprintf(ctxcanvas->file, "clip_polygon\n"); + } + else + { + /* margin clipping only */ + setcliprect(ctxcanvas, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h); + } + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdClip %dEnd\n", mode); + + return mode; +} + +/******************************************************/ +/* primitives */ +/******************************************************/ + +static void cdline(cdCtxCanvas *ctxcanvas, int x1, int y1, int x2, int y2) +{ + update_fill(ctxcanvas, 0); + + fprintf(ctxcanvas->file, "N %d %d %d %d LL\n", x1, y1, x2, y2); + + if (ctxcanvas->eps) + { + bbox(ctxcanvas, x1, y1); + bbox(ctxcanvas, x2, y2); + } +} + +static void cdfline(cdCtxCanvas *ctxcanvas, double x1, double y1, double x2, double y2) +{ + update_fill(ctxcanvas, 0); + + fprintf(ctxcanvas->file, "N %g %g %g %g LL\n", x1, y1, x2, y2); + + if (ctxcanvas->eps) + { + fbbox(ctxcanvas, x1, y1); + fbbox(ctxcanvas, x2, y2); + } +} + +static void cdrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + update_fill(ctxcanvas, 0); + + if (ctxcanvas->level1) + { + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "%d %d M\n", xmin, ymin); + fprintf(ctxcanvas->file, "%d %d L\n", xmin, ymax); + fprintf(ctxcanvas->file, "%d %d L\n", xmax, ymax); + fprintf(ctxcanvas->file, "%d %d L\n", xmax, ymin); + fprintf(ctxcanvas->file, "C S\n"); + } + else + fprintf(ctxcanvas->file, "%d %d %d %d RS\n", xmin, ymin, xmax - xmin, ymax - ymin); + + if (ctxcanvas->eps) + { + bbox(ctxcanvas, xmin, ymin); + bbox(ctxcanvas, xmax, ymax); + } +} + +static void cdfrect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + update_fill(ctxcanvas, 0); + + if (ctxcanvas->level1) + { + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "%g %g M\n", xmin, ymin); + fprintf(ctxcanvas->file, "%g %g L\n", xmin, ymax); + fprintf(ctxcanvas->file, "%g %g L\n", xmax, ymax); + fprintf(ctxcanvas->file, "%g %g L\n", xmax, ymin); + fprintf(ctxcanvas->file, "C S\n"); + } + else + fprintf(ctxcanvas->file, "%g %g %g %g RS\n", xmin, ymin, xmax - xmin, ymax - ymin); + + if (ctxcanvas->eps) + { + fbbox(ctxcanvas, xmin, ymin); + fbbox(ctxcanvas, xmax, ymax); + } +} + +static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + update_fill(ctxcanvas, 1); + + if (ctxcanvas->level1) + { + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "%d %d M\n", xmin, ymin); + fprintf(ctxcanvas->file, "%d %d L\n", xmin, ymax); + fprintf(ctxcanvas->file, "%d %d L\n", xmax, ymax); + fprintf(ctxcanvas->file, "%d %d L\n", xmax, ymin); + fprintf(ctxcanvas->file, "C fill\n"); + } + else + fprintf(ctxcanvas->file, "%d %d %d %d RF\n", xmin, ymin, xmax - xmin, ymax - ymin); + + if (ctxcanvas->eps) + { + bbox(ctxcanvas, xmin, ymin); + bbox(ctxcanvas, xmax, ymax); + } +} + +static void cdfbox(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + update_fill(ctxcanvas, 1); + + if (ctxcanvas->level1) + { + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "%g %g M\n", xmin, ymin); + fprintf(ctxcanvas->file, "%g %g L\n", xmin, ymax); + fprintf(ctxcanvas->file, "%g %g L\n", xmax, ymax); + fprintf(ctxcanvas->file, "%g %g L\n", xmax, ymin); + fprintf(ctxcanvas->file, "C fill\n"); + } + else + fprintf(ctxcanvas->file, "%g %g %g %g RF\n", xmin, ymin, xmax - xmin, ymax - ymin); + + if (ctxcanvas->eps) + { + fbbox(ctxcanvas, xmin, ymin); + fbbox(ctxcanvas, xmax, ymax); + } +} + +static void cdarc(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + update_fill(ctxcanvas, 0); + + if (w==h) /* Circulo: PS implementa direto */ + { + fprintf(ctxcanvas->file, "N %d %d %g %g %g arc S\n", xc, yc, 0.5*w, a1, a2); + } + else /* Elipse: mudar a escala p/ criar a partir do circulo */ + { + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdArc Ellipse Begin\n"); + + fprintf(ctxcanvas->file, "[0 0 0 0 0 0] currentmatrix\n"); /* fill new matrix from CTM */ + fprintf(ctxcanvas->file, "%d %d translate\n", xc, yc); + fprintf(ctxcanvas->file, "1 %g scale\n", ((double)h)/w); + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "0 0 %g %g %g arc\n", 0.5*w, a1, a2); + fprintf(ctxcanvas->file, "S\n"); + fprintf(ctxcanvas->file, "setmatrix\n"); /* back to CTM */ + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdArc EllipseEnd\n"); + } + + if (ctxcanvas->eps) + { + int xmin, xmax, ymin, ymax; + cdCanvasGetEllipseBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax); + bbox(ctxcanvas, xmin, ymin); + bbox(ctxcanvas, xmax, ymax); + } +} + +static void cdfarc(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + update_fill(ctxcanvas, 0); + + if (w==h) /* Circulo: PS implementa direto */ + { + fprintf(ctxcanvas->file, "N %g %g %g %g %g arc S\n", xc, yc, 0.5*w, a1, a2); + } + else /* Elipse: mudar a escala p/ criar a partir do circulo */ + { + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdfArc Ellipse Begin\n"); + + fprintf(ctxcanvas->file, "[0 0 0 0 0 0] currentmatrix\n"); + fprintf(ctxcanvas->file, "%g %g translate\n", xc, yc); + fprintf(ctxcanvas->file, "1 %g scale\n", h/w); + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "0 0 %g %g %g arc\n", 0.5*w, a1, a2); + fprintf(ctxcanvas->file, "S\n"); + fprintf(ctxcanvas->file, "setmatrix\n"); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdfArc EllipseEnd\n"); + } + + if (ctxcanvas->eps) + { + int xmin, xmax, ymin, ymax; + cdCanvasGetEllipseBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax); + bbox(ctxcanvas, xmin, ymin); + bbox(ctxcanvas, xmax, ymax); + } +} + +static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + update_fill(ctxcanvas, 1); + + if (w==h) /* Circulo: PS implementa direto */ + { + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdSector Circle Begin\n"); + + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "%d %d M\n", xc, yc); + fprintf(ctxcanvas->file, "%d %d %g %g %g arc\n", xc, yc, 0.5*w, a1, a2); + fprintf(ctxcanvas->file, "C fill\n"); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdSector CircleEnd\n"); + } + else /* Elipse: mudar a escala p/ criar a partir do circulo */ + { + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdSector Ellipse Begin\n"); + + fprintf(ctxcanvas->file, "[0 0 0 0 0 0] currentmatrix\n"); + fprintf(ctxcanvas->file, "%d %d translate\n", xc, yc); + fprintf(ctxcanvas->file, "1 %g scale\n", ((double)h)/w); + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "0 0 M\n"); + fprintf(ctxcanvas->file, "0 0 %g %g %g arc\n", 0.5*w, a1, a2); + fprintf(ctxcanvas->file, "C fill\n"); + fprintf(ctxcanvas->file, "setmatrix\n"); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdSector EllipseEnd\n"); + } + + if (ctxcanvas->eps) + { + int xmin, xmax, ymin, ymax; + cdCanvasGetEllipseBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax); + bbox(ctxcanvas, xmin, ymin); + bbox(ctxcanvas, xmax, ymax); + bbox(ctxcanvas, xc, yc); + } +} + +static void cdfsector(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + update_fill(ctxcanvas, 1); + + if (w==h) /* Circulo: PS implementa direto */ + { + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdfSector Circle Begin\n"); + + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "%g %g M\n", xc, yc); + fprintf(ctxcanvas->file, "%g %g %g %g %g arc\n", xc, yc, 0.5*w, a1, a2); + fprintf(ctxcanvas->file, "C fill\n"); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdfSector CircleEnd\n"); + } + else /* Elipse: mudar a escala p/ criar a partir do circulo */ + { + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdfSector Ellipse Begin\n"); + + fprintf(ctxcanvas->file, "[0 0 0 0 0 0] currentmatrix\n"); + fprintf(ctxcanvas->file, "%g %g translate\n", xc, yc); + fprintf(ctxcanvas->file, "1 %g scale\n", h/w); + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "0 0 M\n"); + fprintf(ctxcanvas->file, "0 0 %g %g %g arc\n", 0.5*w, a1, a2); + fprintf(ctxcanvas->file, "C fill\n"); + fprintf(ctxcanvas->file, "setmatrix\n"); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdfSector EllipseEnd\n"); + } + + if (ctxcanvas->eps) + { + int xmin, xmax, ymin, ymax; + cdCanvasGetEllipseBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax); + bbox(ctxcanvas, xmin, ymin); + bbox(ctxcanvas, xmax, ymax); + fbbox(ctxcanvas, xc, yc); + } +} + +static void cdchord(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + update_fill(ctxcanvas, 1); + + if (w==h) /* Circulo: PS implementa direto */ + { + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdChord Circle Begin\n"); + + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "%d %d %g %g %g arc\n", xc, yc, 0.5*w, a1, a2); + fprintf(ctxcanvas->file, "C fill\n"); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdChord CircleEnd\n"); + } + else /* Elipse: mudar a escala p/ criar a partir do circulo */ + { + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdChord Ellipse Begin\n"); + + fprintf(ctxcanvas->file, "[0 0 0 0 0 0] currentmatrix\n"); + fprintf(ctxcanvas->file, "%d %d translate\n", xc, yc); + fprintf(ctxcanvas->file, "1 %g scale\n", ((double)h)/w); + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "0 0 %g %g %g arc\n", 0.5*w, a1, a2); + fprintf(ctxcanvas->file, "C fill\n"); + fprintf(ctxcanvas->file, "setmatrix\n"); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdChord EllipseEnd\n"); + } + + if (ctxcanvas->eps) + { + int xmin, xmax, ymin, ymax; + cdCanvasGetEllipseBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax); + bbox(ctxcanvas, xmin, ymin); + bbox(ctxcanvas, xmax, ymax); + } +} + +static void cdfchord(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + update_fill(ctxcanvas, 1); + + if (w==h) /* Circulo: PS implementa direto */ + { + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdfChord Circle Begin\n"); + + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "%g %g %g %g %g arc\n", xc, yc, 0.5*w, a1, a2); + fprintf(ctxcanvas->file, "C fill\n"); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdfChord CircleEnd\n"); + } + else /* Elipse: mudar a escala p/ criar a partir do circulo */ + { + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdfChord Ellipse Begin\n"); + + fprintf(ctxcanvas->file, "[0 0 0 0 0 0] currentmatrix\n"); + fprintf(ctxcanvas->file, "%g %g translate\n", xc, yc); + fprintf(ctxcanvas->file, "1 %g scale\n", h/w); + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "0 0 %g %g %g arc\n", 0.5*w, a1, a2); + fprintf(ctxcanvas->file, "C fill\n"); + fprintf(ctxcanvas->file, "setmatrix\n"); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdfChord EllipseEnd\n"); + } + + if (ctxcanvas->eps) + { + int xmin, xmax, ymin, ymax; + cdCanvasGetEllipseBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax); + bbox(ctxcanvas, xmin, ymin); + bbox(ctxcanvas, xmax, ymax); + } +} + +static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix); + +static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *s) +{ + int i, length; + int ascent, height, baseline; + + update_fill(ctxcanvas, 0); + + cdCanvasGetFontDim(ctxcanvas->canvas, NULL, &height, &ascent, NULL); + baseline = height - ascent; + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdText Begin\n"); + + if (ctxcanvas->canvas->use_matrix || ctxcanvas->rotate_angle) + set_default_matrix(ctxcanvas); + + fprintf(ctxcanvas->file, "N 0 0 M\n"); + putc('(', ctxcanvas->file); + + for (length = (int)strlen(s), i=0; i<length; i++) + { + if (s[i]=='(' || s[i]==')') + putc('\\', ctxcanvas->file); + putc(s[i], ctxcanvas->file); + } + + fprintf(ctxcanvas->file, ")\n"); + fprintf(ctxcanvas->file, "dup true charpath\n"); + fprintf(ctxcanvas->file, "flattenpath\n"); + fprintf(ctxcanvas->file, "pathbbox\n"); /* bbox na pilha: llx lly urx ury */ + fprintf(ctxcanvas->file, "exch\n"); /* troca o topo: llx lly ury urx */ + fprintf(ctxcanvas->file, "4 1 roll\n"); /* roda: urx llx lly ury */ + fprintf(ctxcanvas->file, "exch\n"); /* troca o topo: urx llx ury lly */ + fprintf(ctxcanvas->file, "sub\n"); /* subtrai: urx llx h */ + fprintf(ctxcanvas->file, "3 1 roll\n"); /* roda: h urx llx */ + fprintf(ctxcanvas->file, "sub\n"); /* subtrai: h w */ + fprintf(ctxcanvas->file, "0 0\n"); /* empilha: h w 0 0 */ + fprintf(ctxcanvas->file, "4 -1 roll\n"); /* roda: w 0 0 h */ + + if (ctxcanvas->canvas->use_matrix || ctxcanvas->rotate_angle) + cdtransform(ctxcanvas, ctxcanvas->canvas->use_matrix? ctxcanvas->canvas->matrix: NULL); + + fprintf(ctxcanvas->file, "gsave\n"); /* save to use local transform */ + fprintf(ctxcanvas->file, "%d %d translate\n", x, y); + + if (ctxcanvas->canvas->text_orientation != 0) + fprintf(ctxcanvas->file, "%g rotate\n", ctxcanvas->canvas->text_orientation); + + switch (ctxcanvas->canvas->text_alignment) /* Operacao em Y. topo da pilha: w x y h */ + { + case CD_NORTH: + case CD_NORTH_EAST: + case CD_NORTH_WEST: + fprintf(ctxcanvas->file, "%d sub sub\n", baseline); /* empilha, subtrai, subtrai: w x y-(h-baseline) */ + break; + case CD_EAST: + case CD_WEST: + case CD_CENTER: + fprintf(ctxcanvas->file, "2 div %d sub sub\n", baseline); /* empilha, divide, empilha, subtrai, subtrai: w x y-(h/2-baseline) */ + break; + case CD_SOUTH_EAST: + case CD_SOUTH: + case CD_SOUTH_WEST: + fprintf(ctxcanvas->file, "pop %d add\n", baseline); /* desempilha, empilha, adiciona: w x y+baseline */ + break; + case CD_BASE_RIGHT: + case CD_BASE_CENTER: + case CD_BASE_LEFT: + fprintf(ctxcanvas->file, "pop\n"); /* desempilha h: w x y */ + break; + } + + fprintf(ctxcanvas->file, "3 1 roll\n"); /* roda: y' w x */ + fprintf(ctxcanvas->file, "exch\n"); /* inverte: y' x w */ + + switch (ctxcanvas->canvas->text_alignment) /* Operacao em X, topo da pilha: x w */ + { + case CD_NORTH: + case CD_SOUTH: + case CD_CENTER: + case CD_BASE_CENTER: + fprintf(ctxcanvas->file, "2 div sub\n"); /* empilha, divide, subtrai: y' x-w/2 */ + break; + case CD_NORTH_EAST: + case CD_EAST: + case CD_SOUTH_EAST: + case CD_BASE_RIGHT: + fprintf(ctxcanvas->file, "sub\n"); /* subtrai: y' x-w */ + break; + case CD_SOUTH_WEST: + case CD_WEST: + case CD_NORTH_WEST: + case CD_BASE_LEFT: + fprintf(ctxcanvas->file, "pop\n"); /* desempilha: y' x */ + break; + } + + fprintf(ctxcanvas->file, "exch\n"); /* inverte: x' y' */ + fprintf(ctxcanvas->file, "M\n"); /* moveto */ + + fprintf(ctxcanvas->file, "show\n"); + + if (ctxcanvas->eps) + { + int xmin, xmax, ymin, ymax; + cdCanvasGetTextBox(ctxcanvas->canvas, x, y, s, &xmin, &xmax, &ymin, &ymax); + bbox(ctxcanvas, xmin, ymin); + bbox(ctxcanvas, xmax, ymax); + } + + fprintf(ctxcanvas->file, "grestore\n"); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdTextEnd\n"); +} + +static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n) +{ + int i; + + if (mode == CD_CLIP) + { + if (ctxcanvas->eps) /* initclip not allowed in EPS */ + return; + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdPoly %d Begin\n", mode); + + fprintf(ctxcanvas->file, "/clip_polygon {\n"); + fprintf(ctxcanvas->file, "initclip\n"); + } + else + { + if (mode == CD_FILL) + update_fill(ctxcanvas, 1); + else + update_fill(ctxcanvas, 0); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdPoly %d Begin\n", mode); + } + + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "%d %d M\n", poly[0].x, poly[0].y); + + if (ctxcanvas->eps) + bbox(ctxcanvas, poly[0].x, poly[0].y); + + if (mode == CD_BEZIER) + { + for (i=1; i<n; i+=3) + { + fprintf(ctxcanvas->file, "%d %d %d %d %d %d B\n", poly[i].x, poly[i].y, + poly[i+1].x, poly[i+1].y, + poly[i+2].x, poly[i+2].y); + + if (ctxcanvas->eps) + { + bbox(ctxcanvas, poly[i].x, poly[i].y); + bbox(ctxcanvas, poly[i+2].x, poly[i+2].y); + bbox(ctxcanvas, poly[i+3].x, poly[i+3].y); + } + } + } + else + { + int hole_index = 0; + + for (i=1; i<n; i++) + { + if (ctxcanvas->holes && i == ctxcanvas->poly_holes[hole_index]) + { + fprintf(ctxcanvas->file, "%d %d M\n", poly[i].x, poly[i].y); + hole_index++; + } + else + fprintf(ctxcanvas->file, "%d %d L\n", poly[i].x, poly[i].y); + + if (ctxcanvas->eps) + bbox(ctxcanvas, poly[i].x, poly[i].y); + } + } + + switch (mode) + { + case CD_CLOSED_LINES : + fprintf(ctxcanvas->file, "C S\n"); + break; + case CD_OPEN_LINES : + fprintf(ctxcanvas->file, "S\n"); + break; + case CD_BEZIER : + fprintf(ctxcanvas->file, "S\n"); + break; + case CD_FILL : + if (ctxcanvas->holes || ctxcanvas->canvas->fill_mode==CD_EVENODD) + fprintf(ctxcanvas->file, "eofill\n"); + else + fprintf(ctxcanvas->file, "fill\n"); + break; + case CD_CLIP : + if (ctxcanvas->canvas->fill_mode==CD_EVENODD) + fprintf(ctxcanvas->file, "C eoclip\n"); + else + fprintf(ctxcanvas->file, "C clip\n"); + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "} bind def\n"); + if (ctxcanvas->canvas->clip_mode == CD_CLIPPOLYGON) + fprintf(ctxcanvas->file, "clip_polygon\n"); + break; + } + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPoly %dEnd\n", mode); +} + +static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n) +{ + int i, hole_index = 0; + + if (mode == CD_CLIP) + { + if (ctxcanvas->eps) /* initclip not allowed in EPS */ + return; + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdfPoly %d Begin\n", mode); + + fprintf(ctxcanvas->file, "/clip_polygon {\n"); + fprintf(ctxcanvas->file, "initclip\n"); + } + else + { + if (mode == CD_FILL) + update_fill(ctxcanvas, 1); + else + update_fill(ctxcanvas, 0); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdfPoly %d Begin\n", mode); + } + + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "%g %g M\n", poly[0].x, poly[0].y); + + if (ctxcanvas->eps) + fbbox(ctxcanvas, poly[0].x, poly[0].y); + + for (i=1; i<n; i++) + { + if (ctxcanvas->holes && i == ctxcanvas->poly_holes[hole_index]) + { + fprintf(ctxcanvas->file, "%g %g M\n", poly[i].x, poly[i].y); + hole_index++; + } + else + fprintf(ctxcanvas->file, "%g %g L\n", poly[i].x, poly[i].y); + + if (ctxcanvas->eps) + fbbox(ctxcanvas, poly[i].x, poly[i].y); + } + + switch (mode) + { + case CD_CLOSED_LINES : + fprintf(ctxcanvas->file, "C S\n"); + break; + case CD_OPEN_LINES : + fprintf(ctxcanvas->file, "S\n"); + break; + case CD_FILL : + if (ctxcanvas->holes || ctxcanvas->canvas->fill_mode==CD_EVENODD) + fprintf(ctxcanvas->file, "eofill\n"); + else + fprintf(ctxcanvas->file, "fill\n"); + break; + case CD_CLIP : + if (ctxcanvas->canvas->fill_mode==CD_EVENODD) + fprintf(ctxcanvas->file, "C eoclip\n"); + else + fprintf(ctxcanvas->file, "C clip\n"); + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "} bind def\n"); + if (ctxcanvas->canvas->clip_mode == CD_CLIPPOLYGON) + fprintf(ctxcanvas->file, "clip_polygon\n"); + break; + } + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdfPoly %dEnd\n", mode); +} + + +/******************************************************/ +/* attributes */ +/******************************************************/ + +static int cdlinestyle(cdCtxCanvas *ctxcanvas, int style) +{ + double mm = (72.0/25.4) / ctxcanvas->scale; + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdLineStyle %d Begin\n", style); + + fprintf(ctxcanvas->file, "["); + + switch (style) + { + case CD_CONTINUOUS : /* empty dash */ + fprintf(ctxcanvas->file, " "); + break; + case CD_DASHED : + fprintf(ctxcanvas->file, "%g %g", 3*mm, mm); + break; + case CD_DOTTED : + fprintf(ctxcanvas->file, "%g %g", mm, mm); + break; + case CD_DASH_DOT : + fprintf(ctxcanvas->file, "%g %g %g %g", 3*mm, mm, mm, mm); + break; + case CD_DASH_DOT_DOT : + fprintf(ctxcanvas->file, "%g %g %g %g %g %g", 3*mm, mm, mm, mm, mm, mm); + break; + case CD_CUSTOM : + { + int i; + for (i = 0; i < ctxcanvas->canvas->line_dashes_count; i++) + fprintf(ctxcanvas->file, "%g ", ctxcanvas->canvas->line_dashes[i]*mm); + } + break; + } + + fprintf(ctxcanvas->file, "] 0 setdash\n"); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdLineStyle %dEnd\n", style); + + return style; +} + +static int cdlinewidth(cdCtxCanvas *ctxcanvas, int width) +{ + fprintf(ctxcanvas->file, "%d setlinewidth\n", width); + return width; +} + +static int cdlinejoin(cdCtxCanvas *ctxcanvas, int join) +{ + int cd2ps_join[] = {0, 2, 1}; + fprintf(ctxcanvas->file, "%d setlinejoin\n", cd2ps_join[join]); + return join; +} + +static int cdlinecap(cdCtxCanvas *ctxcanvas, int cap) +{ + int cd2ps_cap[] = {0, 2, 1}; + fprintf(ctxcanvas->file, "%d setlinecap\n", cd2ps_cap[cap]); + return cap; +} + +static void make_pattern(cdCtxCanvas *ctxcanvas, int n, int m, void* data, void (*data2rgb)(cdCtxCanvas *ctxcanvas, int n, int i, int j, void* data, unsigned char*r, unsigned char*g, unsigned char*b)) +{ + int i, j; + unsigned char r, g, b; + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdPsMakePattern Begin\n"); + + fprintf(ctxcanvas->file, "/cd_pattern\n"); + fprintf(ctxcanvas->file, "currentfile %d string readhexstring\n", n*m*3); + + for (j=0; j<m; j++) + { + for (i=0; i<n; i++) + { + data2rgb(ctxcanvas, n, i, j, data, &r, &g, &b); + fprintf(ctxcanvas->file, "%02x%02x%02x", (int)r, (int)g, (int)b); + } + + fprintf(ctxcanvas->file, "\n"); + } + + fprintf(ctxcanvas->file, "pop\n"); + fprintf(ctxcanvas->file, "/Pat exch def\n"); + fprintf(ctxcanvas->file, "<<\n"); + fprintf(ctxcanvas->file, " /PatternType 1\n"); + fprintf(ctxcanvas->file, " /PaintType 1\n"); + fprintf(ctxcanvas->file, " /TilingType 1\n"); + fprintf(ctxcanvas->file, " /BBox [0 0 %d %d]\n", n, m); + fprintf(ctxcanvas->file, " /XStep %d /YStep %d\n", n, m); + fprintf(ctxcanvas->file, " /PaintProc {\n"); + fprintf(ctxcanvas->file, " pop\n"); + fprintf(ctxcanvas->file, " %d %d 8\n", n, m); + fprintf(ctxcanvas->file, " matrix\n"); + fprintf(ctxcanvas->file, " Pat\n"); + fprintf(ctxcanvas->file, " false 3\n"); + fprintf(ctxcanvas->file, " colorimage\n"); + fprintf(ctxcanvas->file, " }\n"); + fprintf(ctxcanvas->file, ">>\n"); + fprintf(ctxcanvas->file, "matrix\n"); + fprintf(ctxcanvas->file, "makepattern\n"); + fprintf(ctxcanvas->file, "def\n"); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPsMakePatternEnd\n"); +} + +static void long2rgb(cdCtxCanvas *ctxcanvas, int n, int i, int j, void* data, unsigned char*r, unsigned char*g, unsigned char*b) +{ + long* long_data = (long*)data; + (void)ctxcanvas; + cdDecodeColor(long_data[j*n+i], r, g, b); +} + +static void cdpattern(cdCtxCanvas *ctxcanvas, int n, int m, const long int *pattern) +{ + if (ctxcanvas->level1) + return; + + make_pattern(ctxcanvas, n, m, (void*)pattern, long2rgb); +} + +static void uchar2rgb(cdCtxCanvas *ctxcanvas, int n, int i, int j, void* data, unsigned char*r, unsigned char*g, unsigned char*b) +{ + unsigned char* uchar_data = (unsigned char*)data; + if (uchar_data[j*n+i]) + cdDecodeColor(ctxcanvas->canvas->foreground, r, g, b); + else + cdDecodeColor(ctxcanvas->canvas->background, r, g, b); +} + +static void cdstipple(cdCtxCanvas *ctxcanvas, int n, int m, const unsigned char *stipple) +{ + if (ctxcanvas->level1) + return; + + make_pattern(ctxcanvas, n, m, (void*)stipple, uchar2rgb); +} + +static void ucharh2rgb(cdCtxCanvas *ctxcanvas, int n, int i, int j, void* data, unsigned char*r, unsigned char*g, unsigned char*b) +{ + unsigned char* uchar_data = (unsigned char*)data; + static unsigned char hatch; + (void)n; + if (i == 0) hatch = uchar_data[j]; + if (hatch & 0x80) + cdDecodeColor(ctxcanvas->canvas->foreground, r, g, b); + else + cdDecodeColor(ctxcanvas->canvas->background, r, g, b); + _cdRotateHatch(hatch); +} + +static int cdhatch(cdCtxCanvas *ctxcanvas, int style) +{ + if (ctxcanvas->level1) + return ctxcanvas->canvas->hatch_style; + + make_pattern(ctxcanvas, 8, 8, (void*)HatchBits[style], ucharh2rgb); + + return style; +} + +static void add_font_name(cdCtxCanvas *ctxcanvas, char *nativefontname) +{ + int size, i; + for (i = 0; i < ctxcanvas->num_native_font; i++) + { + if (cdStrEqualNoCase(ctxcanvas->nativefontname[i], nativefontname)) + return; + } + + size = strlen(nativefontname)+1; + ctxcanvas->nativefontname[ctxcanvas->num_native_font] = (char*)malloc(size); + memcpy(ctxcanvas->nativefontname[ctxcanvas->num_native_font], nativefontname, size); + ctxcanvas->num_native_font++; +} + +static char *findfont(const char* type_face, int style) +{ + static char font[1024]; + + static char *type[] = + { + "", /* CD_PLAIN */ + "-Bold", /* CD_BOLD */ + "-Oblique", /* CD_ITALIC */ + "-BoldOblique", /* CD_BOLD_ITALIC */ + + "-Roman", /* Plain p/ Times */ + "-Bold", /* Bold p/ Times */ + "-Italic", /* Italic p/ Times */ + "-BoldItalic" /* BoldItalic p/ Times */ + }; + + if (cdStrEqualNoCase(type_face, "System")) + type_face = "Courier"; + + if (cdStrEqualNoCase(type_face, "Times")) + style += 4; + + sprintf(font, "%s%s", type_face, type[style]); + + return font; +} + +static int cdfont(cdCtxCanvas *ctxcanvas, const char *type_face, int style, int size) +{ + char *nativefontname = findfont(type_face, style&3); /* no underline or strikeout support */ + int size_pixel = cdGetFontSizePixels(ctxcanvas->canvas, size); + fprintf(ctxcanvas->file, "%d /%s /%s-Latin1 ChgFnt\n", size_pixel, nativefontname, nativefontname); + add_font_name(ctxcanvas, nativefontname); + return 1; +} + +static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix) +{ + set_default_matrix(ctxcanvas); + + if (matrix) + { + fprintf(ctxcanvas->file, "[%g %g %g %g %g %g] concat\n", matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]); + } + else + { + if (ctxcanvas->rotate_angle) + { + /* rotation = translate to point + rotation + translate back */ + fprintf(ctxcanvas->file, "%d %d translate\n", ctxcanvas->rotate_center_x, ctxcanvas->rotate_center_y); + fprintf(ctxcanvas->file, "%g rotate\n", (double)ctxcanvas->rotate_angle); + fprintf(ctxcanvas->file, "%d %d translate\n", -ctxcanvas->rotate_center_x, -ctxcanvas->rotate_center_y); + } + } +} + +/******************************************************/ +/* client images */ +/******************************************************/ + +static void cdputimagerectrgb(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int i, j, rw, rh; + rw = xmax-xmin+1; + rh = ymax-ymin+1; + (void)ih; + + if (ctxcanvas->level1) + return; + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPutImageRectRGB Start\n"); + + fprintf(ctxcanvas->file, "[0 0 0 0 0 0] currentmatrix\n"); + fprintf(ctxcanvas->file, "%d %d translate\n", x, y); + fprintf(ctxcanvas->file, "%d %d scale\n", w, h); + + fprintf(ctxcanvas->file, "%d %d 8\n", rw, rh); + fprintf(ctxcanvas->file, "[%d 0 0 %d 0 0]\n", rw, rh); + fprintf(ctxcanvas->file, "{currentfile %d string readhexstring pop}\n", rw); + fprintf(ctxcanvas->file, "false 3\n"); + fprintf(ctxcanvas->file, "colorimage\n"); + + for (j=ymin; j<=ymax; j++) + { + for (i=xmin; i<=xmax; i++) + { + int pos = j*iw+i; + fprintf(ctxcanvas->file, "%02x%02x%02x", (int)r[pos], (int)g[pos], (int)b[pos]); + } + + fprintf(ctxcanvas->file, "\n"); + } + + fprintf(ctxcanvas->file, "setmatrix\n"); + + if (ctxcanvas->eps) + { + bbox(ctxcanvas, x, y); + bbox(ctxcanvas, x+rw-1, y+rh-1); + } + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPutImageRectRGBEnd\n"); +} + +static int isgray(int size, const unsigned char *index, const long int *colors) +{ + int i, pal_size = 0; + unsigned char r, g, b; + + for (i = 0; i < size; i++) + { + if (index[i] > pal_size) + pal_size = index[i]; + } + + pal_size++; + + for (i = 0; i < pal_size; i++) + { + cdDecodeColor(colors[i], &r, &g, &b); + + if (i != r || r != g || g != b) + return 0; + } + + return 1; +} + +static void cdputimagerectmap(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *index, const long int *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int i, j, rw, rh, is_gray; + rw = xmax-xmin+1; + rh = ymax-ymin+1; + (void)ih; + + is_gray = isgray(iw*ih, index, colors); + + if (!is_gray && ctxcanvas->level1) + return; + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPutImageRectMap Start\n"); + + fprintf(ctxcanvas->file, "[0 0 0 0 0 0] currentmatrix\n"); + fprintf(ctxcanvas->file, "%d %d translate\n", x, y); + fprintf(ctxcanvas->file, "%d %d scale\n", w, h); + + fprintf(ctxcanvas->file, "%d %d 8\n", rw, rh); + fprintf(ctxcanvas->file, "[%d 0 0 %d 0 0]\n", rw, rh); + fprintf(ctxcanvas->file, "{currentfile %d string readhexstring pop}\n", rw); + + if (is_gray) + { + fprintf(ctxcanvas->file, "image\n"); + + for (j=ymin; j<=ymax; j++) + { + for (i=xmin; i<=xmax; i++) + { + int pos = j*iw+i; + fprintf(ctxcanvas->file, "%02x", (int)index[pos]); + } + + fprintf(ctxcanvas->file, "\n"); + } + } + else + { + fprintf(ctxcanvas->file, "false 3\n"); + fprintf(ctxcanvas->file, "colorimage\n"); + + for (j=ymin; j<=ymax; j++) + { + for (i=xmin; i<=xmax; i++) + { + int pos = j*iw+i; + unsigned char r, g, b; + cdDecodeColor(colors[index[pos]], &r, &g, &b); + fprintf(ctxcanvas->file, "%02x%02x%02x", (int)r, (int)g, (int)b); + } + + fprintf(ctxcanvas->file, "\n"); + } + } + + fprintf(ctxcanvas->file, "setmatrix\n"); + + if (ctxcanvas->eps) + { + bbox(ctxcanvas, x, y); + bbox(ctxcanvas, x+rw-1, y+rh-1); + } + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPutImageRectMapEnd\n"); +} + +/******************************************************/ +/* server images */ +/******************************************************/ + +static void cdpixel(cdCtxCanvas *ctxcanvas, int x, int y, long int color) +{ + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPixel Start\n"); + + fprintf(ctxcanvas->file, "%g %g %g setrgbcolor\n", + get_red(color), get_green(color), get_blue(color)); + + if (ctxcanvas->level1) + { + fprintf(ctxcanvas->file, "N\n"); + fprintf(ctxcanvas->file, "%d %d 1 0 360 arc\n", x, y); + fprintf(ctxcanvas->file, "C fill\n"); + } + else + fprintf(ctxcanvas->file, "%d %d 1 1 RF\n", x, y); + + if (ctxcanvas->eps) + bbox(ctxcanvas, x, y); + + if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPixelEnd\n"); +} + +/******************************************************/ +/* custom attributes */ +/******************************************************/ + +static void set_rotate_attrib(cdCtxCanvas *ctxcanvas, char* data) +{ + /* ignore ROTATE if transform is set */ + if (ctxcanvas->canvas->use_matrix) + return; + + if (data) + { + sscanf(data, "%g %d %d", &ctxcanvas->rotate_angle, + &ctxcanvas->rotate_center_x, + &ctxcanvas->rotate_center_y); + } + else + { + ctxcanvas->rotate_angle = 0; + ctxcanvas->rotate_center_x = 0; + ctxcanvas->rotate_center_y = 0; + } + + set_default_matrix(ctxcanvas); + + if (ctxcanvas->rotate_angle) + { + /* rotation = translate to point + rotation + translate back */ + fprintf(ctxcanvas->file, "%d %d translate\n", ctxcanvas->rotate_center_x, ctxcanvas->rotate_center_y); + fprintf(ctxcanvas->file, "%g rotate\n", (double)ctxcanvas->rotate_angle); + fprintf(ctxcanvas->file, "%d %d translate\n", -ctxcanvas->rotate_center_x, -ctxcanvas->rotate_center_y); + } +} + +static char* get_rotate_attrib(cdCtxCanvas *ctxcanvas) +{ + static char data[100]; + + if (!ctxcanvas->rotate_angle) + return NULL; + + sprintf(data, "%g %d %d", (double)ctxcanvas->rotate_angle, + ctxcanvas->rotate_center_x, + ctxcanvas->rotate_center_y); + + return data; +} + +static cdAttribute rotate_attrib = +{ + "ROTATE", + set_rotate_attrib, + get_rotate_attrib +}; + +static void set_cmd_attrib(cdCtxCanvas *ctxcanvas, char* data) +{ + fprintf(ctxcanvas->file, data); +} + +static cdAttribute cmd_attrib = +{ + "CMD", + set_cmd_attrib, + NULL +}; + +static void set_poly_attrib(cdCtxCanvas *ctxcanvas, char* data) +{ + int hole; + + if (data == NULL) + { + ctxcanvas->holes = 0; + return; + } + + sscanf(data, "%d", &hole); + ctxcanvas->poly_holes[ctxcanvas->holes] = hole; + ctxcanvas->holes++; +} + +static char* get_poly_attrib(cdCtxCanvas *ctxcanvas) +{ + static char holes[10]; + sprintf(holes, "%d", ctxcanvas->holes); + return holes; +} + +static cdAttribute poly_attrib = +{ + "POLYHOLE", + set_poly_attrib, + get_poly_attrib +}; + +/* +%F Cria um novo canvas PS +Parametros passados em data: +nome nome do arquivo de saida <= 255 caracteres +-p[num] tamanho do papel (A0-5, LETTER, LEGAL) +-w[num] largura do papel em milimetros +-h[num] altura do papel em milimetros +-l[num] margem esquerda em milimetros +-r[num] margem direita em milimetros +-b[num] margem inferior em milimetros +-t[num] margem superior em milimetros +-s[num] resolucao em dpi +-e encapsulated postscript +-1 level 1 operators only +-d[num] margem da bbox em milimetros para eps +*/ +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + char *line = (char *)data; + cdCtxCanvas *ctxcanvas; + char filename[10240] = ""; + + ctxcanvas = (cdCtxCanvas *)malloc(sizeof(cdCtxCanvas)); + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + + line += cdGetFileName(line, filename); + if (filename[0] == 0) + return; + + if ((ctxcanvas->file = fopen(filename, "w")) == NULL) + { + free(ctxcanvas); + return; + } + + ctxcanvas->holes = 0; + cdRegisterAttribute(canvas, &poly_attrib); + cdRegisterAttribute(canvas, &cmd_attrib); + cdRegisterAttribute(canvas, &rotate_attrib); + + setpsdefaultvalues(ctxcanvas); + + while (*line != '\0') + { + while (*line != '\0' && *line != '-') + line++; + + if (*line != '\0') + { + float num; + line++; + switch (*line++) + { + case 'p': + { + int paper; + sscanf(line, "%d", &paper); + setpspapersize(ctxcanvas, paper); + break; + } + case 'w': + sscanf(line, "%g", &num); + ctxcanvas->width = mm2pt(num); + break; + case 'h': + sscanf(line, "%g", &num); + ctxcanvas->height = mm2pt(num); + break; + case 'l': + sscanf(line, "%g", &num); + ctxcanvas->xmin = num; + break; + case 'r': + sscanf(line, "%g", &num); + ctxcanvas->xmax = num; /* right margin, must be converted to xmax */ + break; + case 'b': + sscanf(line, "%g", &num); + ctxcanvas->ymin = num; + break; + case 't': + sscanf(line, "%g", &num); + ctxcanvas->ymax = num; /* top margin, must be converted to ymax */ + break; + case 's': + sscanf(line, "%d", &(ctxcanvas->res)); + break; + case 'e': + ctxcanvas->eps = 1; + break; + case 'o': + ctxcanvas->landscape = 1; + break; + case '1': + ctxcanvas->level1 = 1; + break; + case 'g': + ctxcanvas->debug = 1; + break; + case 'd': + sscanf(line, "%g", &num); + ctxcanvas->bbmargin = num; + break; + } + } + + while (*line != '\0' && *line != ' ') + line++; + } + + /* store the base canvas */ + ctxcanvas->canvas = canvas; + + /* update canvas context */ + canvas->ctxcanvas = ctxcanvas; + + if (ctxcanvas->landscape == 1) + { + _cdSwapDouble(ctxcanvas->width, ctxcanvas->height); + _cdSwapDouble(ctxcanvas->xmin, ctxcanvas->ymin); + _cdSwapDouble(ctxcanvas->xmax, ctxcanvas->ymax); + } + + init_ps(ctxcanvas); +} + +static void cdinittable(cdCanvas* canvas) +{ + canvas->cxFlush = cdflush; + canvas->cxPixel = cdpixel; + canvas->cxLine = cdline; + canvas->cxPoly = cdpoly; + canvas->cxRect = cdrect; + canvas->cxBox = cdbox; + canvas->cxArc = cdarc; + canvas->cxSector = cdsector; + canvas->cxChord = cdchord; + canvas->cxText = cdtext; + canvas->cxPutImageRectRGB = cdputimagerectrgb; + canvas->cxPutImageRectMap = cdputimagerectmap; + canvas->cxFLine = cdfline; + canvas->cxFPoly = cdfpoly; + canvas->cxFRect = cdfrect; + canvas->cxFBox = cdfbox; + canvas->cxFArc = cdfarc; + canvas->cxFSector = cdfsector; + canvas->cxFChord = cdfchord; + canvas->cxClip = cdclip; + canvas->cxFClipArea = cdfcliparea; + canvas->cxLineStyle = cdlinestyle; + canvas->cxLineWidth = cdlinewidth; + canvas->cxLineCap = cdlinecap; + canvas->cxLineJoin = cdlinejoin; + canvas->cxPattern = cdpattern; + canvas->cxStipple = cdstipple; + canvas->cxHatch = cdhatch; + canvas->cxFont = cdfont; + canvas->cxTransform = cdtransform; + canvas->cxKillCanvas = cdkillcanvas; + canvas->cxDeactivate = cddeactivate; +} + +static cdContext cdPSContext = +{ + CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_PLAY | CD_CAP_PALETTE | + CD_CAP_REGION | CD_CAP_IMAGESRV | + CD_CAP_BACKGROUND | CD_CAP_BACKOPACITY | CD_CAP_WRITEMODE | + CD_CAP_FONTDIM | CD_CAP_TEXTSIZE | + CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB), + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + +cdContext* cdContextPS(void) +{ + return &cdPSContext; +} diff --git a/src/drv/cgm.c b/src/drv/cgm.c new file mode 100644 index 0000000..55461cb --- /dev/null +++ b/src/drv/cgm.c @@ -0,0 +1,2281 @@ +/** \file + * \brief CGM library + * Extracted from GKS/PUC + * + * See Copyright Notice in cd.h + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include <float.h> +#include <limits.h> + +#include "cgm.h" + + +struct _cgmFunc +{ + /* write command header */ + void (*wch)( CGM *, int, int, int ); + + /* put colour index at colour index precision */ + void (*ci)( CGM *, unsigned long ); + + /* put color direct at colour direct precision */ + void (*cd)( CGM *, double ); + + /* put color direct at colour direct precision */ + void (*rgb)( CGM *, double, double, double ); + + /* put index at index precision */ + void (*ix)( CGM *, long ); + + /* put enum ( int*2 ) */ + void (*e)( CGM *, int, const char *l[] ); + + /* put int ( integer precision ) */ + void (*i)( CGM *, long ); + + /* put unsigned int ( integer precision ) */ + void (*u)( CGM *, unsigned long ); + + /* put real ( real precision ) */ + void (*r)( CGM *, double ); + + /* put string */ + void (*s)( CGM *, const char * ); + + /* put VDC at VDC mode and precision */ + void (*vdc)( CGM *, double ); + + /* put point at VDC mode and precision */ + void (*p)( CGM *, double, double ); + + /* put colour at colour mode and precision */ + void (*co)( CGM *, const void * ); + + /* put separator */ + void (*sep)( CGM *, const char * ); + + /* get column position */ + int (*get_col)( CGM * ); + + /* align at column number */ + void (*align)( CGM *, int ); + + /* nova linha */ + void (*nl)( CGM * ); + + /* terminate element */ + int (*term)( CGM * ); +}; + +typedef struct _cgmCommand +{ + const char *ct; + const char *c; +} cgmCommand; + +/************************************************ +* * +* Dados para nao-binario * +* * +************************************************/ + +/* delimiter elements */ + +static const cgmCommand _cgmX_NULL = { "" , "" }; +static const cgmCommand _cgmX_BEGMF = { "BEGMF" , "\x30\x20" }; +static const cgmCommand _cgmX_ENDMF = { "ENDMF" , "\x30\x21" }; +static const cgmCommand _cgmX_BEG_PIC = { "BEG_PIC" , "\x30\x22" }; +static const cgmCommand _cgmX_BEG_PIC_BODY = { "BEG_PIC_BODY" , "\x30\x23" }; +static const cgmCommand _cgmX_END_PIC = { "END_PIC" , "\x30\x24" }; + +/* metafile descriptor elements */ + +static const cgmCommand _cgmX_MF_VERSION = { "MF_VERSION" , "\x31\x20" }; +static const cgmCommand _cgmX_MF_DESC = { "MF_DESC" , "\x31\x21" }; +static const cgmCommand _cgmX_VDC_TYPE = { "VDC_TYPE" , "\x31\x22" }; +static const cgmCommand _cgmX_INTEGER_PREC = { "INTEGER_PREC" , "\x31\x23" }; +static const cgmCommand _cgmX_REAL_PREC = { "REAL_PREC" , "\x31\x24" }; +static const cgmCommand _cgmX_INDEX_PREC = { "INDEX_PREC" , "\x31\x25" }; +static const cgmCommand _cgmX_COLR_PREC = { "COLR_PREC" , "\x31\x26" }; +static const cgmCommand _cgmX_COLR_INDEX_PREC = { "COLR_INDEX_PREC" , "\x31\x27" }; +static const cgmCommand _cgmX_MAX_COLR_INDEX = { "MAX_COLR_INDEX" , "\x31\x28" }; +static const cgmCommand _cgmX_COLR_VALUE_EXT = { "COLR_VALUE_EXT" , "\x31\x29" }; +static const cgmCommand _cgmX_MF_ELEM_LIST = { "MF_ELEM_LIST" , "\x31\x2a" }; +static const cgmCommand _cgmX_BEG_MF_DEFAULTS = { "BEG_MF_DEFAULTS" , "\x31\x2b" }; +static const cgmCommand _cgmX_END_MF_DEFAULTS = { "END_MF_DEFAULTS" , "\x31\x2c" }; +static const cgmCommand _cgmX_FONT_LIST = { "FONT_LIST" , "\x31\x2d" }; +static const cgmCommand _cgmX_CHAR_SET_LIST = { "CHAR_SET_LIST" , "\x31\x2e" }; +static const cgmCommand _cgmX_CHAR_CODING = { "CHAR_CODING" , "\x31\x2f" }; + +/* picture descriptor elements */ + +static const cgmCommand _cgmX_SCALE_MODE = { "SCALE_MODE" , "\x30\x20" }; +static const cgmCommand _cgmX_COLR_MODE = { "COLR_MODE" , "\x30\x21" }; +static const cgmCommand _cgmX_LINE_WIDTH_MODE = { "LINE_WIDTH_MODE" , "\x30\x22" }; +static const cgmCommand _cgmX_MARKER_SIZE_MODE = { "MARKER_SIZE_MODE" , "\x30\x23" }; +static const cgmCommand _cgmX_EDGE_WIDTH_MODE = { "EDGE_WIDTH_MODE" , "\x30\x24" }; +static const cgmCommand _cgmX_VDC_EXTENT = { "VDC_EXT" , "\x30\x25" }; +static const cgmCommand _cgmX_BACK_COLR = { "BACK_COLR" , "\x30\x26" }; + +/* control elements */ + +static const cgmCommand _cgmX_VDC_INTEGER_PREC = { "VDC_INTEGER_PREC" , "\x30\x20" }; +static const cgmCommand _cgmX_VDC_REAL_PREC = { "VDC_REAL_PREC" , "\x30\x21" }; +static const cgmCommand _cgmX_AUX_COLR = { "AUX_COLR" , "\x30\x22" }; +static const cgmCommand _cgmX_TRANSPARENCY = { "TRANSPARENCY" , "\x30\x23" }; +static const cgmCommand _cgmX_CLIP_RECT = { "CLIP_RECT" , "\x30\x24" }; +static const cgmCommand _cgmX_CLIP = { "CLIP" , "\x30\x25" }; + +/* primitive elements */ + +static const cgmCommand _cgmX_LINE = { "LINE" , "\x20" }; +static const cgmCommand _cgmX_DISJT_LINE = { "DISJT_LINE" , "\x21" }; +static const cgmCommand _cgmX_MARKER = { "MARKER" , "\x22" }; +static const cgmCommand _cgmX_TEXT = { "TEXT" , "\x23" }; +static const cgmCommand _cgmX_RESTR_TEXT = { "RESTR_TEXT" , "\x24" }; +static const cgmCommand _cgmX_APND_TEXT = { "APND_TEXT" , "\x25" }; +static const cgmCommand _cgmX_POLYGON = { "POLYGON" , "\x26" }; +static const cgmCommand _cgmX_POLYGON_SET = { "POLYGON_SET" , "\x27" }; +static const cgmCommand _cgmX_CELL_ARRAY = { "CELL_ARRAY" , "\x28" }; +static const cgmCommand _cgmX_GDP = { "GDP" , "\x29" }; +static const cgmCommand _cgmX_RECT = { "RECT" , "\x2a" }; +static const cgmCommand _cgmX_CIRCLE = { "CIRCLE" , "\x34\x20" }; +static const cgmCommand _cgmX_ARC_3_PT = { "ARC_3_PT" , "\x34\x21" }; +static const cgmCommand _cgmX_ARC_3_PT_CLOSE = { "ARC_3_PT_CLOSE" , "\x34\x22" }; +static const cgmCommand _cgmX_ARC_CTR = { "ARC_CTR" , "\x34\x23" }; +static const cgmCommand _cgmX_ARC_CTR_CLOSE = { "ARC_CTR_CLOSE" , "\x34\x24" }; +static const cgmCommand _cgmX_ELLIPSE = { "ELLIPSE" , "\x34\x25" }; +static const cgmCommand _cgmX_ELLIP_ARC = { "ELLIP_ARC" , "\x34\x26" }; +static const cgmCommand _cgmX_ELLIP_ARC_CLOSE = { "ELLIP_ARC_CLOSE" , "\x34\x27" }; + +/* attribute elements */ + +static const cgmCommand _cgmX_LINE_INDEX = { "LINE_INDEX" , "\x35\x20" }; +static const cgmCommand _cgmX_LINE_TYPE = { "LINE_TYPE" , "\x35\x21" }; +static const cgmCommand _cgmX_LINE_WIDTH = { "LINE_WIDTH" , "\x35\x22" }; +static const cgmCommand _cgmX_LINE_COLR = { "LINE_COLR" , "\x35\x23" }; +static const cgmCommand _cgmX_MARKER_INDEX = { "MARKER_INDEX" , "\x35\x24" }; +static const cgmCommand _cgmX_MARKER_TYPE = { "MARKER_TYPE" , "\x35\x25" }; +static const cgmCommand _cgmX_MARKER_WIDTH = { "MARKER_SIZE" , "\x35\x26" }; +static const cgmCommand _cgmX_MARKER_COLR = { "MARKER_COLR" , "\x35\x27" }; +static const cgmCommand _cgmX_TEXT_INDEX = { "TEXT_INDEX" , "\x35\x30" }; +static const cgmCommand _cgmX_TEXT_FONT_INDEX = { "TEXT_FONT_INDEX" , "\x35\x31" }; +static const cgmCommand _cgmX_TEXT_PREC = { "TEXT_PREC" , "\x35\x32" }; +static const cgmCommand _cgmX_CHAR_EXPAN = { "CHAR_EXPAN" , "\x35\x33" }; +static const cgmCommand _cgmX_CHAR_SPACE = { "CHAR_SPACE" , "\x35\x34" }; +static const cgmCommand _cgmX_TEXT_COLR = { "TEXT_COLR" , "\x35\x35" }; +static const cgmCommand _cgmX_CHAR_HEIGHT = { "CHAR_HEIGHT" , "\x35\x36" }; +static const cgmCommand _cgmX_CHAR_ORI = { "CHAR_ORI" , "\x35\x37" }; +static const cgmCommand _cgmX_TEXT_PATH = { "TEXT_PATH" , "\x35\x38" }; +static const cgmCommand _cgmX_TEXT_ALIGN = { "TEXT_ALIGN" , "\x35\x39" }; +static const cgmCommand _cgmX_CHAR_SET_INDEX = { "CHAR_SET_INDEX" , "\x35\x3a" }; +static const cgmCommand _cgmX_ALT_CHAR_SET = { "ALT_CHAR_SET_INDEX" , "\x35\x3b" }; +static const cgmCommand _cgmX_FILL_INDEX = { "FILL_INDEX" , "\x36\x20" }; +static const cgmCommand _cgmX_INT_STYLE = { "INT_STYLE" , "\x36\x21" }; +static const cgmCommand _cgmX_FILL_COLR = { "FILL_COLR" , "\x36\x22" }; +static const cgmCommand _cgmX_HATCH_INDEX = { "HATCH_INDEX" , "\x36\x23" }; +static const cgmCommand _cgmX_PAT_INDEX = { "PAT_INDEX" , "\x36\x24" }; +static const cgmCommand _cgmX_EDGE_INDEX = { "EDGE_INDEX" , "\x36\x25" }; +static const cgmCommand _cgmX_EDGE_TYPE = { "EDGE_TYPE" , "\x36\x26" }; +static const cgmCommand _cgmX_EDGE_WIDTH = { "EDGE_WIDTH" , "\x36\x27" }; +static const cgmCommand _cgmX_EDGE_COLR = { "EDGE_COLR" , "\x36\x28" }; +static const cgmCommand _cgmX_EDGE_VIS = { "EDGE_VIS" , "\x36\x29" }; +static const cgmCommand _cgmX_FILL_REF_PT = { "FILL_REF_PT" , "\x36\x2a" }; +static const cgmCommand _cgmX_PAT_TABLE = { "PAT_TABLE" , "\x36\x2b" }; +static const cgmCommand _cgmX_PAT_SIZE = { "PAT_SIZE" , "\x36\x2c" }; +static const cgmCommand _cgmX_COLR_TABLE = { "COLR_TABLE" , "\x36\x30" }; +static const cgmCommand _cgmX_ASF = { "ASF" , "\x36\x31" }; + +/* escape elements */ + +static const cgmCommand _cgmX_ESCAPE = { "ESCAPE" , "\x37\x20" }; +static const cgmCommand _cgmX_DOMAIN_RING = { "DOMAIN_RING" , "\x37\x30" }; + +/* external elements */ + +static const cgmCommand _cgmX_MESSAGE = { "MESSAGE" , "\x37\x21" }; +static const cgmCommand _cgmX_APPL_DATA = { "APPL_DATA" , "\x37\x22" }; + +/* drawing sets */ +static const cgmCommand _cgmX_DRAWING_SET = { "drawing_set" , "\x40" }; +static const cgmCommand _cgmX_DRAWING_PLUS = { "drawing_plus" , "\x41" }; + +static const cgmCommand *_elements_list_sets[] = { + & _cgmX_DRAWING_SET, + & _cgmX_DRAWING_PLUS, + NULL }; + + +static const cgmCommand *delimiter[] = { + & _cgmX_NULL, + & _cgmX_BEGMF, + & _cgmX_ENDMF, + & _cgmX_BEG_PIC, + & _cgmX_BEG_PIC_BODY, + & _cgmX_END_PIC, + NULL }; + +static const cgmCommand *metafile[] = { + & _cgmX_END_MF_DEFAULTS, + & _cgmX_MF_VERSION, + & _cgmX_MF_DESC, + & _cgmX_VDC_TYPE, + & _cgmX_INTEGER_PREC, + & _cgmX_REAL_PREC, + & _cgmX_INDEX_PREC, + & _cgmX_COLR_PREC, + & _cgmX_COLR_INDEX_PREC, + & _cgmX_MAX_COLR_INDEX, + & _cgmX_COLR_VALUE_EXT, + & _cgmX_MF_ELEM_LIST, + & _cgmX_BEG_MF_DEFAULTS, + & _cgmX_FONT_LIST, + & _cgmX_CHAR_SET_LIST, + & _cgmX_CHAR_CODING, + NULL }; + +static const cgmCommand *picture[] = { + & _cgmX_NULL, + & _cgmX_SCALE_MODE, + & _cgmX_COLR_MODE, + & _cgmX_LINE_WIDTH_MODE, + & _cgmX_MARKER_SIZE_MODE, + & _cgmX_EDGE_WIDTH_MODE, + & _cgmX_VDC_EXTENT, + & _cgmX_BACK_COLR, + NULL }; + +static const cgmCommand *control[] = { + & _cgmX_NULL, + & _cgmX_VDC_INTEGER_PREC, + & _cgmX_VDC_REAL_PREC, + & _cgmX_AUX_COLR, + & _cgmX_TRANSPARENCY, + & _cgmX_CLIP_RECT, + & _cgmX_CLIP, + NULL }; + +static const cgmCommand *primitive[] = { + & _cgmX_NULL, + & _cgmX_LINE, + & _cgmX_DISJT_LINE, + & _cgmX_MARKER, + & _cgmX_TEXT, + & _cgmX_RESTR_TEXT, + & _cgmX_APND_TEXT, + & _cgmX_POLYGON, + & _cgmX_POLYGON_SET, + & _cgmX_CELL_ARRAY, + & _cgmX_GDP, + & _cgmX_RECT, + & _cgmX_CIRCLE, + & _cgmX_ARC_3_PT, + & _cgmX_ARC_3_PT_CLOSE, + & _cgmX_ARC_CTR, + & _cgmX_ARC_CTR_CLOSE, + & _cgmX_ELLIPSE, + & _cgmX_ELLIP_ARC, + & _cgmX_ELLIP_ARC_CLOSE, + NULL }; + +static const cgmCommand *attributes[] = { + & _cgmX_NULL, + & _cgmX_LINE_INDEX, + & _cgmX_LINE_TYPE, + & _cgmX_LINE_WIDTH, + & _cgmX_LINE_COLR, + & _cgmX_MARKER_INDEX, + & _cgmX_MARKER_TYPE, + & _cgmX_MARKER_WIDTH, + & _cgmX_MARKER_COLR, + & _cgmX_TEXT_INDEX, + & _cgmX_TEXT_FONT_INDEX, + & _cgmX_TEXT_PREC, + & _cgmX_CHAR_EXPAN, + & _cgmX_CHAR_SPACE, + & _cgmX_TEXT_COLR, + & _cgmX_CHAR_HEIGHT, + & _cgmX_CHAR_ORI, + & _cgmX_TEXT_PATH, + & _cgmX_TEXT_ALIGN, + & _cgmX_CHAR_SET_INDEX, + & _cgmX_ALT_CHAR_SET, + & _cgmX_FILL_INDEX, + & _cgmX_INT_STYLE, + & _cgmX_FILL_COLR, + & _cgmX_HATCH_INDEX, + & _cgmX_PAT_INDEX, + & _cgmX_EDGE_INDEX, + & _cgmX_EDGE_TYPE, + & _cgmX_EDGE_WIDTH, + & _cgmX_EDGE_COLR, + & _cgmX_EDGE_VIS, + & _cgmX_FILL_REF_PT, + & _cgmX_PAT_TABLE, + & _cgmX_PAT_SIZE, + & _cgmX_COLR_TABLE, + & _cgmX_ASF, + NULL }; + +static const cgmCommand *escape[] = { + & _cgmX_NULL, + & _cgmX_ESCAPE, + & _cgmX_DOMAIN_RING, + NULL }; + +static const cgmCommand *external[] = { + & _cgmX_NULL, + & _cgmX_MESSAGE, + & _cgmX_APPL_DATA, + NULL }; + +static const cgmCommand **comandos[] = { + _elements_list_sets, + delimiter, + metafile, + picture, + control, + primitive, + attributes, + escape, + external, + NULL }; + +#define unit (cgm->file) + +/************************************************ +* * +* listas de funcoes necessarias * +* * +************************************************/ + + +static void cgmb_wch ( CGM *, int, int, int ); /* write command header */ +static void cgmb_ci ( CGM *, unsigned long ); /* put colour index at colour index precision */ +static void cgmb_cd ( CGM *, double ); /* put color direct at colour direct precision */ +static void cgmb_rgb ( CGM *, double, double, double ); /* put color direct (rgb) at colour direct precision */ +static void cgmb_ix ( CGM *, long ); /* put index at index precision */ +static void cgmb_e ( CGM *, int, const char *l[] ); /* put enum ( int*2 ) */ +static void cgmb_i ( CGM *, long ); /* put int ( integer precision ) */ +static void cgmb_u ( CGM *, unsigned long ); /* put unsigned int ( integer precision ) */ +static void cgmb_r ( CGM *, double ); /* put real ( real precision ) */ +static void cgmb_s ( CGM *, const char * ); /* put string */ +static void cgmb_vdc ( CGM *, double ); /* put VDC at VDC mode and precision */ +static void cgmb_p ( CGM *, double, double ); /* put point at VDC mode and precision */ +static void cgmb_co ( CGM *, const void * ); /* put colour at colour mode and precision */ +static void cgmb_sep ( CGM *, const char * ); /* put separator */ +static int cgmb_get_col ( CGM * ); /* get column position */ +static void cgmb_align ( CGM *, int ); /* align at column number */ +static void cgmb_nl ( CGM * ); /* new line */ +static int cgmb_term ( CGM * ); /* terminate element */ + +static const CGMFUNC cgmf_binary = { + cgmb_wch , + cgmb_ci , + cgmb_cd , + cgmb_rgb , + cgmb_ix , + cgmb_e , + cgmb_i , + cgmb_u , + cgmb_r , + cgmb_s , + cgmb_vdc , + cgmb_p , + cgmb_co , + cgmb_sep , + cgmb_get_col, + cgmb_align , + cgmb_nl , + cgmb_term + }; + +static void cgmt_wch ( CGM *, int, int, int ); /* write command header */ +static void cgmt_ci ( CGM *, unsigned long ); /* put colour index at colour index precision */ +static void cgmt_cd ( CGM *, double ); /* put color direct at colour direct precision */ +static void cgmt_rgb ( CGM *, double, double, double ); /* put color direct (rgb) at colour direct precision */ +static void cgmt_ix ( CGM *, long ); /* put index at index precision */ +static void cgmt_e ( CGM *, int, const char *l[] ); /* put enum ( int*2 ) */ +static void cgmt_i ( CGM *, long ); /* put int ( integer precision ) */ +static void cgmt_u ( CGM *, unsigned long ); /* put unsigned int ( integer precision ) */ +static void cgmt_r ( CGM *, double ); /* put real ( real precision ) */ +static void cgmt_s ( CGM *, const char * ); /* put string */ +static void cgmt_vdc ( CGM *, double ); /* put VDC at VDC mode and precision */ +static void cgmt_p ( CGM *, double, double ); /* put point at VDC mode and precision */ +static void cgmt_co ( CGM *, const void * ); /* put colour at colour mode and precision */ +static void cgmt_sep ( CGM *, const char * ); /* put separator */ +static int cgmt_get_col ( CGM * ); /* get column position */ +static void cgmt_align ( CGM *, int ); /* align at column number */ +static void cgmt_nl ( CGM * ); /* new line */ +static int cgmt_term ( CGM * ); /* terminate element */ + +static const CGMFUNC cgmf_clear_text = { + cgmt_wch , + cgmt_ci , + cgmt_cd , + cgmt_rgb , + cgmt_ix , + cgmt_e , + cgmt_i , + cgmt_u , + cgmt_r , + cgmt_s , + cgmt_vdc , + cgmt_p , + cgmt_co , + cgmt_sep , + cgmt_get_col, + cgmt_align , + cgmt_nl , + cgmt_term + }; + +static void cgmc_wch ( CGM *, int, int, int ); /* write command header */ +static void cgmc_ci ( CGM *, unsigned long ); /* put colour index at colour index precision */ +static void cgmc_cd ( CGM *, double ); /* put color direct at colour direct precision */ +static void cgmc_rgb ( CGM *, double, double, double ); /* put color direct (rgb) at colour direct precision */ +static void cgmc_ix ( CGM *, long ); /* put index at index precision */ +static void cgmc_e ( CGM *, int, const char *l[] ); /* put enum ( int*2 ) */ +static void cgmc_i ( CGM *, long ); /* put int ( integer precision ) */ +static void cgmc_u ( CGM *, unsigned long ); /* put unsigned int ( integer precision ) */ +static void cgmc_r ( CGM *, double ); /* put real ( real precision ) */ +static void cgmc_s ( CGM *, const char * ); /* put string */ +static void cgmc_vdc ( CGM *, double ); /* put VDC at VDC mode and precision */ +static void cgmc_p ( CGM *, double, double ); /* put point at VDC mode and precision */ +static void cgmc_co ( CGM *, const void * ); /* put colour at colour mode and precision */ +static void cgmc_sep ( CGM *, const char * ); /* put separator */ +static int cgmc_get_col ( CGM * ); /* get column position */ +static void cgmc_align ( CGM *, int ); /* align at column number */ +static void cgmc_nl ( CGM * ); /* new line */ +static int cgmc_term ( CGM * ); /* terminate element */ + +static const CGMFUNC cgmf_character = { + cgmc_wch , + cgmc_ci , + cgmc_cd , + cgmc_rgb , + cgmc_ix , + cgmc_e , + cgmc_i , + cgmc_u , + cgmc_r , + cgmc_s , + cgmc_vdc , + cgmc_p , + cgmc_co , + cgmc_sep , + cgmc_get_col, + cgmc_align , + cgmc_nl , + cgmc_term + }; + +static const CGMFUNC *cgmf[] = { &cgmf_character, &cgmf_binary, &cgmf_clear_text }; + +/************************************************ +* * +* Funcoes para binario * +* * +************************************************/ + +#define cgmb_putw cgmb_putu16 +#define cgmb_putb(a,b) cgmb_putc((a),(int)(b)) + +static void cgmb_putw ( CGM *, unsigned ); + +static void cgmb_putc ( CGM *cgm, int b ) +{ + if ( cgm->op != -1 ) + { + register int i; + for ( i=cgm->op; i>=0; i-- ) + { + if ( cgm->bc[i] == 32766 - 2*i ) + { + long po = ftell(unit); + int op = cgm->op; + + cgm->op = -1; + fseek(unit, cgm->po[i] , SEEK_SET); + cgmb_putw ( cgm, (1 << 15) | (cgm->bc[i]) ); + + cgm->op = i - 1; + fseek(unit, po, SEEK_SET); + cgmb_putw ( cgm, 0 ); + + cgm->op = op; + cgm->bc[i] = 0; + cgm->po[i] = po; + } + cgm->bc[i] ++; + } + } + + fputc ( b, unit ); +} + + +static void cgmb_puti8 ( CGM *cgm, int b ) +{ + cgmb_putb ( cgm, b ); +} + +static void cgmb_puti16 ( CGM *cgm, int b ) +{ + cgmb_putb ( cgm, b >> 8 ); + cgmb_putb ( cgm, b ); +} + +static void cgmb_puti24 ( CGM *cgm, long b ) +{ + cgmb_putb ( cgm, b >> 16 ); + cgmb_putb ( cgm, b >> 8 ); + cgmb_putb ( cgm, b ); +} + +static void cgmb_puti32 ( CGM *cgm, long b ) +{ + cgmb_putb ( cgm, b >> 24 ); + cgmb_putb ( cgm, b >> 16 ); + cgmb_putb ( cgm, b >> 8 ); + cgmb_putb ( cgm, b ); +} + +static void cgmb_putu8 ( CGM *cgm, unsigned int b ) +{ + cgmb_putb ( cgm, b ); +} + +static void cgmb_putu16 ( CGM *cgm, unsigned int b ) +{ + cgmb_putb ( cgm, b >> 8 ); + cgmb_putb ( cgm, b ); +} + +static void cgmb_putu24 ( CGM *cgm, unsigned long b ) +{ + cgmb_putb ( cgm, b >> 16 ); + cgmb_putb ( cgm, b >> 8 ); + cgmb_putb ( cgm, b ); +} + +static void cgmb_putu32 ( CGM *cgm, unsigned long b ) +{ + cgmb_putb ( cgm, b >> 24 ); + cgmb_putb ( cgm, b >> 16 ); + cgmb_putb ( cgm, b >> 8 ); + cgmb_putb ( cgm, b ); +} + +static void cgmb_putfl32 ( CGM *cgm, float b ) +{ + union { + float func; + long l; + } r; + r.func = b; + cgmb_putb ( cgm, r.l >> 24 ); + cgmb_putb ( cgm, r.l >> 16 ); + cgmb_putb ( cgm, r.l >> 8 ); + cgmb_putb ( cgm, r.l ); +} + +static void cgmb_putfl64 ( CGM *cgm, double b ) +{ + union { + double d; + long l[2]; + } r; + r.d = b; + cgmb_putb ( cgm, r.l[1] >> 24 ); + cgmb_putb ( cgm, r.l[1] >> 16 ); + cgmb_putb ( cgm, r.l[1] >> 8 ); + cgmb_putb ( cgm, r.l[1] ); + cgmb_putb ( cgm, r.l[0] >> 24 ); + cgmb_putb ( cgm, r.l[0] >> 16 ); + cgmb_putb ( cgm, r.l[0] >> 8 ); + cgmb_putb ( cgm, r.l[0] ); +} + +static void cgmb_putfx32 ( CGM *cgm, float b ) +{ + int si = ( int ) floor ( b ); + unsigned int ui = ( unsigned int ) ( (b - si) * 65536.0 ); + + cgmb_puti16 ( cgm, si ); + cgmb_puti16 ( cgm, ui ); +} + +static void cgmb_putfx64 ( CGM *cgm, double b ) +{ + long si = ( long ) floor ( b ); + unsigned long ui = ( unsigned long ) ( (b - si) * 65536.0 * 65536.0 ); + + cgmb_puti32 ( cgm, si ); + cgmb_puti32 ( cgm, ui ); +} + +static void cgmb_wch ( CGM* cgm, int c, int id, int len ) +{ + + /* if ( len & 1 ) len ++; */ /* word aligned */ + + if ( len > 30 ) + cgmb_putw ( cgm, (c << 12) | ( id << 5 ) | 31 ); + else + cgmb_putw ( cgm, (c << 12) | ( id << 5 ) | (int)(len) ); + + + cgm->op++; + + if ( len > 30 ) + { + cgm->po[cgm->op] = ftell(unit); + cgmb_putw ( cgm, 0 ); + } + else + cgm->po[cgm->op] = 0L; + + cgm->bc[cgm->op] = 0; + +} + +static void cgmb_ci ( CGM *cgm, unsigned long ci ) +{ + switch ( cgm->cix_prec ) + { + case 0: cgmb_putu8 ( cgm, (unsigned)ci ); break; + case 1: cgmb_putu16 ( cgm, (unsigned)ci ); break; + case 2: cgmb_putu24 ( cgm, ci ); break; + case 3: cgmb_putu32 ( cgm, ci ); break; + } +} + +static void cgmb_cd ( CGM *cgm, double cd ) +{ + unsigned long cv = (unsigned long) (cd * (pow(2.0, (cgm->cd_prec + 1) * 8.0) - 1)); + switch ( cgm->cd_prec ) + { + case 0: cgmb_putu8 ( cgm, (unsigned)cv ); break; + case 1: cgmb_putu16 ( cgm, (unsigned)cv ); break; + case 2: cgmb_putu24 ( cgm, cv ); break; + case 3: cgmb_putu32 ( cgm, cv ); break; + } +} + +static void cgmb_rgb ( CGM *cgm, double r, double g, double b ) +{ + cgmb_cd ( cgm, r ); + cgmb_cd ( cgm, g ); + cgmb_cd ( cgm, b ); +} + +static void cgmb_ix ( CGM *cgm, long ix ) +{ + switch ( cgm->ix_prec ) + { + case 0: cgmb_puti8 ( cgm, (int)ix ); break; + case 1: cgmb_puti16 ( cgm, (int)ix ); break; + case 2: cgmb_puti24 ( cgm, ix ); break; + case 3: cgmb_puti32 ( cgm, ix ); break; + } +} + +static void cgmb_e ( CGM *cgm, int e, const char *el[] ) +{ + cgmb_puti16 ( cgm, e ); +} + +static void cgmb_i ( CGM *cgm, long i ) +{ + switch ( cgm->int_prec ) + { + case 0: cgmb_puti8 ( cgm, (int)i ); break; + case 1: cgmb_puti16 ( cgm, (int)i ); break; + case 2: cgmb_puti24 ( cgm, i ); break; + case 3: cgmb_puti32 ( cgm, i ); break; + } +} + +static void cgmb_u ( CGM *cgm, unsigned long i ) +{ + switch ( cgm->int_prec ) + { + case 0: cgmb_putu8 ( cgm, (unsigned)i ); break; + case 1: cgmb_putu16 ( cgm, (unsigned)i ); break; + case 2: cgmb_putu24 ( cgm, i ); break; + case 3: cgmb_putu32 ( cgm, i ); break; + } +} + +static void cgmb_r ( CGM *cgm, double func ) +{ + switch ( cgm->real_prec ) + { + case 0: cgmb_putfl32 ( cgm, (float )func ); break; + case 1: cgmb_putfl64 ( cgm, (double)func ); break; + case 2: cgmb_putfx32 ( cgm, (float )func ); break; + case 3: cgmb_putfx64 ( cgm, (double)func ); break; + } +} + +static void cgmb_s ( CGM *cgm, const char *s ) +{ + register unsigned i; + unsigned l = strlen(s); + int bc = 0; + + if ( l > 254 ) + { + cgmb_putu8(cgm,255); + if ( l > 32763 ) + cgmb_putu16 ( cgm, (1<<16) | 32763 ); + else + cgmb_putu16 ( cgm, l ); + bc = 1; + } + else + cgmb_putu8(cgm,l); + + for ( i=0; s[i]; s++ ) + { + if ( (i + bc) == 32766 ) + { + l -= i; + s += i; + i = 0; + bc = 0; + if ( l > 32764 ) + cgmb_putu16 ( cgm, (1<<16) | 32764 ); + else + cgmb_putu16 ( cgm, l ); + } + cgmb_putc ( cgm, s[i] ); + } +} + +static void cgmb_vdc ( CGM *cgm, double vdc) +{ + if ( cgm->vdc_type == 0 ) + switch ( cgm->vdc_int ) + { + case 0: cgmb_puti8 ( cgm, (int )vdc ); break; + case 1: + /* Evita overflow em ambientes de 32 bits */ + if (vdc < -32768) vdc = -32768; + else if (vdc > 32767) vdc = +32767; + cgmb_puti16 ( cgm, (int) vdc ); + break; + case 2: cgmb_puti24 ( cgm, (long)vdc ); break; + case 3: + /* Evita overflow em ambientes de 32 bits */ + if (vdc < (double)-2147483648.0) vdc = (double)-2147483648.0; + else if (vdc > (double)2147483647.0) vdc = (double)2147483647.0; + cgmb_puti32 ( cgm, (long)vdc ); + break; + + } + else + switch ( cgm->vdc_real ) + { + case 0: cgmb_putfl32 ( cgm, (float )vdc ); break; + case 1: cgmb_putfl64 ( cgm, (double)vdc ); break; + case 2: cgmb_putfx32 ( cgm, (float )vdc ); break; + case 3: cgmb_putfx64 ( cgm, (double)vdc ); break; + } + +} + +static void cgmb_p ( CGM *cgm, double x, double y) +{ + cgmb_vdc ( cgm, x ); + cgmb_vdc ( cgm, y ); +} + +static void cgmb_co ( CGM *cgm, const void * co) +{ + if ( cgm->clrsm == 0 ) /* indexed */ + { + unsigned long ci = *(unsigned long *)co; + cgmb_ci ( cgm, ci ); + } + else + { + double *cb = (double *) co; + cgmb_rgb ( cgm, cb[0], cb[1], cb[2] ); + } +} + +static void cgmb_sep ( CGM *cgm, const char * sep ) +{} + +static int cgmb_get_col ( CGM *cgm ) +{ + return 0; +} + +static void cgmb_align ( CGM *cgm, int n ) +{} + +static void cgmb_nl ( CGM *cgm ) +{} + +static int cgmb_term ( CGM *cgm ) +{ + if ( cgm->op != -1 ) + { + if ( cgm->bc[cgm->op] & 1 ) + { + cgmb_putb( cgm, 0 ); + cgm->bc[cgm->op] --; + } + + if ( cgm->po[cgm->op] != 0L ) + { + long po = ftell(unit); + int op = cgm->op; + + cgm->op = -1; + fseek ( unit, cgm->po[op], SEEK_SET); + cgmb_putw ( cgm, cgm->bc[op] ); + + fseek ( unit, po, SEEK_SET ); + cgm->op = op; + } + cgm->op --; + } + + return 0; +} + +/************************************************ +* * +* Funcoes para clear text * +* * +************************************************/ + +static void cgmt_wch ( CGM* cgm, int c, int id, int len ) +{ + cgm->cl += fprintf ( unit, "%s", comandos[c+1][id]->ct ); +} + +static void cgmt_ci ( CGM *cgm, unsigned long ci ) +{ + cgm->func->u ( cgm, ci ); +} + +static void cgmt_cd ( CGM *cgm, double cd ) +{ + unsigned long cv = (unsigned long) (cd * (pow(2.0, (cgm->cd_prec + 1) * 8.0) - 1)); + + cgm->func->u ( cgm, cv ); +} + +static void cgmt_rgb ( CGM *cgm, double r, double g, double b ) +{ + cgm->func->cd ( cgm, r ); + cgm->func->cd ( cgm, g ); + cgm->func->cd ( cgm, b ); +} + +static void cgmt_ix ( CGM *cgm, long ix ) +{ + cgm->func->i ( cgm, ix ); +} + +static void cgmt_e ( CGM *cgm, int e, const char *el[] ) +{ + cgm->cl += fprintf ( unit, " %s", el[e] ); +} + +static void cgmt_i ( CGM *cgm, long i ) +{ + cgm->cl += fprintf ( unit, " %ld", i ); +} + +static void cgmt_u ( CGM *cgm, unsigned long i ) +{ + cgm->cl += fprintf ( unit, " %lu", i ); +} + +static void cgmt_r ( CGM *cgm, double func ) +{ + cgm->cl += fprintf ( unit, " %g", func ); +} + +static void cgmt_s ( CGM *cgm, const char *s ) +{ + register unsigned i; + fputc ( 34, unit ); + + for ( i=0; s[i]; i++ ) + { + if ( s[i] == 34 ) + { + fputc ( 34, unit ); + cgm->cl ++; + } + fputc ( s[i], unit ); + } + + fputc ( 34, unit ); + cgm->cl += strlen (s) + 2; +} + +static void cgmt_vdc ( CGM *cgm, double vdc) +{ + if ( cgm->vdc_type == 0 ) + { + /* Evita overflow em ambientes de 32 bits */ + if (vdc < (double)-2147483648.0) vdc = (double)-2147483648.0; + else if (vdc > (double)2147483647.0) vdc = (double)2147483647.0; + + cgm->func->i ( cgm, (long) vdc ); + } + else + cgm->func->r ( cgm, vdc ); +} + +static void cgmt_p ( CGM *cgm, double x, double y) +{ + cgm->func->sep ( cgm, "(" ); + cgm->func->vdc ( cgm, x ); + cgm->func->sep ( cgm, "," ); + cgm->func->vdc ( cgm, y ); + cgm->func->sep ( cgm, ")" ); +} + +static void cgmt_co ( CGM *cgm, const void * co) +{ + if ( cgm->clrsm == 0 ) /* indexed */ + { + unsigned long ci = *(unsigned *)co; + cgm->func->ci ( cgm, ci ); + } + else + { + double *cb = (double *) co; + cgm->func->rgb ( cgm, cb[0], cb[1], cb[2] ); + } +} + +static void cgmt_sep ( CGM *cgm, const char * sep ) +{ + cgm->cl += fprintf ( unit, " %s", sep ); +} + +static int cgmt_get_col ( CGM *cgm ) +{ + return cgm->cl; +} + +static void cgmt_align ( CGM *cgm, int n ) +{ + for ( ; cgm->cl < n ; cgm->cl ++ ) + fputc ( ' ', unit ); +} + +static void cgmt_nl ( CGM *cgm ) +{ + fputc ( '\n', unit ); + cgm->cl = 1; +} + +static int cgmt_term ( CGM *cgm ) +{ + fputc ( ';', unit ); + cgm->func->nl(cgm); + return 0; +} + +/************************************************ +* * +* Funcoes para character * +* * +************************************************/ + +static void cgmc_wch ( CGM* cgm, int c, int id, int len ) +{ + cgm->cl += fprintf ( unit, "%s", comandos[c+1][id]->ct ); +} + +static void cgmc_ci ( CGM *cgm, unsigned long ci ) +{ + cgm->func->u ( cgm, ci ); +} + +static void cgmc_cd ( CGM *cgm, double cd ) +{ + cgm->func->r ( cgm, cd ); +} + +static void cgmc_rgb ( CGM *cgm, double r, double g, double b ) +{ + cgm->func->cd ( cgm, r ); + cgm->func->sep ( cgm, "," ); + cgm->func->cd ( cgm, g ); + cgm->func->sep ( cgm, "," ); + cgm->func->cd ( cgm, b ); +} + +static void cgmc_ix ( CGM *cgm, long ix ) +{ + cgm->func->i ( cgm, ix ); +} + +static void cgmc_e ( CGM *cgm, int e, const char *el[] ) +{ + cgm->cl += fprintf ( unit, " %s", el[e] ); +} + +static void cgmc_i ( CGM *cgm, long i ) +{ + cgm->cl += fprintf ( unit, " %ld", i ); +} + +static void cgmc_u ( CGM *cgm, unsigned long i ) +{ + cgm->cl += fprintf ( unit, " %lu", i ); +} + +static void cgmc_r ( CGM *cgm, double func ) +{ + cgm->cl += fprintf ( unit, " %g", func ); +} + +static void cgmc_s ( CGM *cgm, const char *s ) +{ + register unsigned i; + fputc ( 34, unit ); + + for ( i=0; s[i]; i++ ) + { + if ( s[i] == 34 ) + { + fputc ( 34, unit ); + cgm->cl ++; + } + fputc ( s[i], unit ); + } + + fputc ( 34, unit ); + cgm->cl += strlen (s) + 2; +} + +static void cgmc_vdc ( CGM *cgm, double vdc) +{ + if ( cgm->vdc_type == 0 ) + cgm->func->i ( cgm, (long) vdc ); + else + cgm->func->r ( cgm, vdc ); +} + +static void cgmc_p ( CGM *cgm, double x, double y) +{ + cgm->func->sep ( cgm, "(" ); + cgm->func->vdc ( cgm, x ); + cgm->func->sep ( cgm, "," ); + cgm->func->vdc ( cgm, y ); + cgm->func->sep ( cgm, ")" ); +} + +static void cgmc_co ( CGM *cgm, const void * co) +{ + if ( cgm->clrsm == 0 ) /* indexed */ + { + unsigned long ci = *(unsigned long *)co; + cgm->func->ci ( cgm, ci ); + } + else + { + double *cb = (double *) co; + cgm->func->rgb ( cgm, cb[0], cb[1], cb[2] ); + } +} + +static void cgmc_sep ( CGM *cgm, const char * sep ) +{ + cgm->cl += fprintf ( unit, " %s", sep ); +} + +static int cgmc_get_col ( CGM *cgm ) +{ + return cgm->cl; +} + +static void cgmc_align ( CGM *cgm, int n ) +{ + for ( ; cgm->cl < n ; cgm->cl ++ ) + fputc ( ' ', unit ); +} + +static void cgmc_nl ( CGM *cgm ) +{ + fputc ( '\n', unit ); + cgm->cl = 1; +} + +static int cgmc_term ( CGM *cgm ) +{ + fputc ( ';', unit ); + cgm->func->nl(cgm); + return 0; +} + +/************************************************ +* * +* independente de codificacao * +* * +************************************************/ + + +/* Definicoes de precisao */ + +static const long _cgm_int_precs[][2] = { + { -128, 127 }, /* 8 */ + { -32768L, 32767 }, /* 16 */ + { LONG_MIN >> 8, LONG_MAX >> 8 }, /* 24 */ + { LONG_MIN , LONG_MAX } }; /* 32 */ + +static int _cgm_ireal_precs[][4] = { + { 0, 9, 23, 0 }, /* float*32 */ + { 0, 12, 52, 0 }, /* float*64 */ + { 1, 16, 16, 5 }, /* fixed*32 */ + { 1, 32, 32, 9 } }; /* fixed*64 */ + +static double _cgm_rreal_precs[][2] = { + /* float*32 */ { 0, 0 }, /* Em Turbo C, FLT_MAX e DLB_MAX sao */ + /* float*64 */ { 0, 0 }, /* DEFINES para variaveis externas */ + /* fixed*32 */ { - (32769.0 - 1.0 / 65536.0), + 32768.0 - 1.0 / 65536.0 }, + /* fixed*64 */ { (double)(LONG_MIN) - ( 1 - 1 / ( 65536.0 * 65536.0 ) ), + (double)(LONG_MAX) + ( 1 - 1 / ( 65536.0 * 65536.0 ) ) } }; + +/* Enumeraveis genericos */ + +static const char *offon[] = { "OFF", "ON" }; + +/********************* +* Delimiter elements * +*********************/ + +CGM *cgm_begin_metafile ( char *file, int mode, char *header ) +{ + CGM *cgm; + + if ( (cgm = (CGM *)malloc ( sizeof (CGM) ) ) == NULL ) + return NULL; + +#ifdef __VAXC__ + + if ( mode == 2 ) + cgm->file = fopen ( file , "w" , "rfm=var", "rat=cr" ); + else + cgm->file = fopen ( file , "w+b", "rfm=var", "ctx=stm" ); + +#else + + if ( mode == 2 ) + cgm->file = fopen ( file , "w" ); + else + cgm->file = fopen ( file , "w+b" ); + +#endif + + if ( cgm->file == NULL ) + { + free ( cgm ); + return NULL; + } + + cgm->mode = mode; + cgm->func = cgmf[mode]; + + cgm->vdc_type = 0; + cgm->int_prec = 1; + cgm->real_prec = 2; + cgm->ix_prec = 1; + cgm->cd_prec = 0; + cgm->cix_prec = 0; + cgm->max_cix = 63; + + cgm->clrsm = 0; + cgm->lnwsm = 1; + cgm->mkssm = 1; + cgm->edwsm = 1; + cgm->vdc_int = 1; + cgm->vdc_real = 2; + + cgm->vdc_size = 2; + cgm->int_size = 2; + cgm->real_size = 4; + cgm->ix_size = 3; + cgm->cd_size = 3; + cgm->cix_size = 1; + cgm->clr_size = 1; + cgm->lnw_size = 4; + cgm->mks_size = 4; + cgm->edw_size = 4; + + cgm->cl = 1; + + cgm->op = -1; + + cgm->func->wch ( cgm, 0, 1, strlen ( header ) + 1 ); + + cgm->func->s ( cgm, header ); + + cgm->func->term ( cgm ); + + _cgm_ireal_precs[0][3] = FLT_DIG; + _cgm_ireal_precs[1][3] = DBL_DIG; + + _cgm_rreal_precs[0][0] = - FLT_MAX; + _cgm_rreal_precs[0][1] = FLT_MAX; + _cgm_rreal_precs[1][0] = - DBL_MAX; + _cgm_rreal_precs[1][1] = DBL_MAX; + + return cgm; +} + +int cgm_end_metafile ( CGM *cgm ) +{ + cgm->func->wch ( cgm, 0, 2, 0 ); + cgm->func->term ( cgm ); + + fclose ( cgm->file ); + cgm->file = NULL; + free ( cgm ); + + return 0; +} + +int cgm_begin_picture (CGM *cgm, const char *s ) +{ + cgm->func->wch ( cgm, 0, 3, strlen(s)+1 ); + cgm->func->s ( cgm, s ); + return cgm->func->term(cgm); +} + +int cgm_begin_picture_body ( CGM *cgm ) +{ + cgm->func->wch ( cgm, 0, 4, 0 ); + return cgm->func->term(cgm); +} + +int cgm_end_picture ( CGM *cgm ) +{ + cgm->func->wch ( cgm, 0, 5, 0 ); + return cgm->func->term(cgm); +} + +/******************************* +* Metafile Descriptor Elements * +*******************************/ + +int cgm_metafile_version ( CGM *cgm, long version ) +{ + cgm->func->wch ( cgm, 1, 1, cgm->int_size ); + + cgm->func->i ( cgm, version ); + + return cgm->func->term(cgm); +} + +int cgm_metafile_description ( CGM *cgm, const char *s ) +{ + cgm->func->wch ( cgm, 1, 2, 1+strlen(s) ); + cgm->func->s ( cgm, s ); + return cgm->func->term(cgm); +} + +int cgm_vdc_type ( CGM *cgm, int mode ) +{ + static const char *vdct[] = { "integer", "real" }; + cgm->func->wch ( cgm, 1, 3, 2 ); + cgm->func->e ( cgm, mode, vdct ); + + cgm->vdc_type = mode; + if ( cgm->vdc_type == 0 ) /* integer */ + cgm->vdc_size = cgm->vdc_int + 1; + else + cgm->vdc_size = ( _cgm_ireal_precs[cgm->vdc_real][1] + + _cgm_ireal_precs[cgm->vdc_real][2]) / 8; + + return cgm->func->term(cgm); +} + +int cgm_integer_precision ( CGM *cgm, int prec ) +{ + cgm->func->wch ( cgm, 1, 4, cgm->int_size ); + + switch ( cgm->mode ) + { + case 0: /* character */ + break; + + case 1: /* binary */ + cgm->func->i ( cgm, (long)(prec) ); + break; + + case 2: /* clear text */ + cgm->func->i ( cgm, _cgm_int_precs[prec/8 - 1][0] ); + cgm->func->sep ( cgm, "," ); + cgm->func->i ( cgm, _cgm_int_precs[prec/8 - 1][1] ); + break; + } + + cgm->int_prec = prec/8-1; + cgm->int_size = prec/8; + + return cgm->func->term(cgm); +} + +int cgm_real_precision ( CGM *cgm, int mode ) +{ + cgm->func->wch ( cgm, 1, 5, 2 + 2*cgm->int_size ); + switch ( cgm->mode ) + { + case 0: /* character */ + break; + + case 1: /* binary */ + cgm->func->e ( cgm, _cgm_ireal_precs[mode][0] , NULL ); + cgm->func->i ( cgm, (long)(_cgm_ireal_precs[mode][1]) ); + cgm->func->i ( cgm, (long)(_cgm_ireal_precs[mode][2]) ); + break; + + case 2: /* clear text */ + cgm->func->r ( cgm, _cgm_rreal_precs[mode][0] ); + cgm->func->sep ( cgm, "," ); + cgm->func->r ( cgm, _cgm_rreal_precs[mode][1] ); + cgm->func->sep ( cgm, "," ); + cgm->func->i ( cgm, (long)(_cgm_ireal_precs[mode][3]) ); + break; + } + + cgm->real_prec = mode; + cgm->real_size = ( _cgm_ireal_precs[mode][1] + _cgm_ireal_precs[mode][2]) / 8; + + /* absolute scaling modes */ + if ( cgm->lnwsm == 1 ) cgm->lnw_size = cgm->real_size; + if ( cgm->mkssm == 1 ) cgm->mks_size = cgm->real_size; + if ( cgm->edwsm == 1 ) cgm->edw_size = cgm->real_size; + + return cgm->func->term(cgm); +} + +int cgm_index_precision ( CGM *cgm, int prec ) +{ + cgm->func->wch ( cgm, 1, 6, cgm->int_size ); + switch ( cgm->mode ) + { + case 0: /* character */ + break; + + case 1: /* binary */ + cgm->func->i ( cgm, (long)(prec) ); + break; + + case 2: /* clear text */ + cgm->func->i ( cgm, _cgm_int_precs[prec/8 - 1][0] ); + cgm->func->sep ( cgm, "," ); + cgm->func->i ( cgm, _cgm_int_precs[prec/8 - 1][1] ); + break; + } + + cgm->ix_prec = prec/8-1; + cgm->ix_size = prec/8; + return cgm->func->term(cgm); +} + +int cgm_colour_precision ( CGM *cgm, int prec ) +{ + cgm->func->wch ( cgm, 1, 7, cgm->int_size ); + switch ( cgm->mode ) + { + case 0: /* character */ + break; + + case 1: /* binary */ + cgm->func->i ( cgm, (long)(prec) ); + break; + + case 2: /* clear text */ + cgm->func->i ( cgm, 1ul+ 2ul * (unsigned long)_cgm_int_precs[prec/8 - 1][1] ); + break; + } + + cgm->cd_prec = prec/8-1; + cgm->cd_size = 3*(prec/8); + + if ( cgm->clrsm == 1 ) /* direct */ + cgm->clr_size = cgm->cd_size; + + return cgm->func->term(cgm); +} + +int cgm_colour_index_precision ( CGM *cgm, int prec ) +{ + cgm->func->wch ( cgm, 1, 8, cgm->int_size ); + + switch ( cgm->mode ) + { + case 0: /* character */ + break; + + case 1: /* binary */ + cgm->func->i ( cgm, (long)(prec) ); + break; + + case 2: /* clear text */ + cgm->func->i ( cgm, 1ul+ 2ul * (unsigned long)_cgm_int_precs[prec/8 - 1][1] ); + break; + } + + cgm->cix_prec = prec/8-1; + cgm->cix_size = prec/8; + + if ( cgm->clrsm == 0 ) /* indexed */ + cgm->clr_size = cgm->cix_size; + + return cgm->func->term(cgm); +} + +int cgm_maximum_colour_index ( CGM *cgm, unsigned long ci ) +{ + cgm->func->wch ( cgm, 1, 9, cgm->cix_size ); + cgm->func->ci ( cgm, ci ); + return cgm->func->term(cgm); +} + +int cgm_colour_value_extent ( CGM *cgm, const double *black, + const double *white) +{ + cgm->func->wch ( cgm, 1, 10, 2 * cgm->cd_size ); + cgm->func->rgb ( cgm, black[0], black[1], black[2] ); + cgm->func->nl ( cgm ); + cgm->func->align ( cgm, 15 ); + cgm->func->rgb ( cgm, white[0], white[1], white[2] ); + return cgm->func->term(cgm); +} + +int cgm_metafile_element_list ( CGM *cgm, int n, const int *group, const int *element ) +{ + register int i; + cgm->func->wch ( cgm, 1, 11, 31 ); + cgm->func->sep ( cgm, "\x22" ); /* aspas */ + if ( cgm->mode == 1 ) cgm->func->i ( cgm, n ); + for ( i=0; i<n; i++ ) + { + if ( cgm->mode == 1 ) /* binario */ + { + cgm->func->ix ( cgm, group[i] ); + cgm->func->ix ( cgm, element[i] ); + cgm->func->term( cgm ); + } + else + { + cgm->func->wch ( cgm, group[i], element[i], 0 ); + cgm->func->sep ( cgm, "" ); + } + } + cgm->func->sep ( cgm, "\x22" ); /* aspas */ + return cgm->func->term(cgm); +} + +int cgm_begin_metafile_defaults ( CGM *cgm ) +{ + cgm->func->wch ( cgm, 1, 12, 31 ); + + /* modo binario - deixa aberto */ + if ( cgm->mode == 1 ) /* binario */ + return 0; + + return cgm->func->term(cgm); +} + +int cgm_end_metafile_defaults ( CGM *cgm ) +{ + /* modo binario - ja estava aberto */ + if ( cgm->mode != 1 ) /* binario */ + cgm->func->wch ( cgm, 1, 0, 0 ); + + return cgm->func->term(cgm); +} + +int cgm_font_list ( CGM *cgm, const char *fl[] ) +{ + register int i; + + cgm->func->wch ( cgm, 1, 13, 31 ); + + for ( i=0; fl[i] != NULL; i++ ) + { + cgm->func->nl ( cgm ); + cgm->func->align ( cgm, 10 ); + cgm->func->s ( cgm, fl[i] ); + } + + return cgm->func->term(cgm); +} + +/****************************** +* Picture Descriptor Elements * +******************************/ + +int cgm_scaling_mode ( CGM *cgm, int mode, float metric ) +{ + static const char *sm[] = { "abstract", "metric" }; + cgm->func->wch ( cgm, 2, 1, 2 + 4 ); + cgm->func->e ( cgm, mode, sm ); + if ( cgm->mode == 1 ) + cgmb_putfl32 ( cgm, metric ); + else + cgm->func->r ( cgm, metric ); + return cgm->func->term(cgm); +} + +int cgm_colour_selection_mode ( CGM *cgm, int mode) +{ + static const char *csm[] = { "indexed", "direct" }; + cgm->func->wch ( cgm, 2, 2, 2 ); + cgm->func->e ( cgm, mode, csm ); + + cgm->clrsm = mode; + if ( mode == 0 ) /* indexed */ + cgm->clr_size = cgm->cix_size; + else + cgm->clr_size = cgm->cd_size; + + return cgm->func->term(cgm); +} + +static int _cgm_width_specify_mode ( CGM *cgm, int t, int mode) +{ + static const char *sm[] = { "abstract", "scaled" }; + cgm->func->wch ( cgm, 2, t, 2 ); + cgm->func->e ( cgm, mode, sm ); + return cgm->func->term(cgm); +} + +int cgm_line_width_specify_mode ( CGM *cgm, int mode) +{ + cgm->lnwsm = mode; + if ( mode == 0 ) + cgm->lnw_size = cgm->vdc_size; + else + cgm->lnw_size = cgm->real_size; + return _cgm_width_specify_mode ( cgm, 3, mode ); +} + +int cgm_marker_size_specify_mode ( CGM *cgm, int mode) +{ + cgm->mkssm = mode; + if ( mode == 0 ) + cgm->mks_size = cgm->vdc_size; + else + cgm->mks_size = cgm->real_size; + return _cgm_width_specify_mode ( cgm, 4, mode ); +} + +int cgm_edge_width_specify_mode ( CGM *cgm, int mode) +{ + cgm->edwsm = mode; + if ( mode == 0 ) + cgm->edw_size = cgm->vdc_size; + else + cgm->edw_size = cgm->real_size; + return _cgm_width_specify_mode ( cgm, 5, mode ); +} + +int cgm_vdc_extent ( CGM *cgm, double xmin, double ymin, + double xmax, double ymax ) +{ + cgm->func->wch ( cgm, 2, 6, 2*2*cgm->vdc_size ); + cgm->func->vdc ( cgm, xmin ); + cgm->func->vdc ( cgm, ymin ); + cgm->func->vdc ( cgm, xmax ); + cgm->func->vdc ( cgm, ymax ); + return cgm->func->term(cgm); +} + +int cgm_backgound_colour ( CGM *cgm, const double *cr ) +{ + cgm->func->wch ( cgm, 2, 7, cgm->cd_size ); + cgm->func->rgb ( cgm , cr[0], cr[1], cr[2] ); + return cgm->func->term(cgm); +} + +/******************* +* Control Elements * +*******************/ + +int cgm_vdc_integer_precision ( CGM *cgm, int prec ) +{ + cgm->func->wch ( cgm, 3, 1, cgm->int_size ); + switch ( cgm->mode ) + { + case 0: /* character */ + break; + + case 1: /* binary */ + cgm->func->i ( cgm, (long)(prec) ); + break; + + case 2: /* clear text */ + cgm->func->i ( cgm, _cgm_int_precs[prec/8 - 1][0] ); + cgm->func->sep ( cgm, "," ); + cgm->func->i ( cgm, _cgm_int_precs[prec/8 - 1][1] ); + break; + } + + if ( cgm->vdc_type == 0 ) + cgm->vdc_size = prec/8; + + cgm->vdc_int = prec/8 - 1; + + if ( cgm->lnwsm == 0 && cgm->vdc_type == 0 ) cgm->lnw_size = cgm->vdc_size; + if ( cgm->mkssm == 0 && cgm->vdc_type == 0 ) cgm->mks_size = cgm->vdc_size; + if ( cgm->edwsm == 0 && cgm->vdc_type == 0 ) cgm->edw_size = cgm->vdc_size; + + return cgm->func->term(cgm); +} + +int cgm_vdc_real_precision ( CGM *cgm, int mode ) +{ + cgm->func->wch ( cgm, 3, 2, 2 + 2*cgm->int_size ); + switch ( cgm->mode ) + { + case 0: /* character */ + break; + + case 1: /* binary */ + cgm->func->e ( cgm, _cgm_ireal_precs[mode][0] , NULL ); + cgm->func->i ( cgm, (long)(_cgm_ireal_precs[mode][1]) ); + cgm->func->i ( cgm, (long)(_cgm_ireal_precs[mode][2]) ); + break; + + case 2: /* clear text */ + cgm->func->r ( cgm, _cgm_rreal_precs[mode][0] ); + cgm->func->sep ( cgm, "," ); + cgm->func->r ( cgm, _cgm_rreal_precs[mode][1] ); + cgm->func->sep ( cgm, "," ); + cgm->func->i ( cgm, (long)(_cgm_ireal_precs[mode][3]) ); + break; + } + + if ( cgm->vdc_type == 1 ) + cgm->vdc_size = ( _cgm_ireal_precs[mode][1] + _cgm_ireal_precs[mode][2]) / 8; + + cgm->vdc_real = mode; + + if ( cgm->lnwsm == 0 && cgm->vdc_type == 1 ) cgm->lnw_size = cgm->vdc_size; + if ( cgm->mkssm == 0 && cgm->vdc_type == 1 ) cgm->mks_size = cgm->vdc_size; + if ( cgm->edwsm == 0 && cgm->vdc_type == 1 ) cgm->edw_size = cgm->vdc_size; + + return cgm->func->term(cgm); +} + +int cgm_auxiliary_colour ( CGM *cgm, const void *c ) +{ + cgm->func->wch ( cgm, 3, 3, cgm->clr_size ); + + cgm->func->co ( cgm, c ) ; + + return cgm->func->term(cgm); +} + +int cgm_transparency ( CGM *cgm, int mode ) +{ + cgm->func->wch ( cgm, 3, 4, 2 ); + + cgm->func->e ( cgm, mode, offon ); + + return cgm->func->term(cgm); +} + +int cgm_clip_rectangle ( CGM *cgm, double xmin, double ymin, + double xmax, double ymax ) +{ + cgm->func->wch ( cgm, 3, 5, 4 * cgm->vdc_size ); + + cgm->func->vdc ( cgm, xmin ); + cgm->func->vdc ( cgm, ymin ); + cgm->func->vdc ( cgm, xmax ); + cgm->func->vdc ( cgm, ymax ); + + return cgm->func->term(cgm); +} + +int cgm_clip_indicator ( CGM *cgm, int mode ) +{ + cgm->func->wch ( cgm, 3, 6, 2 ); + + cgm->func->e ( cgm, mode, offon ); + + return cgm->func->term(cgm); +} + +/******************************* +* Graphical Primitive Elements * +*******************************/ + +static int _cgm_point ( CGM *cgm, double x, double y ) +{ + cgm->func->p ( cgm, x, y ); + return 0; +} + +static int _cgm_point_list ( CGM *cgm, int element, int n, const double *p) +{ + register int i; + cgm->func->wch ( cgm, 4, element, 2*n*cgm->vdc_size ); + + for ( i=0; i < 2*n; i+=2 ) + { + cgm->func->nl ( cgm ); + cgm->func->align ( cgm, 8 ); + _cgm_point ( cgm, p[i], p[i+1] ); + } + return cgm->func->term(cgm); +} + +int cgm_polyline ( CGM *cgm, int n, const double *p ) +{ + return _cgm_point_list ( cgm, 1, n, p ); +} + +int cgm_polymarker ( CGM *cgm, int n, const double *p ) +{ + return _cgm_point_list ( cgm, 3, n, p ); +} + +static int _cgm_text_piece ( CGM *cgm, int t, const char *s) +{ + static const char *tt[] = { "NOT_FINAL", " FINAL" }; + cgm->func->e ( cgm, t, tt ); + cgm->func->s ( cgm, s ); + return cgm->func->term(cgm); +} + +int cgm_text ( CGM *cgm, int tt, double x, double y, const char *s ) +{ + cgm->func->wch ( cgm, 4, 4, 2 * cgm->vdc_size + strlen(s) + 3 ); + cgm->func->p ( cgm, x, y ); + cgm->func->nl ( cgm ); + cgm->func->align ( cgm, 10 ); + + if ( cgm->mode == 2 ) /* clear text */ + { + while ( strlen (s) > 50 ) + { + char s1[51]; + + strncpy ( s1, s, 50 ); + s1[50] = 0; + + _cgm_text_piece ( cgm, 0, s1 ); + + s += 50; + cgm->func->wch ( cgm, 4, 6, 2 * cgm->vdc_size + strlen(s) + 1 ); + } + + } + + return _cgm_text_piece ( cgm, tt, s ); +} + +int cgm_polygon ( CGM *cgm, int n, const double *p ) +{ + return _cgm_point_list ( cgm, 7, n, p ); +} + +static int _cgm_cell_rows ( CGM *cgm, long sx, long sy, int prec, const void *c ) +{ + register long i,j, brk; + + cgm->func->nl ( cgm ); + cgm->func->sep ( cgm, "(" ); + + if ( cgm->clrsm ) + brk = 5; + else + brk = 12; + + for ( i=0; i < sy; i++ ) + { + if ( i ) + { + cgm->func->nl ( cgm ); + cgm->func->align ( cgm, 3 ); + } + + for ( j=0; j < sx; j++) + { + if ( j && ( j % brk == 0 ) ) + { + cgm->func->nl ( cgm ); + cgm->func->align ( cgm, 3 ); + } + + cgm->func->co ( cgm, c ); + c = (void*)((char*)c+ (cgm->clrsm ? (3*sizeof(double)) : sizeof(int))); + + if ( i<sy-1 || j<sx-1 ) cgm->func->sep ( cgm, "," ); + } + } + + cgm->func->sep ( cgm, ")" ); + + return 0; +} + +int cgm_cell_array ( CGM *cgm, const double *p, long sx, long sy, int prec, const void *c ) +{ + register int i; + static const char *repmode[] = { "run lenght", "packed" }; + + cgm->func->wch ( cgm, 4, 9, 31 ); + + for ( i=0; i<3*2; i+=2 ) + _cgm_point ( cgm, p[i], p[i+1] ); + + cgm->func->nl (cgm ); + + cgm->func->i ( cgm, sx ); + cgm->func->i ( cgm, sy ); + + if ( prec == 0 ) + cgm->func->i ( cgm, (long)(prec) ); + else + { + switch ( cgm->mode ) + { + case 0: /* character */ + break; + + case 1: /* binary */ + cgm->func->i ( cgm, (long)(prec) ); + break; + + case 2: /* clear text */ + cgm->func->i ( cgm, 2 * ( _cgm_int_precs[prec/8 - 1][1] + 1) ); + break; + } + } + + if ( cgm->mode==1 ) cgm->func->e ( cgm, 1, repmode ); + + _cgm_cell_rows( cgm, sx, sy, prec, c ); + + return cgm->func->term(cgm); +} + +int cgm_rectangle ( CGM *cgm, const double *p ) +{ + return _cgm_point_list ( cgm, 11, 2, p ); +} + +static int _cgm_ellipse_CDP ( CGM *cgm, const double *c, const double *p1, + const double *p2 ) +{ + _cgm_point ( cgm, c[0], c[1] ); + _cgm_point ( cgm, p1[0], p1[1] ); + _cgm_point ( cgm, p2[0], p2[1] ); + + return 0; +} + +static int _cgm_ellipse_vectors ( CGM *cgm, double dxs, double dys, double dxe, + double dye ) +{ + cgm->func->vdc ( cgm, dxs ); + cgm->func->vdc ( cgm, dys ); + cgm->func->vdc ( cgm, dxe ); + cgm->func->vdc ( cgm, dye ); + + return 0; +} + +int cgm_elliptical_arc ( CGM *cgm, const double *c, const double *p1, + const double *p2, double dxs, double dys, double dxe, + double dye ) +{ + cgm->func->wch ( cgm, 4, 18, 10*cgm->vdc_size ); + + _cgm_ellipse_CDP ( cgm, c, p1, p2 ); + + _cgm_ellipse_vectors ( cgm, dxs, dys, dxe, dye ); + + return cgm->func->term(cgm); +} + +int cgm_elliptical_arc_close ( CGM *cgm, const double *c, const double *p1, + const double *p2, double dxs, double dys, + double dxe, double dye, int type ) +{ + static const char *ct[] = { "pie", "chord" }; + + cgm->func->wch ( cgm, 4, 19, 10*cgm->vdc_size + 2 ); + + _cgm_ellipse_CDP ( cgm, c, p1, p2 ); + + _cgm_ellipse_vectors ( cgm, dxs, dys, dxe, dye ); + + cgm->func->e ( cgm, type, ct ); + + return cgm->func->term(cgm); +} + +/********************* +* Attribute Elements * +*********************/ + +int cgm_line_bundle_index( CGM *cgm, long li) +{ + cgm->func->wch ( cgm, 5, 1, cgm->ix_size ); + cgm->func->ix ( cgm, li ); + return cgm->func->term(cgm); +} + +int cgm_line_type( CGM *cgm, long lt) +{ + cgm->func->wch ( cgm, 5, 2, cgm->ix_size ); + cgm->func->ix ( cgm, lt ); + return cgm->func->term(cgm); +} + +int cgm_line_width( CGM *cgm, double lw) +{ + cgm->func->wch ( cgm, 5, 3, cgm->lnw_size ); + + if ( cgm->lnwsm == 0 ) /* absolute */ + cgm->func->vdc ( cgm, lw ); + else + cgm->func->r ( cgm, lw ); + + return cgm->func->term(cgm); +} + +int cgm_line_colour( CGM *cgm, const void *lc) +{ + cgm->func->wch ( cgm, 5, 4, cgm->clr_size ); + cgm->func->co ( cgm, lc ); + return cgm->func->term(cgm); +} + +int cgm_marker_bundle_index( CGM *cgm, long mi) +{ + cgm->func->wch ( cgm, 5, 5, cgm->ix_size ); + cgm->func->ix ( cgm, mi ); + return cgm->func->term(cgm); +} + +int cgm_marker_type( CGM *cgm, long mt) +{ + cgm->func->wch ( cgm, 5, 6, cgm->ix_size ); + cgm->func->ix ( cgm, mt ); + return cgm->func->term(cgm); +} + +int cgm_marker_size( CGM *cgm, double ms) +{ + cgm->func->wch ( cgm, 5, 7, cgm->mks_size ); + + if ( cgm->mkssm == 0 ) /* absolute */ + cgm->func->vdc ( cgm, ms ); + else + cgm->func->r ( cgm, ms ); + + return cgm->func->term(cgm); +} + +int cgm_marker_colour( CGM *cgm, const void *mc) +{ + cgm->func->wch ( cgm, 5, 8, cgm->clr_size ); + cgm->func->co ( cgm, mc ); + return cgm->func->term(cgm); +} + +int cgm_text_bundle_index( CGM *cgm, long ti) +{ + cgm->func->wch ( cgm, 5, 9, cgm->ix_size ); + cgm->func->ix ( cgm, ti ); + return cgm->func->term(cgm); +} + +int cgm_text_font_index( CGM *cgm, long fi) +{ + cgm->func->wch ( cgm, 5, 10, cgm->ix_size ); + cgm->func->ix ( cgm, fi ); + return cgm->func->term(cgm); +} + +int cgm_text_precision( CGM *cgm, int tp) +{ + static const char *txprec[] = { "STRING", "CHAR", "STROKE" }; + cgm->func->wch ( cgm, 5, 11, 2 ); + cgm->func->e ( cgm, tp, txprec ); + return cgm->func->term(cgm); +} + +int cgm_char_expansion_factor ( CGM *cgm, double expan ) +{ + cgm->func->wch ( cgm, 5, 12, cgm->real_size ); + cgm->func->r ( cgm, expan ); + return cgm->func->term(cgm); +} + +int cgm_char_spacing ( CGM *cgm, double spacing ) +{ + cgm->func->wch ( cgm, 5, 13, cgm->real_size ); + cgm->func->r ( cgm, spacing ); + return cgm->func->term(cgm); +} + +int cgm_text_colour( CGM *cgm, const void *tc) +{ + cgm->func->wch ( cgm, 5, 14, cgm->clr_size ); + cgm->func->co ( cgm, tc ); + return cgm->func->term(cgm); +} + +int cgm_char_height ( CGM *cgm, double height ) +{ + cgm->func->wch ( cgm, 5, 15, cgm->vdc_size ); + cgm->func->vdc ( cgm, height ); + return cgm->func->term(cgm); +} + +int cgm_char_orientation ( CGM *cgm, double chupx, double chupy, + double chbsx, double chbsy ) +{ + cgm->func->wch ( cgm, 5, 16, 4*cgm->vdc_size ); + cgm->func->sep ( cgm, "% char up %" ); + cgm->func->vdc ( cgm, chupx ); + cgm->func->sep ( cgm, "," ); + cgm->func->vdc ( cgm, chupy ); + cgm->func->nl ( cgm ); + cgm->func->align ( cgm, 8 ); + cgm->func->sep ( cgm, "% char base %" ); + cgm->func->vdc ( cgm, chbsx ); + cgm->func->sep ( cgm, "," ); + cgm->func->vdc ( cgm, chbsy ); + return cgm->func->term(cgm); +} + +int cgm_text_path ( CGM *cgm, int tp) +{ + static const char *txpath[] = { "RIGHT", "LEFT", "UP", "DOWN" }; + cgm->func->wch ( cgm, 5, 17, 2 ); + cgm->func->e ( cgm, tp, txpath ); + return cgm->func->term(cgm); +} + +int cgm_text_alignment ( CGM *cgm, int hor, int ver , double ch, double cv) +{ + static const char *txhor[] = { "NORMHORIZ", "LEFT", "CTR", "RIGHT", "CONTHORIZ" }; + static const char *txver[] = { "NORMVERT", "TOP", "CAP", "HALF", "BASE", + "BOTTOM", "CONTHORIZ" }; + + cgm->func->wch ( cgm, 5, 18, 2*2 + 2*cgm->real_size ); + cgm->func->e ( cgm, hor, txhor ); + cgm->func->e ( cgm, ver, txver ); + cgm->func->r ( cgm, ch ); + cgm->func->r ( cgm, cv ); + return cgm->func->term(cgm); +} + +int cgm_fill_bundle_index( CGM *cgm, long fi) +{ + cgm->func->wch ( cgm, 5, 21, cgm->ix_size ); + cgm->func->ix ( cgm, fi ); + return cgm->func->term(cgm); +} + +int cgm_interior_style( CGM *cgm, int is) +{ + static const char *style[]= { "HOLLOW", "SOLID", "PAT", "HATCH", "EMPTY" }; + cgm->func->wch ( cgm, 5, 22, 2 ); + cgm->func->e ( cgm, is, style ); + return cgm->func->term(cgm); +} + +int cgm_fill_colour( CGM *cgm, const void *fc) +{ + cgm->func->wch ( cgm, 5, 23, cgm->clr_size ); + cgm->func->co ( cgm, fc ); + return cgm->func->term(cgm); +} + +int cgm_hatch_index( CGM *cgm, long hi) +{ + cgm->func->wch ( cgm, 5, 24, cgm->ix_size ); + cgm->func->ix ( cgm, hi ); + return cgm->func->term(cgm); +} + +int cgm_pattern_index( CGM *cgm, long pi) +{ + cgm->func->wch ( cgm, 5, 25, cgm->ix_size ); + cgm->func->ix ( cgm, pi ); + return cgm->func->term(cgm); +} + +int cgm_edge_width( CGM *cgm, double ew) +{ + cgm->func->wch ( cgm, 5, 28, cgm->edw_size ); + + if ( cgm->lnwsm == 0 ) /* absolute */ + cgm->func->vdc ( cgm, ew ); + else + cgm->func->r ( cgm, ew ); + + return cgm->func->term(cgm); +} + +int cgm_edge_colour( CGM *cgm, const void *ec) +{ + cgm->func->wch ( cgm, 5, 29, cgm->clr_size ); + cgm->func->co ( cgm, ec ); + return cgm->func->term(cgm); +} + +int cgm_edge_visibility ( CGM *cgm, int mode ) +{ + cgm->func->wch ( cgm, 5, 30, 2 ); + cgm->func->e ( cgm, mode, offon ); + return cgm->func->term(cgm); +} + +int cgm_fill_reference_point ( CGM *cgm, double rpx, double rpy ) +{ + cgm->func->wch ( cgm, 5, 31, 2*cgm->vdc_size ); + _cgm_point ( cgm, rpx, rpy ); + return cgm->func->term(cgm); +} + +int cgm_pattern_table ( CGM *cgm, long pi, long sx, long sy, int prec, const void *c) +{ + cgm->func->wch ( cgm, 5, 32, 31 ); + cgm->func->ix ( cgm, pi ); + + cgm->func->i ( cgm, sx ); + cgm->func->i ( cgm, sy ); + + if ( prec == 0 ) + cgm->func->i ( cgm, (long)(prec) ); + else + { + switch ( cgm->mode ) + { + case 0: /* character */ + break; + + case 1: /* binary */ + cgm->func->i ( cgm, (long)(prec) ); + break; + + case 2: /* clear text */ + cgm->func->i ( cgm, 2 * ( _cgm_int_precs[prec/8 - 1][1] + 1) ); + break; + } + } + + _cgm_cell_rows( cgm, sx, sy, prec, c ); + + return cgm->func->term(cgm); +} + +int cgm_pattern_size ( CGM *cgm, double hx, double hy, double wx, double wy ) +{ + cgm->func->wch ( cgm, 5, 33, 4*cgm->vdc_size ); + cgm->func->sep ( cgm, "% height %" ); + cgm->func->vdc ( cgm, hx ); + cgm->func->sep ( cgm, "," ); + cgm->func->vdc ( cgm, hy ); + cgm->func->nl ( cgm ); + cgm->func->align ( cgm, 8 ); + cgm->func->sep ( cgm, "% width %" ); + cgm->func->vdc ( cgm, wx ); + cgm->func->sep ( cgm, "," ); + cgm->func->vdc ( cgm, wy ); + return cgm->func->term(cgm); +} + +int cgm_colour_table ( CGM *cgm, long ci, long n, const double *cb ) +{ + register long i=n; + + if ( n > 31 ) n = 31; + + cgm->func->wch ( cgm, 5, 34, cgm->int_size+n*cgm->cd_size ); + cgm->func->i ( cgm, ci ); + + n = i; + + for ( i=0; i<n; i++ ) + { + if ( i ) + { + cgm->func->nl ( cgm ); + cgm->func->align ( cgm, 18 ); + } + cgm->func->rgb ( cgm, cb[(int)i], cb[(int)i+1], cb[(int)i+2] ); + } + + return cgm->func->term(cgm); +} + +static void _cgm_asf_pair ( CGM *cgm, int asft, int asfv ) +{ + static const char *asfvl[] = { "INDIV", "BUNDLED" }; + static const char *asftl[] = { + "LINE_TYPE", "LINE_WIDTH", "LINE_COLR", + "MARKER_TYPE", "MARKER_SIZE", "MARKER_COLR", + "TEXT_FONT_INDEX", "TEXT_PREC", "CHAR_EXP", "CHAR_SPACE", "TEXT_COLR", + "INT_STYLE", "FILL_COLR", "HATCH_INDEX", "PAT_INDEX", + "EDGE_TYPE", "EDGE_WIDTH", "EDGE_COLR", + "ALL", "ALL_LINE", "ALL_MARKER", "ALL_TEXT", "ALL_FILL", "ALL_EDGE" + }; + + cgm->func->nl ( cgm ); + cgm->func->align ( cgm, 4 ); + cgm->func->e ( cgm, asft, asftl ); + cgm->func->e ( cgm, asfv, asfvl ); +} + +int cgm_asfs ( CGM *cgm, int n, const int *asfts, const int* asfvs ) +{ + register int i; + cgm->func->wch ( cgm, 5, 35, 2*n* 2 ); + + for ( i=0; i<n; i++ ) + _cgm_asf_pair ( cgm, asfts[i], asfvs[i] ); + + return cgm->func->term(cgm); +} + +/***************** +* Escape Element * +*****************/ + +/******************** +* External elements * +********************/ + +int cgm_message ( CGM *cgm, int action, const char *s) +{ + static const char *ac[] = { "NOACTION", "ACTION" }; + cgm->func->wch ( cgm, 7, 2, 2 + strlen(s)+1 ); + cgm->func->e ( cgm, action, ac ); + cgm->func->s ( cgm, s ); + return cgm->func->term(cgm); +} diff --git a/src/drv/cgm.h b/src/drv/cgm.h new file mode 100644 index 0000000..0404604 --- /dev/null +++ b/src/drv/cgm.h @@ -0,0 +1,156 @@ +/** \file + * \brief CGM library + * Extracted from GKS/PUC + * + * See Copyright Notice in cd.h + */ + +#ifndef __CGM_H +#define __CGM_H + +typedef struct _cgmFunc CGMFUNC; + +typedef struct { + FILE *file; /* file pointer */ + + const CGMFUNC *func; /* functions */ + + int mode; /* character, binary, clear text */ + + int vdc_type, /* integer, real */ + int_prec, /* 8, 16, 24, 32 */ + real_prec, /* float*32, float*64, fixed*32, fixed*64 */ + ix_prec, /* 8, 16, 24, 32 */ + cd_prec, /* 8, 16, 24, 32 */ + cix_prec, /* 8, 16, 24, 32 */ + max_cix; /* maximum colour index */ + + int clrsm, /* indexed, direct */ + lnwsm, /* absolute, scaled */ + mkssm, /* absolute, scaled */ + edwsm; /* absolute, scaled */ + int vdc_int, /* X, 16, 24, 32 */ + vdc_real; /* float*32, float*64, fixed*32, fixed*64 */ + + int vdc_size, /* 2, 3, 4, 8 */ + int_size, /* 1, 2, 3, 4 */ + real_size, /* 4, 8 */ + ix_size, /* 1, 2, 3, 4 */ + cd_size, /* 1, 2, 3, 4 */ + cix_size, /* 1, 2, 3, 4 */ + clr_size, /* 3 * cd_size , cix_size */ + lnw_size, /* 2, 3, 4, 8 */ + mks_size, /* 2, 3, 4, 8 */ + edw_size; /* 2, 3, 4, 8 */ + + int cl; /* coluna para alinhamento */ + + int op; /* commands opened */ + int bc[5]; /* bytes count for command */ + long po[5]; /* position offset do arquivo */ +} CGM; + +CGM *cgm_begin_metafile ( char *, int, char * ); +int cgm_end_metafile ( CGM * ); +int cgm_begin_picture ( CGM *, const char * ); +int cgm_begin_picture_body ( CGM * ); +int cgm_end_picture ( CGM * ); +int cgm_metafile_version ( CGM *, long ); +int cgm_metafile_description ( CGM *, const char * ); +int cgm_vdc_type ( CGM *, int ); +int cgm_integer_precision ( CGM *, int ); +int cgm_real_precision ( CGM *, int ); +int cgm_index_precision ( CGM *, int ); +int cgm_colour_precision ( CGM *, int ); +int cgm_colour_index_precision ( CGM *, int ); +int cgm_maximum_colour_index ( CGM *, unsigned long ); +int cgm_colour_value_extent ( CGM *, const double *, const double * ); +int cgm_metafile_element_list ( CGM *, int, const int *, const int * ); +int cgm_begin_metafile_defaults ( CGM * ); +int cgm_end_metafile_defaults ( CGM * ); +int cgm_font_list ( CGM *, const char *l[] ); +int cgm_scaling_mode ( CGM *, int, float ); +int cgm_colour_selection_mode ( CGM *, int ); +int cgm_line_width_specify_mode ( CGM *, int ); +int cgm_marker_size_specify_mode( CGM *, int ); +int cgm_edge_width_specify_mode ( CGM *, int ); +int cgm_vdc_extent ( CGM *, double, double, double, double ); +int cgm_backgound_colour ( CGM *, const double * ); +int cgm_vdc_integer_precision ( CGM *, int ); +int cgm_vdc_real_precision ( CGM *, int ); +int cgm_auxiliary_colour ( CGM *, const void * ); +int cgm_transparency ( CGM *, int ); +int cgm_clip_rectangle ( CGM *, double, double, double, double ); +int cgm_clip_indicator ( CGM *, int ); +int cgm_polyline ( CGM *, int, const double * ); +int cgm_polymarker ( CGM *, int, const double * ); +int cgm_text ( CGM *, int, double, double, const char * ); +int cgm_polygon ( CGM *, int, const double * ); +int cgm_cell_array ( CGM *, const double *, long, long, int, const void * ); +int cgm_rectangle ( CGM *, const double * ); +int cgm_elliptical_arc ( CGM *, const double *, const double *, const double *, double, double, double, double ); +int cgm_elliptical_arc_close ( CGM *, const double *, const double *, const double *, double, double, double, double, int ); +int cgm_line_bundle_index ( CGM *, long ); +int cgm_line_type ( CGM *, long ); +int cgm_line_width ( CGM *, double ); +int cgm_line_colour ( CGM *, const void * ); +int cgm_marker_bundle_index ( CGM *, long ); +int cgm_marker_type ( CGM *, long ); +int cgm_marker_size ( CGM *, double ); +int cgm_marker_colour ( CGM *, const void * ); +int cgm_text_bundle_index ( CGM *, long ); +int cgm_text_font_index ( CGM *, long ); +int cgm_text_precision ( CGM *, int ); +int cgm_char_expansion_factor ( CGM *, double ); +int cgm_char_spacing ( CGM *, double ); +int cgm_text_colour ( CGM *, const void * ); +int cgm_char_height ( CGM *, double ); +int cgm_char_orientation ( CGM *, double, double, double, double ); +int cgm_text_path ( CGM *, int ); +int cgm_text_alignment ( CGM *, int, int, double, double ); +int cgm_fill_bundle_index ( CGM *, long ); +int cgm_interior_style ( CGM *, int ); +int cgm_fill_colour ( CGM *, const void * ); +int cgm_hatch_index ( CGM *, long ); +int cgm_pattern_index ( CGM *, long ); +int cgm_edge_width ( CGM *, double ); +int cgm_edge_colour ( CGM *, const void * ); +int cgm_edge_visibility ( CGM *, int ); +int cgm_fill_reference_point ( CGM *, double, double ); +int cgm_pattern_table ( CGM *, long, long, long, int, const void * ); +int cgm_pattern_size ( CGM *, double, double, double, double ); +int cgm_colour_table ( CGM *, long, long, const double * ); +int cgm_asfs ( CGM *, int, const int *, const int * ); +int cgm_message ( CGM *, int, const char * ); + +enum { + LINE_SOLID=1, + LINE_DASH=2, + LINE_DOT=3, + LINE_DASH_DOT=4, + LINE_DASH_DOT_DOT=5 + }; + +enum { + MARKER_DOT=1, + MARKER_PLUS=2, + MARKER_ASTERISK=3, + MARKER_CIRCLE=4, + MARKER_CROSS=5 + }; + +enum { + HOLLOW, + SOLID, + PAT, + HATCH, + EMPTY + }; + +enum { /* encoding */ + CD_CHARACTER, + CD_BIN, + CD_CLEAR_TEXT + }; + +#endif |