static void vrml_textpara(GVJ_t *job, pointf p, textpara_t * para) { obj_state_t *obj = job->obj; pointf spf, epf, q; if (! obj->u.n || ! im) /* if not a node - or if no im (e.g. for cluster) */ return; switch (para->just) { case 'l': break; case 'r': p.x -= para->width; break; default: case 'n': p.x -= para->width / 2; break; } q.x = p.x + para->width; q.y = p.y; spf = vrml_node_point(job, obj->u.n, p); epf = vrml_node_point(job, obj->u.n, q); gdgen_text(im, spf, epf, color_index(im, obj->pencolor), para->fontsize, DEFAULT_DPI, job->rotation ? (M_PI / 2) : 0, para->fontname, para->str); }
static int set_penstyle(GVJ_t * job, gdImagePtr im, gdImagePtr brush) { obj_state_t *obj = job->obj; int i, pen, pencolor, transparent, width, dashstyle[40]; pen = pencolor = color_index(im, obj->pencolor); transparent = gdImageGetTransparent(im); if (obj->pen == PEN_DASHED) { for (i = 0; i < 20; i++) dashstyle[i] = pencolor; for (; i < 40; i++) dashstyle[i] = transparent; gdImageSetStyle(im, dashstyle, 20); pen = gdStyled; } else if (obj->pen == PEN_DOTTED) { for (i = 0; i < 2; i++) dashstyle[i] = pencolor; for (; i < 24; i++) dashstyle[i] = transparent; gdImageSetStyle(im, dashstyle, 24); pen = gdStyled; } width = obj->penwidth * job->scale.x; if (width < PENWIDTH_NORMAL) width = PENWIDTH_NORMAL; /* gd can't do thin lines */ gdImageSetThickness(im, width); /* use brush instead of Thickness to improve end butts */ if (width != PENWIDTH_NORMAL) { brush = gdImageCreate(width, width); gdImagePaletteCopy(brush, im); gdImageFilledRectangle(brush, 0, 0, width - 1, width - 1, pencolor); gdImageSetBrush(im, brush); if (pen == gdStyled) pen = gdStyledBrushed; else pen = gdBrushed; } return pen; }
static void vrml_ellipse(GVJ_t * job, pointf * A, int filled) { FILE *out = job->output_file; obj_state_t *obj = job->obj; node_t *n; edge_t *e; double z = obj->z; double rx, ry; int dx, dy; pointf npf, nqf; point np; int pen; gdImagePtr brush = NULL; rx = A[1].x - A[0].x; ry = A[1].y - A[0].y; switch (obj->type) { case ROOTGRAPH_OBJTYPE: case CLUSTER_OBJTYPE: break; case NODE_OBJTYPE: n = obj->u.n; if (shapeOf(n) == SH_POINT) { doSphere (job, n, A[0], z, rx, ry); return; } pen = set_penstyle(job, im, brush); npf = vrml_node_point(job, n, A[0]); nqf = vrml_node_point(job, n, A[1]); dx = ROUND(2 * (nqf.x - npf.x)); dy = ROUND(2 * (nqf.y - npf.y)); PF2P(npf, np); if (filled) gdImageFilledEllipse(im, np.x, np.y, dx, dy, color_index(im, obj->fillcolor)); gdImageArc(im, np.x, np.y, dx, dy, 0, 360, pen); if (brush) gdImageDestroy(brush); fprintf(out, "Transform {\n"); fprintf(out, " translation %.3f %.3f %.3f\n", A[0].x, A[0].y, z); fprintf(out, " scale %.3f %.3f 1\n", rx, ry); fprintf(out, " children [\n"); fprintf(out, " Transform {\n"); fprintf(out, " rotation 1 0 0 1.57\n"); fprintf(out, " children [\n"); fprintf(out, " Shape {\n"); fprintf(out, " geometry Cylinder { side FALSE }\n"); fprintf(out, " appearance Appearance {\n"); fprintf(out, " material Material {\n"); fprintf(out, " ambientIntensity 0.33\n"); fprintf(out, " diffuseColor 1 1 1\n"); fprintf(out, " }\n"); fprintf(out, " texture ImageTexture { url \"node%d.png\" }\n", n->id); fprintf(out, " }\n"); fprintf(out, " }\n"); fprintf(out, " ]\n"); fprintf(out, " }\n"); fprintf(out, " ]\n"); fprintf(out, "}\n"); break; case EDGE_OBJTYPE: e = obj->u.e; /* this is gruesome, but how else can we get z coord */ if (DIST2(A[0], ND_coord_i(e->tail)) < DIST2(A[0], ND_coord_i(e->head))) z = obj->tail_z; else z = obj->head_z; fprintf(out, "Transform {\n"); fprintf(out, " translation %.3f %.3f %.3f\n", A[0].x, A[0].y, z); fprintf(out, " children [\n"); fprintf(out, " Shape {\n"); fprintf(out, " geometry Sphere {radius %.3f }\n", (double) rx); fprintf(out, " appearance USE E%d\n", e->id); fprintf(out, " }\n"); fprintf(out, " ]\n"); fprintf(out, "}\n"); } }
static void vrml_polygon(GVJ_t *job, pointf * A, int np, int filled) { FILE *out = job->output_file; obj_state_t *obj = job->obj; node_t *n; edge_t *e; double z = obj->z; pointf p, mp; gdPoint *points; int i, pen; gdImagePtr brush = NULL; double theta; switch (obj->type) { case ROOTGRAPH_OBJTYPE: fprintf(out, " Background { skyColor %.3f %.3f %.3f }\n", obj->fillcolor.u.rgba[0] / 255., obj->fillcolor.u.rgba[1] / 255., obj->fillcolor.u.rgba[2] / 255.); Saw_skycolor = TRUE; break; case CLUSTER_OBJTYPE: break; case NODE_OBJTYPE: n = obj->u.n; pen = set_penstyle(job, im, brush); points = N_GNEW(np, gdPoint); for (i = 0; i < np; i++) { mp = vrml_node_point(job, n, A[i]); points[i].x = ROUND(mp.x); points[i].y = ROUND(mp.y); } if (filled) gdImageFilledPolygon(im, points, np, color_index(im, obj->fillcolor)); gdImagePolygon(im, points, np, pen); free(points); if (brush) gdImageDestroy(brush); fprintf(out, "Shape {\n"); fprintf(out, " appearance Appearance {\n"); fprintf(out, " material Material {\n"); fprintf(out, " ambientIntensity 0.33\n"); fprintf(out, " diffuseColor 1 1 1\n"); fprintf(out, " }\n"); fprintf(out, " texture ImageTexture { url \"node%d.png\" }\n", n->id); fprintf(out, " }\n"); fprintf(out, " geometry Extrusion {\n"); fprintf(out, " crossSection ["); for (i = 0; i < np; i++) { p.x = A[i].x - ND_coord_i(n).x; p.y = A[i].y - ND_coord_i(n).y; fprintf(out, " %.3f %.3f,", p.x, p.y); } p.x = A[0].x - ND_coord_i(n).x; p.y = A[0].y - ND_coord_i(n).y; fprintf(out, " %.3f %.3f ]\n", p.x, p.y); fprintf(out, " spine [ %d %d %.3f, %d %d %.3f ]\n", ND_coord_i(n).x, ND_coord_i(n).y, z - .01, ND_coord_i(n).x, ND_coord_i(n).y, z + .01); fprintf(out, " }\n"); fprintf(out, "}\n"); break; case EDGE_OBJTYPE: e = obj->u.e; if (np != 3) { static int flag; if (!flag) { flag++; agerr(AGWARN, "vrml_polygon: non-triangle arrowheads not supported - ignoring\n"); } } if (IsSegment) { doArrowhead (job, A); return; } p.x = p.y = 0.0; for (i = 0; i < np; i++) { p.x += A[i].x; p.y += A[i].y; } p.x = p.x / np; p.y = p.y / np; /* it is bad to know that A[1] is the aiming point, but we do */ theta = atan2((A[0].y + A[2].y) / 2.0 - A[1].y, (A[0].x + A[2].x) / 2.0 - A[1].x) + M_PI / 2.0; /* this is gruesome, but how else can we get z coord */ if (DIST2(p, ND_coord_i(e->tail)) < DIST2(p, ND_coord_i(e->head))) z = obj->tail_z; else z = obj->head_z; /* FIXME: arrow vector ought to follow z coord of bezier */ fprintf(out, "Transform {\n"); fprintf(out, " translation %.3f %.3f %.3f\n", p.x, p.y, z); fprintf(out, " children [\n"); fprintf(out, " Transform {\n"); fprintf(out, " rotation 0 0 1 %.3f\n", theta); fprintf(out, " children [\n"); fprintf(out, " Shape {\n"); fprintf(out, " geometry Cone {bottomRadius %.3f height %.3f }\n", obj->penwidth * 2.5, obj->penwidth * 10.0); fprintf(out, " appearance USE E%d\n", e->id); fprintf(out, " }\n"); fprintf(out, " ]\n"); fprintf(out, " }\n"); fprintf(out, " ]\n"); fprintf(out, "}\n"); break; } }
/* long color codes look like '<yellow>', '<white>', '<hotkey>', etc. parsing the long color code is a slow function... but it makes programming with color coded strings a lot easier task it's more or less sorted in order of most frequent appearance to make it less slow cpos is the cursor position, which is used in <hline> and <center> tags for <hline>, the function recurses with Out_text() if dev is NULL, it produces no output */ int long_color_code(StringIO *dev, User *usr, char *code, int *cpos, int *lines, int max_lines, int dont_auto_color) { int i, c, color; char colorbuf[MAX_COLORBUF], buf[PRINT_BUF], *p; if (usr == NULL || code == NULL || !*code || cpos == NULL || lines == NULL) return 0; for(i = 0; i < NUM_COLORS; i++) { if (i == HOTKEY) continue; bufprintf(colorbuf, sizeof(colorbuf), "<%s>", color_table[i].name); if (!cstrnicmp(code, colorbuf, strlen(colorbuf))) { if (!(usr->flags & USR_ANSI)) return strlen(colorbuf)-1; c = usr->color = color_table[i].key; color = Ansi_Color(usr, c); if (usr->flags & USR_BOLD) bufprintf(buf, sizeof(buf), "\x1b[1;%dm", color); else bufprintf(buf, sizeof(buf), "\x1b[%dm", color); put_StringIO(dev, buf); return strlen(colorbuf)-1; } } /* Blinking is really irritating... if (!cstrnicmp(code, "<flash>", 7) || !cstrnicmp(code, "<blink>", 7)) { if (!(usr->flags & USR_ANSI)) return 6; usr->color = KEY_CTRL('F'); color = Ansi_Color(usr, KEY_CTRL('F')); if (usr->flags & USR_BOLD) bufprintf(buf, sizeof(buf), "\x1b[1;%dm", color); else bufprintf(buf, sizeof(buf), "\x1b[%dm", color); put_StringIO(dev, buf); return 6; } */ if (!cstrnicmp(code, "<hotkey>", 8)) { c = code[8]; if (!c) return 7; print_hotkey(usr, c, buf, sizeof(buf), cpos); put_StringIO(dev, buf); return 8; } if (!cstrnicmp(code, "<key>", 5)) { c = code[5]; if (!c) return 4; /* Don't do this; the <key> code is used in the Help files to keep this from happening if (usr->flags & USR_UPPERCASE_HOTKEYS) c = ctoupper(c); */ if (usr->flags & USR_ANSI) { if (usr->flags & USR_BOLD) bufprintf(buf, sizeof(buf), "\x1b[1;%dm%c\x1b[1;%dm", color_table[usr->colors[HOTKEY]].value, c, Ansi_Color(usr, usr->color)); else bufprintf(buf, sizeof(buf), "\x1b[%dm%c\x1b[%dm", color_table[usr->colors[HOTKEY]].value, c, Ansi_Color(usr, usr->color)); (*cpos)++; } else { bufprintf(buf, sizeof(buf), "<%c>", c); *cpos += 3; } put_StringIO(dev, buf); return 5; } if (!cstrnicmp(code, "<beep>", 6)) { if (usr->flags & USR_BEEP) write_StringIO(dev, "\a", 1); return 5; } if (!cstrnicmp(code, "<normal>", 8)) { if (usr->flags & USR_ANSI) { bufprintf(buf, sizeof(buf), "\x1b[0;%dm", color_table[usr->colors[BACKGROUND]].value+10); put_StringIO(dev, buf); } else if (usr->flags & USR_BOLD) put_StringIO(dev, "\x1b[0m"); if (usr->flags & USR_BOLD) put_StringIO(dev, "\x1b[1m"); return 7; } if (!cstrnicmp(code, "<default>", 9)) { if (usr->flags & (USR_ANSI | USR_BOLD)) put_StringIO(dev, "\x1b[0m"); return 8; } if (!cstrnicmp(code, "<lt>", 4)) { if ((usr->flags & USR_ANSI) && !(usr->flags & USR_DONT_AUTO_COLOR) && !dont_auto_color) { auto_color(usr, colorbuf, MAX_COLORBUF); put_StringIO(dev, colorbuf); } write_StringIO(dev, "<", 1); (*cpos)++; if ((usr->flags & USR_ANSI) && !(usr->flags & USR_DONT_AUTO_COLOR) && !dont_auto_color) { restore_colorbuf(usr, usr->color, colorbuf, MAX_COLORBUF); put_StringIO(dev, colorbuf); } return 3; } if (!cstrnicmp(code, "<gt>", 4)) { if ((usr->flags & USR_ANSI) && !(usr->flags & USR_DONT_AUTO_COLOR) && !dont_auto_color) { auto_color(usr, colorbuf, MAX_COLORBUF); put_StringIO(dev, colorbuf); } write_StringIO(dev, ">", 1); (*cpos)++; if ((usr->flags & USR_ANSI) && !(usr->flags & USR_DONT_AUTO_COLOR) && !dont_auto_color) { restore_colorbuf(usr, usr->color, colorbuf, MAX_COLORBUF); put_StringIO(dev, colorbuf); } return 3; } /* there are two special codes for use in help files and stuff... <hline> and <center> especially the code for hline is cryptic, but the idea is that it fills the line to the width of the terminal */ if (!cstrnicmp(code, "<hline>", 7)) { int l; code += 7; if (!*code) return 6; c = ((usr->display->term_width-1) > PRINT_BUF) ? PRINT_BUF : (usr->display->term_width-1); cstrncpy(buf, code, c); /* it stinks, but you have to remove all chars that can reset the cursor pos */ p = buf; while(*p) { if (*p == KEY_CTRL('X') || *p == '\b') memmove(p, p+1, strlen(p+1)+1); else { if (*p == '\n') { /* don't go over newlines */ *p = 0; break; } p++; } } l = strlen(buf); i = color_strlen(buf); while(*cpos + i < usr->display->term_width-1) Out_text(dev, usr, buf, cpos, lines, max_lines, AUTO_COLOR_FORCED); /* recurse */ if (*cpos + i >= usr->display->term_width-1) { /* 'partial put' of the remainder */ buf[color_index(buf, c - *cpos)] = 0; Out_text(dev, usr, buf, cpos, lines, max_lines, AUTO_COLOR_FORCED); } return 6+l; } if (!cstrnicmp(code, "<center>", 8)) { code += 8; if (!*code) return 7; c = strlen(code); c = (c > PRINT_BUF) ? PRINT_BUF : c; cstrncpy(buf, code, c); buf[c-1] = 0; if ((p = cstrchr(buf, '\n')) != NULL) /* don't go over newlines */ *p = 0; i = (usr->display->term_width-1)/2 - color_strlen(buf)/2 - *cpos; while(i > 0) { write_StringIO(dev, " ", 1); (*cpos)++; i--; } return 7; } if ((usr->flags & USR_ANSI) && !(usr->flags & USR_DONT_AUTO_COLOR) && !dont_auto_color) { auto_color(usr, colorbuf, MAX_COLORBUF); put_StringIO(dev, colorbuf); } write_StringIO(dev, "<", 1); (*cpos)++; if ((usr->flags & USR_ANSI) && !(usr->flags & USR_DONT_AUTO_COLOR) && !dont_auto_color) { restore_colorbuf(usr, usr->color, colorbuf, MAX_COLORBUF); put_StringIO(dev, colorbuf); } return 0; }