/* Copyright (C) 1995, 1996, 1998 artofcode LLC. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA, 02111-1307. */ /*$Id: gdevcgml.c,v 1.2.6.1.2.1 2003/01/17 00:49:00 giles Exp $ */ /* CGM-writing library */ #include "memory_.h" #include "stdio_.h" #include "gdevcgmx.h" /* Forward references to command-writing procedures */ private void begin_command(P2(cgm_state *, cgm_op_index)); #define OP(op) begin_command(st, op) private cgm_result end_command(P1(cgm_state *)); #define END_OP (void)end_command(st) #define DONE return end_command(st) /* Parameters */ private void put_int(P3(cgm_state *, cgm_int, int)); #define CI(ci) put_int(st, ci, st->metafile.color_index_precision) #define I(i) put_int(st, i, st->metafile.integer_precision) #define IX(ix) put_int(st, ix, st->metafile.index_precision) #define E(e) put_int(st, (int)(e), 16) private void put_real(P3(cgm_state *, cgm_real, const cgm_precision *)); #define R(r) put_real(st, r, &st->metafile.real_precision) private void put_vdc(P2(cgm_state *, const cgm_vdc *)); #define VDC(vdc) put_vdc(st, vdc) #define VDC2(vdc1, vdc2) VDC(vdc1); VDC(vdc2) #define VDC4(vdc1, vdc2, vdc3, vdc4) VDC2(vdc1, vdc2); VDC2(vdc3, vdc4) private void put_vdc_r(P3(cgm_state *, const cgm_line_marker_extent *, cgm_line_marker_specification_mode)); #define VDC_R(vdcr, mode) put_vdc_r(st, vdcr, mode) private void put_point(P2(cgm_state *, const cgm_point *)); #define P(p) put_point(st, p) private void put_points(P3(cgm_state *, const cgm_point *, int)); #define nP(p, n) put_points(st, p, n) private void put_string(P3(cgm_state *, const char *, uint)); #define S(s, l) put_string(st, s, l) private void put_color(P2(cgm_state *, const cgm_color *)); #define CO(co) put_color(st, co) private void put_rgb(P2(cgm_state *, const cgm_rgb *)); #define CD(cd) put_rgb(st, cd) /* Other data types */ #define put_byte(st, b)\ if ( st->command_count == command_max_count ) write_command(st, false);\ st->command[st->command_count++] = (byte)(b) private void put_bytes(P3(cgm_state *, const byte *, uint)); private void write_command(P2(cgm_state *, bool)); private void put_real_precision(P2(cgm_state *, const cgm_precision *)); /* ================ Public routines ================ */ /* ---------------- Initialize/terminate ---------------- */ /* Initialize a CGM writer. */ cgm_state * cgm_initialize(FILE * file, const cgm_allocator * cal) { cgm_state *st = (*cal->alloc) (cal->private_data, sizeof(cgm_state)); if (st == 0) return 0; st->file = file; st->allocator = *cal; /* Initialize metafile elements. */ st->metafile.vdc_type = cgm_vdc_integer; st->metafile.integer_precision = 16; st->metafile.real_precision.representation = cgm_representation_fixed; st->metafile.real_precision.exponent_or_whole_width = 16; st->metafile.real_precision.fraction_width = 16; st->metafile.index_precision = 16; st->metafile.color_precision = 8; st->metafile.color_index_precision = 8; st->metafile.maximum_color_index = 63; /* color_value_extent */ /*st->metafile.character_coding_announcer = 0; */ /* Initialize picture elements. */ st->picture.scaling_mode = cgm_scaling_abstract; st->picture.color_selection_mode = cgm_color_selection_indexed; st->picture.line_width_specification_mode = cgm_line_marker_absolute; st->picture.marker_size_specification_mode = cgm_line_marker_absolute; st->picture.edge_width_specification_mode = cgm_line_marker_absolute; /* vdc_extent */ /* background_color */ /* Initialize control elements. */ st->vdc_integer_precision = st->metafile.integer_precision; st->vdc_real_precision = st->metafile.real_precision; st->transparency = cgm_transparency_on; /* clip_rectangle */ st->clip_indicator = cgm_clip_on; /* Initialize other state elements. */ st->line_bundle_index = 1; st->line_type = cgm_line_solid; /* line_width */ /* line_color */ st->marker_bundle_index = 1; st->marker_type = cgm_marker_asterisk; /* marker_size */ /* marker_color */ st->text_bundle_index = 1; st->text_font_index = 1; st->text_precision = cgm_text_precision_string; st->character_expansion_factor = 1.0; st->character_spacing = 0.0; /* text_color */ /* character_height */ /* character_orientation */ st->text_path = cgm_text_path_right; /* text_alignment */ st->character_set_index = 1; st->alternate_character_set_index = 1; st->fill_bundle_index = 1; st->interior_style = cgm_interior_style_hollow; st->hatch_index = cgm_hatch_horizontal; st->pattern_index = 1; st->edge_bundle_index = 1; st->edge_type = cgm_edge_solid; /* edge_width */ st->edge_visibility = false; /* fill_reference_point */ /* pattern_table */ /* pattern_size */ /* color_table */ memset(st->source_flags, (byte) cgm_aspect_source_individual, sizeof(st->source_flags)); return st; } /* Terminate a CGM writer. */ cgm_result cgm_terminate(cgm_state * st) { (*st->allocator.free) (st->allocator.private_data, st); return cgm_result_ok; } /* ---------------- Metafile elements ---------------- */ cgm_result cgm_BEGIN_METAFILE(cgm_state * st, const char *str, uint len) { OP(BEGIN_METAFILE); S(str, len); DONE; } cgm_result cgm_set_metafile_elements(cgm_state * st, const cgm_metafile_elements * meta, long mask) { if ((mask & cgm_set_METAFILE_VERSION)) { OP(METAFILE_VERSION); I(meta->metafile_version); END_OP; st->metafile.metafile_version = meta->metafile_version; } if ((mask & cgm_set_METAFILE_DESCRIPTION)) { OP(METAFILE_DESCRIPTION); S(meta->metafile_description.chars, meta->metafile_description.length); END_OP; st->metafile.metafile_description = meta->metafile_description; } if ((mask & cgm_set_VDC_TYPE)) { OP(VDC_TYPE); E(meta->vdc_type); END_OP; st->metafile.vdc_type = meta->vdc_type; } if ((mask & cgm_set_INTEGER_PRECISION)) { OP(INTEGER_PRECISION); I(meta->integer_precision); END_OP; st->metafile.integer_precision = meta->integer_precision; } if ((mask & cgm_set_REAL_PRECISION)) { OP(REAL_PRECISION); put_real_precision(st, &meta->real_precision); END_OP; st->metafile.real_precision = meta->real_precision; } if ((mask & cgm_set_INDEX_PRECISION)) { OP(INDEX_PRECISION); I(meta->index_precision); END_OP; st->metafile.index_precision = meta->index_precision; } if ((mask & cgm_set_COLOR_PRECISION)) { OP(COLOR_PRECISION); I(meta->color_precision); END_OP; st->metafile.color_index_precision = meta->color_index_precision; } if ((mask & cgm_set_COLOR_INDEX_PRECISION)) { OP(COLOR_INDEX_PRECISION); I(meta->color_index_precision); END_OP; st->metafile.color_index_precision = meta->color_index_precision; } if ((mask & cgm_set_MAXIMUM_COLOR_INDEX)) { OP(MAXIMUM_COLOR_INDEX); CI(meta->maximum_color_index); END_OP; st->metafile.maximum_color_index = meta->maximum_color_index; } if ((mask & cgm_set_METAFILE_ELEMENT_LIST)) { int i; const int *p; OP(METAFILE_ELEMENT_LIST); for (i = 0, p = meta->metafile_element_list; i < meta->metafile_element_list_count; i++, p += 2 ) { I(p[0]); I(p[1]); } END_OP; st->metafile.metafile_element_list = meta->metafile_element_list; st->metafile.metafile_element_list_count = meta->metafile_element_list_count; } /* element list */ if ((mask & cgm_set_FONT_LIST)) { int i; OP(FONT_LIST); for (i = 0; i < meta->font_list_count; ++i) S(meta->font_list[i].chars, meta->font_list[i].length); END_OP; st->metafile.font_list = meta->font_list; st->metafile.font_list_count = meta->font_list_count; } /* character set list */ /* character coding announcer */ return st->result; } cgm_result cgm_END_METAFILE(cgm_state * st) { OP(END_METAFILE); DONE; } /* ---------------- Picture elements ---------------- */ cgm_result cgm_BEGIN_PICTURE(cgm_state * st, const char *str, uint len) { OP(BEGIN_PICTURE); S(str, len); DONE; } cgm_result cgm_set_picture_elements(cgm_state * st, const cgm_picture_elements * pic, long mask) { if ((mask & cgm_set_SCALING_MODE)) { OP(SCALING_MODE); E(pic->scaling_mode); R(pic->scale_factor); st->picture.scaling_mode = pic->scaling_mode; st->picture.scale_factor = pic->scale_factor; END_OP; } if ((mask & cgm_set_COLOR_SELECTION_MODE)) { OP(COLOR_SELECTION_MODE); E(pic->color_selection_mode); END_OP; st->picture.color_selection_mode = pic->color_selection_mode; } if ((mask & cgm_set_LINE_WIDTH_SPECIFICATION_MODE)) { OP(LINE_WIDTH_SPECIFICATION_MODE); E(pic->line_width_specification_mode); END_OP; st->picture.line_width_specification_mode = pic->line_width_specification_mode; } if ((mask & cgm_set_MARKER_SIZE_SPECIFICATION_MODE)) { OP(MARKER_SIZE_SPECIFICATION_MODE); E(pic->marker_size_specification_mode); END_OP; st->picture.marker_size_specification_mode = pic->marker_size_specification_mode; } if ((mask & cgm_set_EDGE_WIDTH_SPECIFICATION_MODE)) { OP(EDGE_WIDTH_SPECIFICATION_MODE); E(pic->edge_width_specification_mode); END_OP; st->picture.edge_width_specification_mode = pic->edge_width_specification_mode; } if ((mask & cgm_set_VDC_EXTENT)) { OP(VDC_EXTENT); P(&pic->vdc_extent[0]); P(&pic->vdc_extent[1]); END_OP; st->picture.vdc_extent[0] = pic->vdc_extent[0]; st->picture.vdc_extent[1] = pic->vdc_extent[1]; } if ((mask & cgm_set_BACKGROUND_COLOR)) { OP(BACKGROUND_COLOR); CD(&pic->background_color.rgb); DONE; st->picture.background_color = pic->background_color; } return st->result; } cgm_result cgm_BEGIN_PICTURE_BODY(cgm_state * st) { OP(BEGIN_PICTURE_BODY); DONE; } cgm_result cgm_END_PICTURE(cgm_state * st) { OP(END_PICTURE); DONE; } /* ---------------- Control elements ---------------- */ cgm_result cgm_VDC_INTEGER_PRECISION(cgm_state * st, int precision) { if (st->vdc_integer_precision != precision) { OP(VDC_INTEGER_PRECISION); I(precision); st->vdc_integer_precision = precision; DONE; } else return cgm_result_ok; } cgm_result cgm_VDC_REAL_PRECISION(cgm_state * st, const cgm_precision * precision) { OP(VDC_REAL_PRECISION); put_real_precision(st, precision); st->vdc_real_precision = *precision; DONE; } cgm_result cgm_AUXILIARY_COLOR(cgm_state * st, const cgm_color * color) { OP(AUXILIARY_COLOR); CO(color); st->auxiliary_color = *color; DONE; } cgm_result cgm_TRANSPARENCY(cgm_state * st, cgm_transparency transparency) { OP(TRANSPARENCY); E(transparency); st->transparency = transparency; DONE; } cgm_result cgm_CLIP_RECTANGLE(cgm_state * st, const cgm_point rectangle[2]) { OP(CLIP_RECTANGLE); P(&rectangle[0]); st->clip_rectangle[0] = rectangle[0]; P(&rectangle[1]); st->clip_rectangle[1] = rectangle[1]; DONE; } cgm_result cgm_CLIP_INDICATOR(cgm_state * st, cgm_clip_indicator clip) { OP(CLIP_INDICATOR); E(clip); st->clip_indicator = clip; DONE; } /* ---------------- Graphical primitive elements ---------------- */ cgm_result cgm_POLYLINE(cgm_state * st, const cgm_point * vertices, int count) { OP(POLYLINE); nP(vertices, count); DONE; } cgm_result cgm_DISJOINT_POLYLINE(cgm_state * st, const cgm_point * endpoints, int count) { OP(DISJOINT_POLYLINE); nP(endpoints, count); DONE; } cgm_result cgm_POLYMARKER(cgm_state * st, const cgm_point * positions, int count) { OP(POLYMARKER); nP(positions, count); DONE; } cgm_result cgm_TEXT(cgm_state * st, const cgm_point * position, bool final, const char *str, uint len) { OP(TEXT); P(position); E(final); S(str, len); DONE; } cgm_result cgm_RESTRICTED_TEXT(cgm_state * st, const cgm_vdc * delta_width, const cgm_vdc * delta_height, const cgm_point * position, bool final, const char *str, uint len) { OP(RESTRICTED_TEXT); VDC2(delta_width, delta_height); P(position); E(final); S(str, len); DONE; } cgm_result cgm_APPEND_TEXT(cgm_state * st, bool final, const char *str, uint len) { OP(APPEND_TEXT); E(final); S(str, len); DONE; } cgm_result cgm_POLYGON(cgm_state * st, const cgm_point * vertices, int count) { OP(POLYGON); nP(vertices, count); DONE; } cgm_result cgm_POLYGON_SET(cgm_state * st, const cgm_polygon_edge * vertices, int count) { int i; OP(POLYGON); for (i = 0; i < count; ++i) { P(&vertices[i].vertex); E(vertices[i].edge_out); } DONE; } cgm_result cgm_CELL_ARRAY(cgm_state * st, const cgm_point * pqr /*[3] */ , cgm_int nx, cgm_int ny, cgm_int local_color_precision, cgm_cell_representation_mode mode, const byte * values, uint source_bit, uint raster) { int precision = local_color_precision; int bits_per_pixel; uint row_bytes; const byte *row = values + (source_bit >> 3); int bit = source_bit & 7; int y; /* Currently we ignore the cell representation_mode, and always */ /* produce cell arrays in 'packed' format. */ mode = cgm_cell_mode_packed; OP(CELL_ARRAY); nP(pqr, 3); I(nx); I(ny); I(local_color_precision); E(mode); if (precision == 0) precision = (st->picture.color_selection_mode == cgm_color_selection_indexed ? st->metafile.color_index_precision : st->metafile.color_precision); bits_per_pixel = (st->picture.color_selection_mode == cgm_color_selection_indexed ? precision : precision * 3); row_bytes = (bits_per_pixel * nx + 7) >> 3; for (y = 0; y < ny; y++, row += raster) { if (bit == 0) put_bytes(st, row, row_bytes); else { uint i; for (i = 0; i < row_bytes; i++) { byte b = (row[i] << bit) + (row[i + 1] >> (8 - bit)); put_byte(st, b); } } if ((row_bytes & 1)) { put_byte(st, 0); } } DONE; } cgm_result cgm_RECTANGLE(cgm_state * st, const cgm_point * corner1, const cgm_point * corner2) { OP(RECTANGLE); P(corner1); P(corner2); DONE; } cgm_result cgm_CIRCLE(cgm_state * st, const cgm_point * center, const cgm_vdc * radius) { OP(CIRCLE); P(center); VDC(radius); DONE; } cgm_result cgm_CIRCULAR_ARC_3_POINT(cgm_state * st, const cgm_point * start, const cgm_point * intermediate, const cgm_point * end) { OP(CIRCULAR_ARC_3_POINT); P(start); P(intermediate); P(end); DONE; } cgm_result cgm_CIRCULAR_ARC_3_POINT_CLOSE(cgm_state * st, const cgm_point * start, const cgm_point * intermediate, const cgm_point * end, cgm_arc_closure closure) { OP(CIRCULAR_ARC_3_POINT_CLOSE); P(start); P(intermediate); P(end); E(closure); DONE; } cgm_result cgm_CIRCULAR_ARC_CENTER(cgm_state * st, const cgm_point * center, const cgm_vdc * dx_start, const cgm_vdc * dy_start, const cgm_vdc * dx_end, const cgm_vdc * dy_end, const cgm_vdc * radius) { OP(CIRCULAR_ARC_CENTER); P(center); VDC4(dx_start, dy_start, dx_end, dy_end); VDC(radius); DONE; } cgm_result cgm_CIRCULAR_ARC_CENTER_CLOSE(cgm_state * st, const cgm_point * center, const cgm_vdc * dx_start, const cgm_vdc * dy_start, const cgm_vdc * dx_end, const cgm_vdc * dy_end, const cgm_vdc * radius, cgm_arc_closure closure) { OP(CIRCULAR_ARC_CENTER_CLOSE); P(center); VDC4(dx_start, dy_start, dx_end, dy_end); VDC(radius); E(closure); DONE; } cgm_result cgm_ELLIPSE(cgm_state * st, const cgm_point * center, const cgm_point * cd1_end, const cgm_point * cd2_end) { OP(ELLIPSE); P(center); P(cd1_end); P(cd2_end); DONE; } cgm_result cgm_ELLIPTICAL_ARC(cgm_state * st, const cgm_point * center, const cgm_point * cd1_end, const cgm_point * cd2_end, const cgm_vdc * dx_start, const cgm_vdc * dy_start, const cgm_vdc * dx_end, const cgm_vdc * dy_end) { OP(ELLIPTICAL_ARC); P(center); P(cd1_end); P(cd2_end); VDC4(dx_start, dy_start, dx_end, dy_end); DONE; } cgm_result cgm_ELLIPTICAL_ARC_CLOSE(cgm_state * st, const cgm_point * center, const cgm_point * cd1_end, const cgm_point * cd2_end, const cgm_vdc * dx_start, const cgm_vdc * dy_start, const cgm_vdc * dx_end, const cgm_vdc * dy_end, cgm_arc_closure closure) { OP(ELLIPTICAL_ARC_CLOSE); P(center); P(cd1_end); P(cd2_end); VDC4(dx_start, dy_start, dx_end, dy_end); E(closure); DONE; } /* ---------------- Attribute elements ---------------- */ cgm_result cgm_LINE_BUNDLE_INDEX(cgm_state * st, cgm_int index) { OP(LINE_BUNDLE_INDEX); IX(index); st->line_bundle_index = index; DONE; } cgm_result cgm_LINE_TYPE(cgm_state * st, cgm_line_type line_type) { OP(LINE_TYPE); IX((int)line_type); st->line_type = line_type; DONE; } cgm_result cgm_LINE_WIDTH(cgm_state * st, const cgm_line_width * line_width) { OP(LINE_WIDTH); VDC_R(line_width, st->picture.line_width_specification_mode); st->line_width = *line_width; DONE; } cgm_result cgm_LINE_COLOR(cgm_state * st, const cgm_color * color) { OP(LINE_COLOR); CO(color); st->line_color = *color; DONE; } cgm_result cgm_MARKER_BUNDLE_INDEX(cgm_state * st, cgm_int index) { OP(MARKER_BUNDLE_INDEX); IX(index); st->marker_bundle_index = index; DONE; } cgm_result cgm_MARKER_TYPE(cgm_state * st, cgm_marker_type marker_type) { OP(MARKER_TYPE); IX((int)marker_type); st->marker_type = marker_type; DONE; } cgm_result cgm_MARKER_SIZE(cgm_state * st, const cgm_marker_size * marker_size) { OP(MARKER_SIZE); VDC_R(marker_size, st->picture.marker_size_specification_mode); st->marker_size = *marker_size; DONE; } cgm_result cgm_MARKER_COLOR(cgm_state * st, const cgm_color * color) { OP(MARKER_COLOR); CO(color); st->marker_color = *color; DONE; } cgm_result cgm_TEXT_BUNDLE_INDEX(cgm_state * st, cgm_int index) { OP(TEXT_BUNDLE_INDEX); IX(index); st->text_bundle_index = index; DONE; } cgm_result cgm_TEXT_FONT_INDEX(cgm_state * st, cgm_int index) { OP(TEXT_FONT_INDEX); IX(index); st->text_font_index = index; DONE; } cgm_result cgm_TEXT_PRECISION(cgm_state * st, cgm_text_precision precision) { OP(TEXT_PRECISION); E(precision); st->text_precision = precision; DONE; } cgm_result cgm_CHARACTER_EXPANSION_FACTOR(cgm_state * st, cgm_real factor) { OP(CHARACTER_EXPANSION_FACTOR); R(factor); st->character_expansion_factor = factor; DONE; } cgm_result cgm_CHARACTER_SPACING(cgm_state * st, cgm_real spacing) { OP(CHARACTER_SPACING); R(spacing); st->character_spacing = spacing; DONE; } cgm_result cgm_TEXT_COLOR(cgm_state * st, const cgm_color * color) { OP(TEXT_COLOR); CO(color); st->text_color = *color; DONE; } cgm_result cgm_CHARACTER_HEIGHT(cgm_state * st, const cgm_vdc * height) { OP(CHARACTER_HEIGHT); VDC(height); st->character_height = *height; DONE; } cgm_result cgm_CHARACTER_ORIENTATION(cgm_state * st, const cgm_vdc * x_up, const cgm_vdc * y_up, const cgm_vdc * x_base, const cgm_vdc * y_base) { OP(CHARACTER_ORIENTATION); VDC4(x_up, y_up, x_base, y_base); st->character_orientation[0] = *x_up; st->character_orientation[1] = *y_up; st->character_orientation[2] = *x_base; st->character_orientation[3] = *y_base; DONE; } cgm_result cgm_TEXT_PATH(cgm_state * st, cgm_text_path text_path) { OP(TEXT_PATH); E(text_path); st->text_path = text_path; DONE; } cgm_result cgm_TEXT_ALIGNMENT(cgm_state * st, cgm_text_alignment_horizontal align_h, cgm_text_alignment_vertical align_v, cgm_real align_cont_h, cgm_real align_cont_v) { OP(TEXT_ALIGNMENT); E(align_h); E(align_v); R(align_cont_h); R(align_cont_v); DONE; } cgm_result cgm_CHARACTER_SET_INDEX(cgm_state * st, cgm_int index) { OP(CHARACTER_SET_INDEX); IX(index); st->character_set_index = index; DONE; } /* See gdevcgml.c for why this isn't named cgm_ALTERNATE_.... */ cgm_result cgm_ALT_CHARACTER_SET_INDEX(cgm_state * st, cgm_int index) { OP(ALTERNATE_CHARACTER_SET_INDEX); IX(index); st->alternate_character_set_index = index; DONE; } cgm_result cgm_FILL_BUNDLE_INDEX(cgm_state * st, cgm_int index) { OP(FILL_BUNDLE_INDEX); IX(index); st->fill_bundle_index = index; DONE; } cgm_result cgm_INTERIOR_STYLE(cgm_state * st, cgm_interior_style interior_style) { OP(INTERIOR_STYLE); E(interior_style); st->interior_style = interior_style; DONE; } cgm_result cgm_FILL_COLOR(cgm_state * st, const cgm_color * color) { OP(FILL_COLOR); CO(color); st->fill_color = *color; DONE; } cgm_result cgm_HATCH_INDEX(cgm_state * st, cgm_hatch_index hatch_index) { OP(HATCH_INDEX); IX((int)hatch_index); st->hatch_index = hatch_index; DONE; } cgm_result cgm_PATTERN_INDEX(cgm_state * st, cgm_int index) { OP(PATTERN_INDEX); IX(index); st->pattern_index = index; DONE; } cgm_result cgm_EDGE_BUNDLE_INDEX(cgm_state * st, cgm_int index) { OP(EDGE_BUNDLE_INDEX); IX(index); st->edge_bundle_index = index; DONE; } cgm_result cgm_EDGE_TYPE(cgm_state * st, cgm_edge_type edge_type) { OP(EDGE_TYPE); IX((int)edge_type); st->edge_type = edge_type; DONE; } cgm_result cgm_EDGE_WIDTH(cgm_state * st, const cgm_edge_width * edge_width) { OP(EDGE_WIDTH); VDC_R(edge_width, st->picture.edge_width_specification_mode); st->edge_width = *edge_width; DONE; } cgm_result cgm_EDGE_COLOR(cgm_state * st, const cgm_color * color) { OP(EDGE_COLOR); CO(color); DONE; } cgm_result cgm_EDGE_VISIBILITY(cgm_state * st, bool visibility) { OP(EDGE_VISIBILITY); E(visibility); st->edge_visibility = visibility; DONE; } cgm_result cgm_FILL_REFERENCE_POINT(cgm_state * st, const cgm_point * reference_point) { OP(FILL_REFERENCE_POINT); P(reference_point); st->fill_reference_point = *reference_point; DONE; } /* PATTERN_TABLE */ cgm_result cgm_PATTERN_SIZE(cgm_state * st, const cgm_vdc * x_height, const cgm_vdc * y_height, const cgm_vdc * x_width, const cgm_vdc * y_width) { OP(PATTERN_SIZE); VDC4(x_height, y_height, x_width, y_width); st->pattern_size[0] = *x_height; st->pattern_size[1] = *y_height; st->pattern_size[2] = *x_width; st->pattern_size[3] = *y_width; DONE; } cgm_result cgm_COLOR_TABLE(cgm_state * st, cgm_int index, const cgm_color * values, int count) { int i; OP(COLOR_TABLE); CI(index); for (i = 0; i < count; ++i) CD(&values[i].rgb); DONE; } cgm_result cgm_ASPECT_SOURCE_FLAGS(cgm_state * st, const cgm_aspect_source_flag * flags, int count) { int i; OP(ASPECT_SOURCE_FLAGS); for (i = 0; i < count; ++i) { E(flags[i].type); E(flags[i].source); st->source_flags[flags[i].type] = (byte) flags[i].source; } DONE; } /* ================ Internal routines ================ */ /* Begin a command. */ private void begin_command(cgm_state * st, cgm_op_index op) { uint op_word = (uint) op << cgm_op_id_shift; st->command[0] = (byte) (op_word >> 8); st->command[1] = (byte) (op_word); st->command_count = 4; /* leave room for extension */ st->command_first = true; st->result = cgm_result_ok; } /* Write the buffer for a partial command. */ /* Note that we always write an even number of bytes. */ private void write_command(cgm_state * st, bool last) { byte *command = st->command; int count = st->command_count; if (st->command_first) { if (count <= 34) { command[2] = command[0]; command[3] = command[1] + count - 4; command += 2, count -= 2; } else { int pcount = count - 4; command[1] |= 31; command[2] = (byte) (pcount >> 8); if (!last) command[2] |= 0x80; command[3] = (byte) pcount; } st->command_first = false; } else { int pcount = count - 2; command[0] = (byte) (pcount >> 8); if (!last) command[0] |= 0x80; command[1] = (byte) pcount; } fwrite(command, sizeof(byte), count + (count & 1), st->file); st->command_count = 2; /* leave room for extension header */ if (ferror(st->file)) st->result = cgm_result_io_error; } /* End a command. */ private cgm_result end_command(cgm_state * st) { write_command(st, true); return st->result; } /* Put an integer value. */ private void put_int(cgm_state * st, cgm_int value, int precision) { switch (precision) { case 32: put_byte(st, value >> 24); case 24: put_byte(st, value >> 16); case 16: put_byte(st, value >> 8); case 8: put_byte(st, value); } } /* Put a real value. */ private void put_real(cgm_state * st, cgm_real value, const cgm_precision * pr) { if (pr->representation == cgm_representation_floating) { } else { /* Casting to integer simply discards the fraction, */ /* so we need to be careful with negative values. */ long whole = (long)value; double fpart; if (value < whole) --whole; fpart = value - whole; put_int(st, whole, pr->exponent_or_whole_width); if (pr->fraction_width == 16) { uint fraction = (uint) (fpart * (1.0 * 0x10000)); put_int(st, fraction, 16); } else { /* pr->fraction_width == 32 */ ulong fraction = (ulong) (fpart * (1.0 * 0x10000 * 0x10000)); put_int(st, fraction, 32); } } } /* Put a real precision. */ private void put_real_precision(cgm_state * st, const cgm_precision * precision) { I((int)precision->representation); I(precision->exponent_or_whole_width); I(precision->fraction_width); } /* Put a VDC. */ private void put_vdc(cgm_state * st, const cgm_vdc * pvdc) { if (st->metafile.vdc_type == cgm_vdc_integer) put_int(st, pvdc->integer, st->vdc_integer_precision); else put_real(st, pvdc->real, &st->vdc_real_precision); } /* Put a VDC or a real. */ private void put_vdc_r(cgm_state * st, const cgm_line_marker_extent * extent, cgm_line_marker_specification_mode mode) { if (mode == cgm_line_marker_absolute) VDC(&extent->absolute); else R(extent->scaled); } /* Put a point (pair of VDCs). */ private void put_point(cgm_state * st, const cgm_point * ppt) { if (st->metafile.vdc_type == cgm_vdc_integer) { put_int(st, ppt->integer.x, st->vdc_integer_precision); put_int(st, ppt->integer.y, st->vdc_integer_precision); } else { put_real(st, ppt->real.x, &st->vdc_real_precision); put_real(st, ppt->real.y, &st->vdc_real_precision); } } /* Put a list of points. */ private void put_points(cgm_state * st, const cgm_point * ppt, int count) { int i; for (i = 0; i < count; i++) P(ppt + i); } /* Put bytes. */ private void put_bytes(cgm_state * st, const byte * data, uint length) { int count; while (length > (count = command_max_count - st->command_count)) { memcpy(st->command + st->command_count, data, count); st->command_count += count; write_command(st, false); data += count; length -= count; } memcpy(st->command + st->command_count, data, length); st->command_count += length; } /* Put a string. */ private void put_string(cgm_state * st, const char *data, uint length) { /* The CGM specification seems to imply that the continuation */ /* mechanism for commands and the mechanism for strings */ /* are orthogonal; we take this interpretation. */ if (length >= 255) { put_byte(st, 255); while (length > 32767) { put_int(st, 65535, 2); put_bytes(st, (const byte *)data, 32767); data += 32767; length -= 32767; } } put_byte(st, length); put_bytes(st, (const byte *)data, length); } /* Put a color. */ private void put_color(cgm_state * st, const cgm_color * color) { if (st->picture.color_selection_mode == cgm_color_selection_indexed) CI(color->index); else CD(&color->rgb); } /* Put an RGB value. */ private void put_rgb(cgm_state * st, const cgm_rgb * rgb) { put_int(st, rgb->r, st->metafile.color_precision); put_int(st, rgb->g, st->metafile.color_precision); put_int(st, rgb->b, st->metafile.color_precision); }