/* Hello, Emacs, this is -*-C-*- * $Id: dumb.trm,v 1.38.2.4 2017/07/08 05:21:44 sfeam Exp $ * */ /* GNUPLOT - dumb.trm */ /*[ * Copyright 1991 - 1993, 1998, 2004 Thomas Williams, Colin Kelley * * Permission to use, copy, and distribute this software and its * documentation for any purpose with or without fee is hereby granted, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. * * Permission to modify the software is granted, but not the right to * distribute the complete modified source code. Modifications are to * be distributed as patches to the released version. Permission to * distribute binaries produced by compiling modified sources is granted, * provided you * 1. distribute the corresponding source modifications from the * released version in the form of a patch file along with the binaries, * 2. add special version identification to distinguish your version * in addition to the base release version number, * 3. provide your name and address as the primary contact for the * support of your modified version, and * 4. retain our contact information in regard to use of the base * software. * Permission to distribute the released version of the source code along * with corresponding source modifications in the form of a patch file is * granted with same provisions 2 through 4 for binary distributions. * * This software is provided "as is" without express or implied warranty * to the extent permitted by applicable law. ]*/ /* * This file is included by ../term.c. * * This terminal driver supports: * DUMB terminals * * AUTHORS * Francois Pinard, 91-04-03 * INTERNET: pinard@iro.umontreal.ca * * Ethan A Merritt Nov 2003 * Added support for enhanced text mode. * Yes, this is frivolous, but it serves as an example for * adding enhanced text to other terminals. You can disable * it by adding a line * #define NO_DUMB_ENHANCED_SUPPORT * * Bastian Maerkisch Nov 2016 * ANSI color support. Filled polygons. * * send your comments or suggestions to (gnuplot-info@lists.sourceforge.net). * */ #include "driver.h" #ifdef TERM_REGISTER register_term(dumb_driver) #endif #ifdef TERM_PROTO TERM_PUBLIC void DUMB_options __PROTO((void)); TERM_PUBLIC void DUMB_init __PROTO((void)); TERM_PUBLIC void DUMB_graphics __PROTO((void)); TERM_PUBLIC void DUMB_text __PROTO((void)); TERM_PUBLIC void DUMB_reset __PROTO((void)); TERM_PUBLIC void DUMB_linetype __PROTO((int linetype)); TERM_PUBLIC void DUMB_move __PROTO((unsigned int x, unsigned int y)); TERM_PUBLIC void DUMB_point __PROTO((unsigned int x, unsigned int y, int point)); TERM_PUBLIC void DUMB_vector __PROTO((unsigned int x, unsigned int y)); TERM_PUBLIC void DUMB_put_text __PROTO((unsigned int x, unsigned int y, const char *str)); TERM_PUBLIC void DUMB_arrow __PROTO((unsigned int sx, unsigned int sy, unsigned int ex, unsigned int ey, int head)); #ifndef NO_DUMB_ENHANCED_SUPPORT /* To support "set term dumb enhanced" (don't ask why!) */ TERM_PUBLIC void ENHdumb_put_text __PROTO((unsigned int x, unsigned int y, const char str[])); TERM_PUBLIC void ENHdumb_OPEN __PROTO((char * fontname, double fontsize, double base, TBOOLEAN widthflag, TBOOLEAN showflag, int overprint)); TERM_PUBLIC void ENHdumb_FLUSH __PROTO((void)); #else #define ENHdumb_put_text NULL #endif #ifndef NO_DUMB_COLOR_SUPPORT TERM_PUBLIC int dumb_make_palette __PROTO((t_sm_palette *palette)); TERM_PUBLIC void dumb_set_color __PROTO((t_colorspec *)); #endif #define DUMB_XMAX 79 #define DUMB_YMAX 24 #endif /* TERM_PROTO */ #ifdef TERM_BODY #define DUMB_AXIS_CONST '\1' #define DUMB_BORDER_CONST '\2' #define DUMB_FILL_CONST '\3' #ifdef HAVE_STDINT_H #include #endif #include "readline.h" /* UTF-8 support */ #ifdef HAVE_STDLIB_H #define DUMB_UTF8 typedef int32_t charcell; #else typedef char charcell; #endif /* matrix of characters */ static charcell *dumb_matrix = NULL; #ifndef NO_DUMB_COLOR_SUPPORT /* matrix of colors */ static t_colorspec *dumb_colors = NULL; static t_colorspec dumb_color; static t_colorspec dumb_prev_color; #endif /* current character used to draw */ static char dumb_pen; /* current X position */ static int dumb_x; /* current Y position */ static int dumb_y; static int dumb_xmax = DUMB_XMAX; static int dumb_ymax = DUMB_YMAX; static TBOOLEAN dumb_feed = TRUE; static int dumb_colormode = 0; #define DUMB_PIXEL(x,y) dumb_matrix[dumb_xmax*(y)+(x)] static void dumb_set_pixel __PROTO((int x, int y, int v)); enum DUMB_id { DUMB_FEED, DUMB_NOFEED, DUMB_ENH, DUMB_NOENH, DUMB_SIZE, DUMB_ASPECT, DUMB_ANSI, DUMB_ANSI256, DUMB_ANSIRGB, DUMB_NOCOLOR, DUMB_OTHER }; static struct gen_table DUMB_opts[] = { { "f$eed", DUMB_FEED }, { "nof$eed", DUMB_NOFEED }, { "enh$anced", DUMB_ENH }, { "noe$nhanced", DUMB_NOENH }, { "size", DUMB_SIZE }, { "aspect", DUMB_ASPECT }, { "ansi", DUMB_ANSI }, { "ansi256", DUMB_ANSI256 }, { "ansirgb", DUMB_ANSIRGB }, { "mono", DUMB_NOCOLOR }, { NULL, DUMB_OTHER } }; TERM_PUBLIC void DUMB_options() { int x, y; int cmd; TBOOLEAN set_size = FALSE; while (!END_OF_COMMAND) { switch ((cmd = lookup_table(&DUMB_opts[0], c_token))) { case DUMB_FEED: c_token++; dumb_feed = TRUE; break; case DUMB_NOFEED: c_token++; dumb_feed = FALSE; break; #ifndef NO_DUMB_ENHANCED_SUPPORT case DUMB_ENH: c_token++; term->put_text = ENHdumb_put_text; term->flags |= TERM_ENHANCED_TEXT; break; case DUMB_NOENH: c_token++; term->put_text = DUMB_put_text; term->flags &= ~TERM_ENHANCED_TEXT; break; #endif case DUMB_ASPECT: c_token++; x = int_expression(); y = 1; if (!END_OF_COMMAND && equals(c_token, ",")) { c_token++; y = int_expression(); } if (x <= 0) x = 1; if (y <= 0) y = 1; term->h_tic = x; term->v_tic = y; break; case DUMB_ANSI: case DUMB_ANSI256: case DUMB_ANSIRGB: c_token++; dumb_colormode = cmd; term->make_palette = dumb_make_palette; term->set_color = dumb_set_color; break; case DUMB_NOCOLOR: c_token++; dumb_colormode = 0; term->make_palette = NULL; term->set_color = null_set_color; break; case DUMB_SIZE: c_token++; /* Fall through */ case DUMB_OTHER: default: if (set_size) { int_warn(c_token++,"unrecognized option"); break; } x = int_expression(); if (x <= 0 || x > 1024) x = DUMB_XMAX; if (!END_OF_COMMAND) { if (equals(c_token,",")) c_token++; y = int_expression(); if (y <= 0 || y > 1024) y = DUMB_YMAX; dumb_xmax = term->xmax = x; dumb_ymax = term->ymax = y; } set_size = TRUE; break; } } { const char * coloropts[] = {"mono", "ansi", "ansi256", "ansirgb"}; sprintf(term_options, "%sfeed %s size %d, %d aspect %i, %i %s", dumb_feed ? "" : "no", term->put_text == ENHdumb_put_text ? "enhanced" : "", dumb_xmax, dumb_ymax, term->h_tic, term->v_tic, coloropts[dumb_colormode == 0 ? 0 : dumb_colormode - DUMB_ANSI + 1] ); } } static void dumb_set_pixel(int x, int y, int v) { char *charpixel; if ((unsigned int) x <= dumb_xmax /* ie x>=0 && x<=dumb_xmax */ && (unsigned int) y <= dumb_ymax ) { charpixel = (char *)(&dumb_matrix[dumb_xmax * y + x]); /* null-terminate single ascii character (needed for UTF-8) */ dumb_matrix[dumb_xmax * y + x] = 0; *charpixel = v; #ifndef NO_DUMB_COLOR_SUPPORT memcpy(&dumb_colors[dumb_xmax * y + x], &dumb_color, sizeof(t_colorspec)); #endif } } TERM_PUBLIC void DUMB_init() { int size = (dumb_xmax+1) * (dumb_ymax+1); dumb_matrix = gp_realloc(dumb_matrix, size*sizeof(charcell), "dumb terminal"); #ifndef NO_DUMB_COLOR_SUPPORT dumb_colors = gp_realloc(dumb_colors, size*sizeof(t_colorspec), "dumb terminal"); #endif } TERM_PUBLIC void DUMB_graphics() { int i; int size = (dumb_xmax+1) * (dumb_ymax+1); charcell *pm = dumb_matrix; memset(dumb_matrix, 0, size * sizeof(charcell)); #ifndef NO_DUMB_COLOR_SUPPORT memset(dumb_colors, 0, size * sizeof(t_colorspec)); #endif for (i=0; i> 0) & 0xf; b = (rgb255.r >> 4) & 0xf; d += (a - b) * (a - b); a = (ansitab16[i] >> 4) & 0xf; b = (rgb255.g >> 4) & 0xf; d += (a - b) * (a - b); a = (ansitab16[i] >> 8) & 0xf; b = (rgb255.b >> 4) & 0xf; d += (a - b) * (a - b); if (d < dist) { dist = d; best = i; } } return best; } /* end of code libcaca code */ static void DUMB_rgb_color(rgb255_color rgb255) { switch (dumb_colormode) { case DUMB_ANSI: { unsigned color = nearest_ansi(rgb255); fprintf(gpoutfile, "\033[%i;%im", color >= 8 ? 22 : 1, 30 + (color % 8)); break; } case DUMB_ANSI256: if ((rgb255.r / 11 == rgb255.g / 11) && (rgb255.r / 11 == rgb255.b / 11)) { /* gray level */ fprintf(gpoutfile, "\033[38;5;%im", 241 + rgb255.r / 11); } else { rgb255.r /= 43; rgb255.g /= 43; rgb255.b /= 43; fprintf(gpoutfile, "\033[38;5;%im", 16 + 36 * rgb255.r + 6 * rgb255.g + rgb255.b); } break; case DUMB_ANSIRGB: fprintf(gpoutfile, "\033[38;2;%i;%i;%im", rgb255.r, rgb255.g, rgb255.b); break; } } #endif TERM_PUBLIC void DUMB_text() { int x, y; putc('\f', gpoutfile); for (y = dumb_ymax - 1; y >= 0; y--) { #ifndef NO_DUMB_COLOR_SUPPORT if (dumb_colormode > 0) { fputs("\033[0;39m", gpoutfile); /* reset colors to default */ memset(&dumb_prev_color, 0, sizeof(t_colorspec)); } #endif for (x = 0; x < dumb_xmax; x++) { #ifdef DUMB_UTF8 char *c; #endif #ifndef NO_DUMB_COLOR_SUPPORT t_colorspec * color = &dumb_colors[dumb_xmax*y + x]; switch (color->type) { case TC_LT: { int n; if (dumb_colormode < DUMB_ANSI) break; if (dumb_prev_color.type == TC_LT && dumb_prev_color.lt == color->lt) break; n = color->lt + 1; /* map line type to colors */ if (n <= 0) { fprintf(gpoutfile, "\033[0;39m"); /* normal foreground color */ } else { if (n > 15) n = ((n - 1) % 15) + 1; fprintf(gpoutfile, "\033[%i;%im", n > 8 ? 22 : 1, 30 + (n % 8)); } memcpy(&dumb_prev_color, color, sizeof(t_colorspec)); break; } case TC_FRAC: { rgb255_color rgb255; if (dumb_prev_color.type == TC_FRAC && dumb_prev_color.value == color->value) break; rgb255maxcolors_from_gray(color->value, &rgb255); DUMB_rgb_color(rgb255); memcpy(&dumb_prev_color, color, sizeof(t_colorspec)); break; } case TC_RGB: { rgb255_color rgb255; if (dumb_prev_color.type == TC_RGB && dumb_prev_color.lt == color->lt) break; rgb255.r = (color->lt >> 16) & 0xff; rgb255.g = (color->lt >> 8) & 0xff; rgb255.b = (color->lt >> 0) & 0xff; DUMB_rgb_color(rgb255); memcpy(&dumb_prev_color, color, sizeof(t_colorspec)); break; } } #endif #ifdef DUMB_UTF8 c = (char *)(&dumb_matrix[dumb_xmax*y + x]); fputs(c, gpoutfile); #else fputc(DUMB_PIXEL(x, y), gpoutfile); #endif } if (dumb_feed || y > 0) putc('\n', gpoutfile); } #ifndef NO_DUMB_COLOR_SUPPORT if (dumb_colormode > 0) { fputs("\033[0;39;49m", gpoutfile); /* reset colors to default */ } #endif fflush(gpoutfile); } TERM_PUBLIC void DUMB_reset() { free(dumb_matrix); dumb_matrix = NULL; #ifndef NO_DUMB_COLOR_SUPPORT free(dumb_colors); dumb_colors = NULL; #endif } TERM_PUBLIC void DUMB_linetype(int linetype) { static char pen_type[7] = { '*', '#', '$', '%', '@', '&', '=' }; if (linetype == LT_BLACK) dumb_pen = DUMB_BORDER_CONST; else if (linetype == LT_AXIS) dumb_pen = DUMB_AXIS_CONST; else if (linetype <= LT_NODRAW) dumb_pen = ' '; else { linetype = linetype % 7; dumb_pen = pen_type[linetype]; } #ifndef NO_DUMB_COLOR_SUPPORT dumb_color.type = TC_LT; dumb_color.lt = linetype; #endif } TERM_PUBLIC void DUMB_move(unsigned int x, unsigned int y) { dumb_x = x; dumb_y = y; } TERM_PUBLIC void DUMB_point(unsigned int x, unsigned int y, int point) { dumb_set_pixel(x, y, point == -1 ? '.' : point % 26 + 'A'); } TERM_PUBLIC void DUMB_vector(unsigned int arg_x, unsigned int arg_y) { int x = arg_x; /* we need signed int, since * unsigned-signed=unsigned and */ int y = arg_y; /* abs and cast to double wouldn't work */ char pen, pen1; int delta; if (ABS(y - dumb_y) > ABS(x - dumb_x)) { switch (dumb_pen) { case DUMB_AXIS_CONST: pen = ':'; pen1 = '+'; break; case DUMB_BORDER_CONST: pen = '|'; pen1 = '+'; break; case DUMB_FILL_CONST: pen = pen1 = 'X'; break; default: pen = dumb_pen; pen1 = dumb_pen; break; } dumb_set_pixel(dumb_x, dumb_y, pen1); for (delta = 1; delta < ABS(y - dumb_y); delta++) { dumb_set_pixel(dumb_x + (int) ((double) (x - dumb_x) * delta / ABS(y - dumb_y) + 0.5), dumb_y + delta * sign(y - dumb_y), pen); } dumb_set_pixel(x, y, pen1); } else if (ABS(x - dumb_x) > ABS(y - dumb_y)) { switch (dumb_pen) { case DUMB_AXIS_CONST: pen = '.'; pen1 = '+'; break; case DUMB_BORDER_CONST: pen = '-'; pen1 = '+'; break; case DUMB_FILL_CONST: pen = pen1 = 'X'; break; default: pen = dumb_pen; pen1 = dumb_pen; break; } dumb_set_pixel(dumb_x, dumb_y, pen1); for (delta = 1; delta < ABS(x - dumb_x); delta++) dumb_set_pixel(dumb_x + delta * sign(x - dumb_x), dumb_y + (int) ((double) (y - dumb_y) * delta / ABS(x - dumb_x) + 0.5), pen); dumb_set_pixel(x, y, pen1); } else { switch (dumb_pen) { case DUMB_AXIS_CONST: /* zero length axis */ pen = '+'; break; case DUMB_BORDER_CONST: /* zero length border */ pen = '+'; break; case DUMB_FILL_CONST: pen = '#'; break; default: pen = dumb_pen; break; } for (delta = 0; delta <= ABS(x - dumb_x); delta++) dumb_set_pixel(dumb_x + delta * sign(x - dumb_x), dumb_y + delta * sign(y - dumb_y), pen); } dumb_x = x; dumb_y = y; } static void utf8_copy_one(char *dest, char *orig) { *((charcell *)dest) = 0; /* zero-fill */ *dest = *orig; /* first char */ if (encoding != S_ENC_UTF8) return; if ((*dest & 0x80) == 0) /* ascii char */ return; orig++; dest++; while ((*orig & 0xc0) == 0x80) *dest++ = *orig++; } TERM_PUBLIC void DUMB_put_text(unsigned int x, unsigned int y, const char *str) { int i, length; if ((unsigned int) y > dumb_ymax) return; length = gp_strlen(str); if (x + length > dumb_xmax) x = GPMAX(0, dumb_xmax - length); #ifdef DUMB_UTF8 for (i = 0; i < length; i++, x++) { utf8_copy_one( (char *)(&DUMB_PIXEL(x, y)), gp_strchrn(str,i)); #ifndef NO_DUMB_COLOR_SUPPORT memcpy(&dumb_colors[dumb_xmax * y + x], &dumb_color, sizeof(t_colorspec)); #endif } #else for (; x < dumb_xmax && *str; x++, str++) dumb_set_pixel(x, y, *str, 5); #endif } TERM_PUBLIC void DUMB_arrow( unsigned int sx, unsigned int sy, unsigned int ex, unsigned int ey, int head) /* mostly ignored */ { char saved_pen; char saved_x; char saved_y; saved_pen = dumb_pen; saved_x = dumb_x; saved_y = dumb_y; /* Arrow shaft */ if (ex == sx) dumb_pen = '|'; else if (ey == sy) dumb_pen = '-'; else dumb_pen = '.'; dumb_x = sx; dumb_y = sy; DUMB_vector(ex, ey); /* Arrow head */ if (head != NOHEAD) { char headsym; if (ex > sx) headsym = '>'; else if (ex < sx) headsym = '<'; else if (ey > sy) headsym = '^'; else headsym = 'v'; dumb_set_pixel(ex, ey, headsym); } dumb_pen = saved_pen; dumb_x = saved_x; dumb_y = saved_y; } #ifndef NO_DUMB_ENHANCED_SUPPORT /* * The code from here on serves as an example of how to * add enhanced text mode support to even a dumb driver. */ static TBOOLEAN ENHdumb_opened_string; static TBOOLEAN ENHdumb_show = TRUE; static int ENHdumb_overprint = 0; static TBOOLEAN ENHdumb_widthflag = TRUE; static unsigned int ENHdumb_xsave, ENHdumb_ysave; #define ENHdumb_fontsize 1 #define ENHdumb_font "" static double ENHdumb_base; TERM_PUBLIC void ENHdumb_OPEN( char *fontname, double fontsize, double base, TBOOLEAN widthflag, TBOOLEAN showflag, int overprint) { /* There are two special cases: * overprint = 3 means save current position * overprint = 4 means restore saved position */ if (overprint == 3) { ENHdumb_xsave = dumb_x; ENHdumb_ysave = dumb_y; return; } else if (overprint == 4) { DUMB_move(ENHdumb_xsave, ENHdumb_ysave); return; } if (!ENHdumb_opened_string) { ENHdumb_opened_string = TRUE; /* Start new text fragment */ enhanced_cur_text = &enhanced_text[0]; /* Scale fractional font height to vertical units of display */ ENHdumb_base = base * 2; /* Keep track of whether we are supposed to show this string */ ENHdumb_show = showflag; /* 0/1/2 no overprint / 1st pass / 2nd pass */ ENHdumb_overprint = overprint; /* widthflag FALSE means do not update text position after printing */ ENHdumb_widthflag = widthflag; /* Many drivers will need to do something about font selection here */ /* but dumb is dumb */ } } TERM_PUBLIC void ENHdumb_FLUSH() { char *str = enhanced_text; /* The fragment to print */ int x = dumb_x; /* The current position */ int y = dumb_y + (int)ENHdumb_base; int i, len; if (ENHdumb_opened_string) { *enhanced_cur_text = '\0'; len = gp_strlen(str); /* print the string fragment, perhaps invisibly */ /* NB: base expresses offset from current y pos */ if (ENHdumb_show) { #ifdef DUMB_UTF8 for (i = 0; i < len && x < dumb_xmax; i++, x++) { utf8_copy_one( (char *)(&DUMB_PIXEL(x, y)), gp_strchrn(str,i)); #ifndef NO_DUMB_COLOR_SUPPORT memcpy(&dumb_colors[dumb_xmax * y + x], &dumb_color, sizeof(t_colorspec)); #endif } #else for (; x < dumb_xmax && *str; x++, str++) dumb_set_pixel(x, y, *str, 5); #endif } if (!ENHdumb_widthflag) /* don't update position */ ; else if (ENHdumb_overprint == 1) /* First pass of overprint, leave position in center of fragment */ dumb_x += len / 2; else /* Normal case is to update position to end of fragment */ dumb_x += len; ENHdumb_opened_string = FALSE; } } TERM_PUBLIC void ENHdumb_put_text(unsigned int x, unsigned int y, const char *str) { /* If no enhanced text processing is needed, we can use the plain */ /* vanilla put_text() routine instead of this fancy recursive one. */ if (ignore_enhanced_text || !strpbrk(str, "{}^_@&~")) { DUMB_put_text(x,y,str); return; } /* Set up global variables needed by enhanced_recursion() */ enhanced_fontscale = 1.0; ENHdumb_opened_string = FALSE; strncpy(enhanced_escape_format,"%c",sizeof(enhanced_escape_format)); DUMB_move(x,y); /* Set the recursion going. We say to keep going until a * closing brace, but we don't really expect to find one. * If the return value is not the nul-terminator of the * string, that can only mean that we did find an unmatched * closing brace in the string. We increment past it (else * we get stuck in an infinite loop) and try again. */ while (*(str = enhanced_recursion((char *)str, TRUE, ENHdumb_font, ENHdumb_fontsize, 0.0, TRUE, TRUE, 0))) { (term->enhanced_flush)(); /* I think we can only get here if *str == '}' */ enh_err_check(str); if (!*++str) break; /* end of string */ /* else carry on and process the rest of the string */ } } #endif /* NO_DUMB_ENHANCED_SUPPORT */ #ifndef NO_DUMB_COLOR_SUPPORT TERM_PUBLIC int dumb_make_palette(t_sm_palette *palette) { /* report continuous colors */ return 0; } TERM_PUBLIC void dumb_set_color(t_colorspec *colorspec) { memcpy(&dumb_color, colorspec, sizeof(t_colorspec)); } #endif static int dumb_float_compare(const void * elem1, const void * elem2) { int val = *(float *)elem1 - *(float *)elem2; return (0 < val) - (val < 0); }; /* adopted copy from caca.trm */ TERM_PUBLIC void dumb_filled_polygon(int points, gpiPoint *corners) { char save_pen; /* Eliminate duplicate polygon points. */ if ((corners[0].x == corners[points - 1].x) && (corners[0].y == corners[points - 1].y)) points--; /* Need at least three remaining points */ if (points < 3) return; /* temporarily change pen */ save_pen = dumb_pen; dumb_pen = DUMB_FILL_CONST; { /* ---------------------------------------------------------------- * Derived from * public-domain code by Darel Rex Finley, 2007 * http://alienryderflex.com/polygon_fill/ * ---------------------------------------------------------------- */ int nodes; float * nodeX; int pixelY; int i, j; int ymin = dumb_ymax, ymax = 0; int xmin = dumb_xmax, xmax = 0; /* Find bounding box */ for (i = 0; i < points; i++) { if (corners[i].x < xmin) xmin = corners[i].x; if (corners[i].x > xmax) xmax = corners[i].x; if (corners[i].y < ymin) ymin = corners[i].y; if (corners[i].y > ymax) ymax = corners[i].y; } /* Dynamically allocate node list. */ nodeX = (float *) gp_alloc(sizeof(* nodeX) * points, "nodeX"); /* Loop through the rows of the image. */ for (pixelY = ymin; pixelY <= ymax + 1; pixelY++) { /* Build a sorted list of nodes. */ nodes = 0; j = points - 1; for (i = 0; i < points; i++) { if (((corners[i].y < pixelY) && (corners[j].y >= pixelY)) || ((corners[j].y < pixelY) && (corners[i].y >= pixelY))) { nodeX[nodes++] = (corners[i].x + + (double) (pixelY - corners[i].y) / (double) (corners[j].y - corners[i].y) * (double) (corners[j].x - corners[i].x)); } j = i; } qsort(nodeX, nodes, sizeof(float), dumb_float_compare); /* Fill the pixels between node pairs. */ for (i = 0; i < nodes; i += 2) { if (nodeX[i] > xmax) break; if (nodeX[i + 1] >= 0) { /* TODO: Are these checks ever required? */ if (nodeX[i] < xmin) nodeX[i] = xmin; if (nodeX[i + 1] > xmax) nodeX[i + 1] = xmax; /* skip lines with zero length */ if (nodeX[i + 1] - nodeX[i] < 0.5) continue; DUMB_move((int)(nodeX[i] + 0.5), pixelY); DUMB_vector((int)(nodeX[i + 1]), pixelY); } } } /* cleanup */ free(nodeX); /* ---------------------------------------------------------------- */ } /* restore pen */ dumb_pen = save_pen; } #endif /* TERM_BODY */ #ifdef TERM_TABLE TERM_TABLE_START(dumb_driver) "dumb", "ascii art for anything that prints text", DUMB_XMAX, DUMB_YMAX, 1, 1, 1, 2, /* account for typical aspect ratio of characters */ DUMB_options, DUMB_init, DUMB_reset, DUMB_text, null_scale, DUMB_graphics, DUMB_move, DUMB_vector, DUMB_linetype, DUMB_put_text, null_text_angle, null_justify_text, DUMB_point, DUMB_arrow, set_font_null, 0, /* pointsize */ TERM_CAN_MULTIPLOT, NULL, NULL, NULL, NULL, #ifdef USE_MOUSE NULL, NULL, NULL, NULL, NULL, #endif NULL, /* Color support sets this to dumb_make_palette */ NULL, /* previous_palette */ NULL, /* Color support sets this to dumb_set_color */ dumb_filled_polygon, /* filled_polygon */ NULL, /* image */ #ifndef NO_DUMB_ENHANCED_SUPPORT ENHdumb_OPEN, ENHdumb_FLUSH, do_enh_writec #endif /* NO_DUMB_ENHANCED_SUPPORT */ TERM_TABLE_END(dumb_driver) #undef LAST_TERM #define LAST_TERM dumb_driver #endif /* TERM_TABLE */ #ifdef TERM_HELP START_HELP(dumb) "1 dumb", "?commands set terminal dumb", "?set terminal dumb", "?set term dumb", "?terminal dumb", "?term dumb", "?dumb", " The `dumb` terminal driver plots into a text block using ascii characters.", " It has an optional size specification and a trailing linefeed flag.", "", " Syntax:", " set terminal dumb {size ,} {[no]feed}", " {aspect {,}}", #ifndef NO_DUMB_ENHANCED_SUPPORT " {[no]enhanced}", #endif #ifndef NO_DUMB_COLOR_SUPPORT " {mono|ansi|ansi256|ansirgb}", #endif "", " where and set the size of the text block. The default is", " 79 by 24. The last newline is printed only if `feed` is enabled.", "", " The `aspect` option can be used to control the aspect ratio of the plot by", " setting the length of the horizontal and vertical tic marks. Only integer", " values are allowed. Default is 2,1 -- corresponding to the aspect ratio of", " common screen fonts.", "", #ifndef NO_DUMB_COLOR_SUPPORT " The `ansi`, `ansi256`, and `ansirgb` options will include escape", " sequences in the output to handle colors. Note that these might", " not be handled by your terminal. Default is `mono`.", " To obtain the best color match in `ansi` mode, you should use", " `set colorsequence classic`.", " Depending on the mode, the `dumb` terminal will emit the", " folowing sequences (without the additional whitespace):", "", " ESC [ 0 m reset attributes to defaults", " foreground color:", " ESC [ 1 m set intense/bold", " ESC [ 22 m intense/bold off", " ESC [ m with color code 30 <= <= 37", " ESC [ 39 m reset to default", " ESC [ 38; 5; m with palette index 16 <= <= 255", " ESC [ 38; 2; ; ; m with components 0 <= <= 255", " background color:", " ESC [ m with color code 40 <= <= 47", " ESC [ 49 m reset to default", " ESC [ 48; 5; m with palette index 16 <= <= 231", " ESC [ 48; 2; ; ; m with components 0 <= <= 255", "", " See also e.g. the description at", "^ ", " https://en.wikipedia.org/wiki/ANSI_escape_code#Colors", "^ ", "", #endif " Example:", " set term dumb mono size 60,15 aspect 1", " set tics nomirror scale 0.5", " plot [-5:6.5] sin(x) with impulse ls -1", "", " 1 +-------------------------------------------------+", " 0.8 +|||++ ++||||++ |", " 0.6 +|||||+ ++|||||||+ sin(x) +----+ |", " 0.4 +||||||+ ++|||||||||+ |", " 0.2 +|||||||+ ++|||||||||||+ +|", " 0 ++++++++++++++++++++++++++++++++++++++++++++++++++|", " -0.2 + +|||||||||||+ +|||||||||||+ |", " -0.4 + +|||||||||+ +|||||||||+ |", " -0.6 + +|||||||+ +|||||||+ |", " -0.8 + ++||||+ ++||||+ |", " -1 +---+--------+--------+-------+--------+--------+-+", " -4 -2 0 2 4 6 " END_HELP(dumb) #endif /* TERM_HELP */