1/* $Id: */
2/* vim:set shiftwidth=8 ts=8: */
3
4/**********************************************************
5* Copyright (c) 2011 Andy Jeutter *
6* AKA HallerHarry at gmx.de *
7* All rights reserved. *
8**********************************************************/
9
10/*************************************************************************
11 * This program and the accompanying materials
12 * are made available under the terms of the Eclipse Public License v1.0
13 * which accompanies this distribution, and is available at
14 * http://www.eclipse.org/legal/epl-v10.html
15 *
16 * Contributors: See CVS logs. Details at http://www.graphviz.org/
17 *************************************************************************/
18
19#define _GNU_SOURCE
20#include "config.h"
21
22#include <stdarg.h>
23#include <stdlib.h>
24#include <string.h>
25#include <ctype.h>
26#include <errno.h>
27
28#include "macros.h"
29#include "const.h"
30
31#include "gvplugin_render.h"
32#include "gvplugin_device.h"
33#include "gvio.h"
34#include "gvcint.h"
35
36#define POV_VERSION \
37 "#version 3.6;\n"
38
39#define POV_GLOBALS \
40 "global_settings { assumed_gamma 1.0 }\n"
41
42#define POV_DEFAULT \
43 "#default { finish { ambient 0.1 diffuse 0.9 } }\n"
44
45#define POV_INCLUDE \
46 "#include \"colors.inc\"\n"\
47 "#include \"textures.inc\"\n"\
48 "#include \"shapes.inc\"\n"
49
50#define POV_LIGHT \
51 "light_source { <1500,3000,-2500> color White }\n"
52
53#define POV_CAMERA \
54 "camera { location <%.3f , %.3f , %.3f>\n"\
55 " look_at <%.3f , %.3f , %.3f>\n"\
56 " right x * image_width / image_height\n"\
57 " angle %.3f\n"\
58 "}\n"
59
60#define POV_SKY_AND_GND \
61 "//sky\n"\
62 "plane { <0, 1, 0>, 1 hollow\n"\
63 " texture {\n"\
64 " pigment { bozo turbulence 0.95\n"\
65 " color_map {\n"\
66 " [0.00 rgb <0.05, 0.20, 0.50>]\n"\
67 " [0.50 rgb <0.05, 0.20, 0.50>]\n"\
68 " [0.75 rgb <1.00, 1.00, 1.00>]\n"\
69 " [0.75 rgb <0.25, 0.25, 0.25>]\n"\
70 " [1.00 rgb <0.50, 0.50, 0.50>]\n"\
71 " }\n"\
72 " scale <1.00, 1.00, 1.50> * 2.50\n"\
73 " translate <0.00, 0.00, 0.00>\n"\
74 " }\n"\
75 " finish { ambient 1 diffuse 0 }\n"\
76 " }\n"\
77 " scale 10000\n"\
78 "}\n"\
79 "//mist\n"\
80 "fog { fog_type 2\n"\
81 " distance 50\n"\
82 " color rgb <1.00, 1.00, 1.00> * 0.75\n"\
83 " fog_offset 0.10\n"\
84 " fog_alt 1.50\n"\
85 " turbulence 1.75\n"\
86 "}\n"\
87 "//gnd\n"\
88 "plane { <0.00, 1.00, 0.00>, 0\n"\
89 " texture {\n"\
90 " pigment{ color rgb <0.25, 0.45, 0.00> }\n"\
91 " normal { bumps 0.75 scale 0.01 }\n"\
92 " finish { phong 0.10 }\n"\
93 " }\n"\
94 "}\n"
95
96#define POV_BOX \
97 "box { <%.3f, %.3f, %.3f>, <%.3f, %.3f, %.3f>\n"
98
99#define POV_SCALE1 \
100 "scale %.3f\n"
101
102#define POV_SCALE3 \
103 "scale "POV_VECTOR3"\n"
104
105#define POV_ROTATE \
106 "rotate "POV_VECTOR3"\n"
107
108#define POV_TRANSLATE \
109 "translate"POV_VECTOR3"\n"
110
111#define END \
112 "}\n"
113
114#define POV_TORUS \
115 "torus { %.3f, %.3f\n"
116
117#define POV_SPHERE_SWEEP \
118 "sphere_sweep {\n"\
119 " %s\n"\
120 " %d,\n"
121
122#define POV_SPHERE \
123 "sphere {"POV_VECTOR3", 1.0\n" // center, radius
124
125#define POV_TEXT \
126 "text {\n"\
127 " ttf \"%s\",\n"\
128 " \"%s\", %.3f, %.3f\n"
129
130#define POV_DECLARE \
131 "#declare %s = %s;\n"
132
133#define POV_OBJECT \
134 "object { %s }\n"
135
136#define POV_VERBATIM \
137 "%s\n"
138
139#define POV_DEBUG \
140 "#debug %s\n"
141
142#define POV_POLYGON \
143 "polygon { %d,\n"
144
145#define POV_VECTOR3 \
146 "<%9.3f, %9.3f, %9.3f>"
147
148#define POV_PIGMENT_COLOR \
149 "pigment { color %s }\n"
150
151#define POV_COLOR_NAME \
152 "%s transmit %.3f"
153
154#define POV_COLOR_RGB \
155 "rgb"POV_VECTOR3" transmit %.3f"
156
157//colors are taken from /usr/share/povray-3.6/include/colors.inc
158//list must be LANG_C sorted (all lower case)
159#define POV_COLORS \
160"aquamarine",\
161"bakerschoc",\
162"black",\
163"blue",\
164"blueviolet",\
165"brass",\
166"brightgold",\
167"bronze",\
168"bronze2",\
169"brown",\
170"cadetblue",\
171"clear",\
172"coolcopper",\
173"copper",\
174"coral",\
175"cornflowerblue",\
176"cyan",\
177"darkbrown",\
178"darkgreen",\
179"darkolivegreen",\
180"darkorchid",\
181"darkpurple",\
182"darkslateblue",\
183"darkslategray",\
184"darkslategrey",\
185"darktan",\
186"darkturquoise",\
187"darkwood",\
188"dkgreencopper",\
189"dustyrose",\
190"feldspar",\
191"firebrick",\
192"flesh",\
193"forestgreen",\
194"gold",\
195"goldenrod",\
196"gray05",\
197"gray10",\
198"gray15",\
199"gray20",\
200"gray25",\
201"gray30",\
202"gray35",\
203"gray40",\
204"gray45",\
205"gray50",\
206"gray55",\
207"gray60",\
208"gray65",\
209"gray70",\
210"gray75",\
211"gray80",\
212"gray85",\
213"gray90",\
214"gray95",\
215"green",\
216"greencopper",\
217"greenyellow",\
218"huntersgreen",\
219"indianred",\
220"khaki",\
221"lightblue",\
222"light_purple",\
223"lightsteelblue",\
224"lightwood",\
225"limegreen",\
226"magenta",\
227"mandarinorange",\
228"maroon",\
229"mediumaquamarine",\
230"mediumblue",\
231"mediumforestgreen",\
232"mediumgoldenrod",\
233"mediumorchid",\
234"mediumseagreen",\
235"mediumslateblue",\
236"mediumspringgreen",\
237"mediumturquoise",\
238"mediumvioletred",\
239"mediumwood",\
240"med_purple",\
241"mica",\
242"midnightblue",\
243"navy",\
244"navyblue",\
245"neonblue",\
246"neonpink",\
247"newmidnightblue",\
248"newtan",\
249"oldgold",\
250"orange",\
251"orangered",\
252"orchid",\
253"palegreen",\
254"pink",\
255"plum",\
256"quartz",\
257"red",\
258"richblue",\
259"salmon",\
260"scarlet",\
261"seagreen",\
262"semiSweetChoc",\
263"sienna",\
264"silver",\
265"skyblue",\
266"slateblue",\
267"spicypink",\
268"springgreen",\
269"steelblue",\
270"summersky",\
271"tan",\
272"thistle",\
273"turquoise",\
274"verydarkbrown",\
275"very_light_purple",\
276"violet",\
277"violetred",\
278"wheat",\
279"white",\
280"yellow",\
281"yellowgreen"
282
283#define GV_OBJ_EXT(type, obj, name) \
284 do { \
285 char debug_str[256]; \
286 gvprintf(job, POV_DECLARE, type, obj); \
287 gvprintf(job, POV_OBJECT, type); \
288 gvprintf(job, POV_DECLARE, "Min", "min_extent("type")"); \
289 gvprintf(job, POV_DECLARE, "Max", "max_extent("type")"); \
290 snprintf(debug_str, 256, \
291 "concat(\"Dim = \" , vstr(3, Max - Min, \", \", 0, 3)," \
292 " \" "type": %s\", \"\\n\")", name); \
293 gvprintf(job, POV_DEBUG, debug_str); \
294 } while (0)
295
296/*
297//png, gif, NO jpg!
298pigment
299{ image_map
300 { gif "image.gif"
301 map_type 1
302 }
303}
304*/
305
306/*
307#declare Sphere =
308sphere {
309 <0,0,0>, 1
310 pigment { rgb <1,0,0> }
311}
312#declare Min = min_extent ( Sphere );
313#declare Max = max_extent ( Sphere );
314object { Sphere }
315box {
316 Min, Max
317 pigment { rgbf <1,1,1,0.5> }
318 scale<20,20,20>
319}
320*/
321
322/*
323STRING functions
324
325str( float , min_len , digits_after_dot )
326concat( STRING , STRING , [STRING ,...])
327chr( INT )
328substr( STRING , INT , INT )
329strupr( STRING )
330strlwr( STRING )
331vstr( vec_dimension , vec, sep_str, min_len, digits_after_dot )
332
333examples:
334#debug vstr(3, Min, ", ", 0, 3)
335#debug "\n*****************\n"
336#debug concat ( "Max =", vstr(3, Max, ", ", 0, 3), chr(13), chr(10) )
337*/
338
339
340#define DPI 72.0
341#define RENDERER_COLOR_TYPE RGBA_BYTE
342typedef enum { FORMAT_POV, } format_type;
343
344//#define DEBUG
345
346//TODO: check why this dot file does not work (90 rotated)
347// /usr/share/graphviz/graphs/directed/NaN.gv
348//TODO: add Texttures
349//TODO: check how we can receive attributes from dot file
350// if we can't receive attributes set defaults in pov include file
351// - put #include "graph-scheme-fancy.inc" in pov file
352// - run povray with +L`pwd`
353// - put e.g. #declare mycolor = Gold; in graph-scheme-fancy.inc
354// - use textures and color: pigment { color mycolor transmit 0.000 }
355//TODO: idea, put the whole graph in a declare= and then
356// print it with something along the line:
357// object{ graph translate{page->translation, ...} rotate{page->rotation, ...} }
358
359static char *pov_knowncolors[] = { POV_COLORS };
360
361static float layerz = 0;
362static float z = 0;
363
364char *el(GVJ_t* job, char *template, ...)
365{
366#if defined(HAVE_VASPRINTF)
367 char *str;
368 va_list arglist;
369
370 va_start(arglist, template);
371 vasprintf(&str, template, arglist);
372 va_end(arglist);
373
374 return str;
375#elif defined(HAVE_VSNPRINTF)
376 char buf[BUFSIZ];
377 int len;
378 char *str;
379 va_list arglist;
380
381 va_start(arglist, template);
382 len = vsnprintf((char *)buf, BUFSIZ, template, arglist);
383 if (len < 0) {
384 job->common->errorfn("pov renderer:el - %s\n", strerror(errno));
385 str = strdup ("");
386 }
387 else if (len >= BUFSIZ) {
388 str = malloc (len+1);
389 va_end(arglist);
390 va_start(arglist, template);
391 len = vsprintf(str, template, arglist);
392 }
393 else {
394 str = strdup (buf);
395 }
396 va_end(arglist);
397
398 return str;
399#else
400/* Dummy function that will never be used */
401 return strdup("");
402#endif
403}
404
405static char *pov_color_as_str(GVJ_t * job, gvcolor_t color, float transparency)
406{
407 char *pov, *c = NULL;
408 switch (color.type) {
409 case COLOR_STRING:
410#ifdef DEBUG
411 gvprintf(job, "// type = %d, color = %s\n", color.type, color.u.string);
412#endif
413 if (!strcmp(color.u.string, "red"))
414 c = el(job, POV_COLOR_NAME, "Red", transparency);
415 else if (!strcmp(color.u.string, "green"))
416 c = el(job, POV_COLOR_NAME, "Green", transparency);
417 else if (!strcmp(color.u.string, "blue"))
418 c = el(job, POV_COLOR_NAME, "Blue", transparency);
419 else
420 c = el(job, POV_COLOR_NAME, color.u.string, transparency);
421 break;
422 case RENDERER_COLOR_TYPE:
423#ifdef DEBUG
424 gvprintf(job, "// type = %d, color = %d, %d, %d\n",
425 color.type, color.u.rgba[0], color.u.rgba[1],
426 color.u.rgba[2]);
427#endif
428 c = el(job, POV_COLOR_RGB,
429 color.u.rgba[0] / 256.0, color.u.rgba[1] / 256.0,
430 color.u.rgba[2] / 256.0, transparency);
431 break;
432 default:
433 fprintf(stderr,
434 "oops, internal error: unhandled color type=%d %s\n",
435 color.type, color.u.string);
436 assert(0); //oops, wrong type set in gvrender_features_t?
437 }
438 pov = el(job, POV_PIGMENT_COLOR, c);
439 free(c);
440 return pov;
441}
442
443static void pov_comment(GVJ_t * job, char *str)
444{
445 gvprintf(job, "//*** comment: %s\n", str);
446}
447
448static void pov_begin_job(GVJ_t * job)
449{
450 gvputs(job, POV_VERSION);
451 gvputs(job, POV_GLOBALS);
452 gvputs(job, POV_DEFAULT);
453 gvputs(job, POV_INCLUDE);
454 gvprintf(job, POV_DECLARE, "black", "Black");
455 gvprintf(job, POV_DECLARE, "white", "White");
456}
457
458static void pov_begin_graph(GVJ_t * job)
459{
460 float x, y, d, px, py;
461
462 gvprintf(job, "//*** begin_graph %s\n", agnameof(job->obj->u.g));
463#ifdef DEBUG
464 gvprintf(job, "// graph_index = %d, pages = %d, layer = %d/%d\n",
465 job->graph_index, job->numPages, job->layerNum,
466 job->numLayers);
467 gvprintf(job, "// pagesArraySize.x,y = %d,%d\n", job->pagesArraySize.x,
468 job->pagesArraySize.y);
469 gvprintf(job, "// pagesArrayFirst.x,y = %d,%d\n",
470 job->pagesArrayFirst.x, job->pagesArrayFirst.y);
471 gvprintf(job, "// pagesArrayElem.x,y = %d,%d\n", job->pagesArrayElem.x,
472 job->pagesArrayElem.y);
473 gvprintf(job, "// bb.LL,UR = %.3f,%.3f, %.3f,%.3f\n", job->bb.LL.x,
474 job->bb.LL.y, job->bb.UR.x, job->bb.UR.y);
475 gvprintf(job, "// pageBox in graph LL,UR = %.3f,%.3f, %.3f,%.3f\n",
476 job->pageBox.LL.x, job->pageBox.LL.y, job->pageBox.UR.x,
477 job->pageBox.UR.y);
478 gvprintf(job, "// pageSize.x,y = %.3f,%.3f\n", job->pageSize.x,
479 job->pageSize.y);
480 gvprintf(job, "// focus.x,y = %.3f,%.3f\n", job->focus.x, job->focus.y);
481 gvprintf(job, "// zoom = %.3f, rotation = %d\n", job->zoom,
482 (float)job->rotation);
483 gvprintf(job, "// view port.x,y = %.3f,%.3f\n", job->view.x,
484 job->view.y);
485 gvprintf(job, "// canvasBox LL,UR = %.3f,%.3f, %.3f,%.3f\n",
486 job->canvasBox.LL.x, job->canvasBox.LL.y, job->canvasBox.UR.x,
487 job->canvasBox.UR.y);
488 gvprintf(job, "// pageBoundingBox LL,UR = %d,%d, %d,%d\n",
489 job->pageBoundingBox.LL.x, job->pageBoundingBox.LL.y,
490 job->pageBoundingBox.UR.x, job->pageBoundingBox.UR.y);
491 gvprintf(job, "// boundingBox (all pages) LL,UR = %d,%d, %d,%d\n",
492 job->boundingBox.LL.x, job->boundingBox.LL.y,
493 job->boundingBox.UR.x, job->boundingBox.UR.y);
494 gvprintf(job, "// scale.x,y = %.3f,%.3f\n", job->scale.x, job->scale.y);
495 gvprintf(job, "// translation.x,y = %.3f,%.3f\n", job->translation.x,
496 job->translation.y);
497 gvprintf(job, "// devscale.x,y = %.3f,%.3f\n", job->devscale.x,
498 job->devscale.y);
499 gvprintf(job, "// verbose = %d\n", job->common->verbose);
500 gvprintf(job, "// cmd = %s\n", job->common->cmdname);
501 gvprintf(job, "// info = %s, %s, %s\n", job->common->info[0],
502 job->common->info[1], job->common->info[2]);
503#endif
504
505 //setup scene
506 x = job->view.x / 2.0 * job->scale.x;
507 y = job->view.y / 2.0 * job->scale.y;
508 d = -500;
509 px = atanf(x / fabsf(d)) * 180 / M_PI * 2;
510 py = atanf(y / fabsf(d)) * 180 / M_PI * 2;
511 gvprintf(job, POV_CAMERA, x, y, d, x, y, 0.0,
512 (px > py ? px : py) * 1.2);
513 gvputs(job, POV_SKY_AND_GND);
514 gvputs(job, POV_LIGHT);
515}
516
517static void pov_end_graph(GVJ_t * job)
518{
519 gvputs(job, "//*** end_graph\n");
520}
521
522static void pov_begin_layer(GVJ_t * job, char *layername, int layerNum, int numLayers)
523{
524 gvprintf(job, "//*** begin_layer: %s, %d/%d\n", layername, layerNum,
525 numLayers);
526 layerz = layerNum * -10;
527}
528
529static void pov_end_layer(GVJ_t * job)
530{
531 gvputs(job, "//*** end_layer\n");
532}
533
534static void pov_begin_page(GVJ_t * job)
535{
536 gvputs(job, "//*** begin_page\n");
537}
538
539static void pov_end_page(GVJ_t * job)
540{
541 gvputs(job, "//*** end_page\n");
542}
543
544static void pov_begin_cluster(GVJ_t * job)
545{
546 gvputs(job, "//*** begin_cluster\n");
547 layerz -= 2;
548}
549
550static void pov_end_cluster(GVJ_t * job)
551{
552 gvputs(job, "//*** end_cluster\n");
553}
554
555static void pov_begin_node(GVJ_t * job)
556{
557 gvprintf(job, "//*** begin_node: %s\n", agnameof(job->obj->u.n));
558}
559
560static void pov_end_node(GVJ_t * job)
561{
562 gvputs(job, "//*** end_node\n");
563}
564
565static void pov_begin_edge(GVJ_t * job)
566{
567 gvputs(job, "//*** begin_edge\n");
568 layerz -= 5;
569#ifdef DEBUG
570 gvprintf(job, "// layerz = %.3f\n", layerz);
571#endif
572}
573
574static void pov_end_edge(GVJ_t * job)
575{
576 gvputs(job, "//*** end_edge\n");
577 layerz += 5;
578#ifdef DEBUG
579 gvprintf(job, "// layerz = %.3f\n", layerz);
580#endif
581}
582
583static void pov_textspan(GVJ_t * job, pointf c, textspan_t * span)
584{
585 double x, y;
586 char *pov, *s, *r, *t, *p;
587
588 gvprintf(job, "//*** textspan: %s, fontsize = %.3f, fontname = %s\n",
589 span->str, span->font->size, span->font->name);
590 z = layerz - 9;
591
592#ifdef DEBUG
593 if (span->font->postscript_alias)
594 gvputs(job, "// Warning: postscript_alias not handled!\n");
595#endif
596
597 //handle text justification
598 switch (span->just) {
599 case 'l': //left justified
600 break;
601 case 'r': //right justified
602 c.x = c.x - span->size.x;
603 break;
604 default:
605 case 'n': //centered
606 c.x = c.x - span->size.x / 2.0;
607 break;
608 }
609
610 x = (c.x + job->translation.x) * job->scale.x;
611 y = (c.y + job->translation.y) * job->scale.y;
612
613 s = el(job, POV_SCALE1, span->font->size * job->scale.x);
614 r = el(job, POV_ROTATE, 0.0, 0.0, (float)job->rotation);
615 t = el(job, POV_TRANSLATE, x, y, z);
616 p = pov_color_as_str(job, job->obj->pencolor, 0.0);
617
618 //pov bundled fonts: timrom.ttf, cyrvetic.ttf
619 pov = el(job, POV_TEXT " %s %s %s %s %s" END,
620 span->font->name, 0.25, 0.0, //font, depth (0.5 ... 2.0), offset
621 span->str, " no_shadow\n", s, r, t, p);
622
623#ifdef DEBUG
624 GV_OBJ_EXT("Text", pov, span->str);
625 gvprintf(job, "sphere{<0, 0, 0>, 2\ntranslate<%f, %f, %f>\n"
626 "pigment{color Red}\nno_shadow\n}\n", x, y, z - 1);
627#else
628 gvputs(job, pov);
629#endif
630
631 free(pov);
632 free(r);
633 free(p);
634 free(t);
635 free(s);
636}
637
638static void pov_ellipse(GVJ_t * job, pointf * A, int filled)
639{
640 char *pov, *s, *r, *t, *p;
641 float cx, cy, rx, ry, w;
642
643 gvputs(job, "//*** ellipse\n");
644 z = layerz - 6;
645
646 // A[0] center, A[1] corner of ellipse
647 cx = (A[0].x + job->translation.x) * job->scale.x;
648 cy = (A[0].y + job->translation.y) * job->scale.y;
649 rx = (A[1].x - A[0].x) * job->scale.x;
650 ry = (A[1].y - A[0].y) * job->scale.y;
651 w = job->obj->penwidth / (rx + ry) / 2.0 * 5;
652
653 //draw rim (torus)
654 s = el(job, POV_SCALE3, rx, (rx + ry) / 4.0, ry);
655 r = el(job, POV_ROTATE, 90.0, 0.0, (float)job->rotation);
656 t = el(job, POV_TRANSLATE, cx, cy, z);
657 p = pov_color_as_str(job, job->obj->pencolor, 0.0);
658
659 pov = el(job, POV_TORUS " %s %s %s %s" END, 1.0, w, //radius, size of ring
660 s, r, t, p);
661
662#ifdef DEBUG
663 GV_OBJ_EXT("Torus", pov, "");
664 gvprintf(job, "sphere{<0, 0, 0>, 2\ntranslate<%f, %f, %f>\n"
665 "pigment{color Green}\nno_shadow\n}\n", cx, cy, z - 1);
666#else
667 gvputs(job, pov);
668#endif
669
670 free(s);
671 free(r);
672 free(t);
673 free(p);
674 free(pov);
675
676 //backgroud of ellipse if filled
677 if (filled) {
678 s = el(job, POV_SCALE3, rx, ry, 1.0);
679 r = el(job, POV_ROTATE, 0.0, 0.0, (float)job->rotation);
680 t = el(job, POV_TRANSLATE, cx, cy, z);
681 p = pov_color_as_str(job, job->obj->fillcolor, 0.0);
682
683 pov = el(job, POV_SPHERE " %s %s %s %s" END,
684 0.0, 0.0, 0.0, s, r, t, p);
685
686 gvputs(job, pov);
687
688 free(s);
689 free(r);
690 free(t);
691 free(p);
692 free(pov);
693 }
694}
695
696static void pov_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
697 int arrow_at_end, int filled)
698{
699 int i;
700 char *v, *x;
701 char *pov, *s, *r, *t, *p;
702
703 gvputs(job, "//*** bezier\n");
704 z = layerz - 4;
705
706 s = el(job, POV_SCALE3, job->scale.x, job->scale.y, 1.0);
707 r = el(job, POV_ROTATE, 0.0, 0.0, (float)job->rotation);
708 t = el(job, POV_TRANSLATE, 0.0, 0.0, z - 2);
709 p = pov_color_as_str(job, job->obj->fillcolor, 0.0);
710
711 pov = el(job, POV_SPHERE_SWEEP, "b_spline", n + 2);
712
713 for (i = 0; i < n; i++) {
714 v = el(job, POV_VECTOR3 ", %.3f\n", A[i].x + job->translation.x, A[i].y + job->translation.y, 0.0, job->obj->penwidth); //z coordinate, thickness
715 x = el(job, "%s %s", pov, v); //catenate pov & vector v
716 free(v);
717 free(pov);
718 pov = x;
719
720 //TODO: we currently just use the start and end points of the curve as
721 //control points but we should use center of nodes
722 if (i == 0 || i == n - 1) {
723 v = el(job, POV_VECTOR3 ", %.3f\n", A[i].x + job->translation.x, A[i].y + job->translation.y, 0.0, job->obj->penwidth); //z coordinate, thickness
724 x = el(job, "%s %s", pov, v); //catenate pov & vector v
725 free(v);
726 free(pov);
727 pov = x;
728 }
729#ifdef DEBUG
730 gvprintf(job, "sphere{<0, 0, 0>, 2\ntranslate<%f, %f, %f>\n"
731 "pigment{color Yellow}\nno_shadow\n}\n",
732 (A[i].x + job->translation.x) * job->scale.x,
733 (A[i].y + job->translation.y) * job->scale.y, z - 2);
734#endif
735 }
736 x = el(job, " tolerance 0.01\n %s %s %s %s" END, s, r, t,
737 p);
738 pov = el(job, "%s%s", pov, x); //catenate pov & end str
739 free(x);
740
741 gvputs(job, pov);
742
743 free(s);
744 free(r);
745 free(t);
746 free(p);
747 free(pov);
748}
749
750static void pov_polygon(GVJ_t * job, pointf * A, int n, int filled)
751{
752 char *pov, *s, *r, *t, *p, *v, *x;
753 int i;
754
755 gvputs(job, "//*** polygon\n");
756 z = layerz - 2;
757
758 s = el(job, POV_SCALE3, job->scale.x, job->scale.y, 1.0);
759 r = el(job, POV_ROTATE, 0.0, 0.0, (float)job->rotation);
760 t = el(job, POV_TRANSLATE, 0.0, 0.0, z - 2);
761 p = pov_color_as_str(job, job->obj->pencolor, 0.0);
762
763 pov = el(job, POV_SPHERE_SWEEP, "linear_spline", n + 1);
764
765 for (i = 0; i < n; i++) {
766 v = el(job, POV_VECTOR3 ", %.3f\n", A[i].x + job->translation.x, A[i].y + job->translation.y, 0.0, job->obj->penwidth); //z coordinate, thickness
767 x = el(job, "%s %s", pov, v); //catenate pov & vector v
768 free(v);
769 free(pov);
770 pov = x;
771 }
772
773 //close polygon, add starting point as final point^
774 v = el(job, POV_VECTOR3 ", %.3f\n", A[0].x + job->translation.x, A[0].y + job->translation.y, 0.0, job->obj->penwidth); //z coordinate, thickness
775
776 x = el(job, "%s %s", pov, v); //catenate pov & vector v
777 free(v);
778 free(pov);
779 pov = x;
780
781 x = el(job, " tolerance 0.1\n %s %s %s %s" END, s, r, t, p);
782 pov = el(job, "%s%s", pov, x); //catenate pov & end str
783 free(x);
784
785 gvputs(job, pov);
786
787 free(s);
788 free(r);
789 free(t);
790 free(p);
791 free(pov);
792
793 //create fill background
794 if (filled) {
795 s = el(job, POV_SCALE3, job->scale.x, job->scale.y, 1.0);
796 r = el(job, POV_ROTATE, 0.0, 0.0, (float)job->rotation);
797 t = el(job, POV_TRANSLATE, 0.0, 0.0, z - 2);
798 p = pov_color_as_str(job, job->obj->fillcolor, 0.25);
799
800 pov = el(job, POV_POLYGON, n);
801
802 for (i = 0; i < n; i++) {
803 //create on z = 0 plane, then translate to real z pos
804 v = el(job, POV_VECTOR3,
805 A[i].x + job->translation.x,
806 A[i].y + job->translation.y, 0.0);
807 x = el(job, "%s\n %s", pov, v); //catenate pov & vector v
808 free(v);
809 free(pov);
810 pov = x;
811 }
812 x = el(job, "\n %s %s %s %s" END, s, r, t, p);
813 pov = el(job, "%s%s", pov, x); //catenate pov & end str
814 free(x);
815
816 gvputs(job, pov);
817
818 free(s);
819 free(r);
820 free(t);
821 free(p);
822 free(pov);
823 }
824}
825
826static void pov_polyline(GVJ_t * job, pointf * A, int n)
827{
828 char *pov, *s, *r, *t, *p, *v, *x;
829 int i;
830
831 gvputs(job, "//*** polyline\n");
832 z = layerz - 6;
833
834 s = el(job, POV_SCALE3, job->scale.x, job->scale.y, 1.0);
835 r = el(job, POV_ROTATE, 0.0, 0.0, (float)job->rotation);
836 t = el(job, POV_TRANSLATE, 0.0, 0.0, z);
837 p = pov_color_as_str(job, job->obj->pencolor, 0.0);
838
839 pov = el(job, POV_SPHERE_SWEEP, "linear_spline", n);
840
841 for (i = 0; i < n; i++) {
842 v = el(job, POV_VECTOR3 ", %.3f\n", A[i].x + job->translation.x, A[i].y + job->translation.y, 0.0, job->obj->penwidth); //z coordinate, thickness
843 x = el(job, "%s %s", pov, v); //catenate pov & vector v
844 free(v);
845 free(pov);
846 pov = x;
847 }
848
849 x = el(job, " tolerance 0.01\n %s %s %s %s" END, s, r, t, p);
850 pov = el(job, "%s%s", pov, x); //catenate pov & end str
851 free(x);
852
853 gvputs(job, pov);
854
855 free(s);
856 free(r);
857 free(t);
858 free(p);
859 free(pov);
860}
861
862gvrender_engine_t pov_engine = {
863 pov_begin_job,
864 0, /* pov_end_job */
865 pov_begin_graph,
866 pov_end_graph,
867 pov_begin_layer,
868 pov_end_layer,
869 pov_begin_page,
870 pov_end_page,
871 pov_begin_cluster,
872 pov_end_cluster,
873 0, /* pov_begin_nodes */
874 0, /* pov_end_nodes */
875 0, /* pov_begin_edges */
876 0, /* pov_end_edges */
877 pov_begin_node,
878 pov_end_node,
879 pov_begin_edge,
880 pov_end_edge,
881 0, /* pov_begin_anchor */
882 0, /* pov_end_anchor */
883 0, /* pov_begin_label */
884 0, /* pov_end_label */
885 pov_textspan,
886 0, /* pov_resolve_color */
887 pov_ellipse,
888 pov_polygon,
889 pov_bezier,
890 pov_polyline,
891 pov_comment,
892 0, /* pov_library_shape */
893};
894
895gvrender_features_t render_features_pov = {
896 /* flags */
897 GVDEVICE_DOES_LAYERS
898 | GVRENDER_DOES_MAP_RECTANGLE
899 | GVRENDER_DOES_MAP_CIRCLE
900 | GVRENDER_DOES_MAP_POLYGON
901 | GVRENDER_DOES_MAP_ELLIPSE
902 | GVRENDER_DOES_MAP_BSPLINE
903 | GVRENDER_NO_WHITE_BG
904 | GVRENDER_DOES_TRANSFORM
905 | GVRENDER_DOES_Z | GVRENDER_DOES_MAP_BSPLINE,
906 4.0, /* default pad - graph units */
907 pov_knowncolors, /* knowncolors */
908 sizeof(pov_knowncolors) / sizeof(char *), /* strings in knowncolors */
909 RENDERER_COLOR_TYPE /* set renderer color type */
910};
911
912gvdevice_features_t device_features_pov = {
913 GVDEVICE_DOES_TRUECOLOR, /* flags */
914 {0.0, 0.0}, /* default margin - points */
915 {0.0, 0.0}, /* default page width, height - points */
916 {DPI, DPI}, /* default dpi */
917};
918
919gvplugin_installed_t gvrender_pov_types[] = {
920#ifdef HAVE_VSNPRINTF
921 {FORMAT_POV, "pov", 1, &pov_engine, &render_features_pov},
922#endif
923 {0, NULL, 0, NULL, NULL}
924};
925
926gvplugin_installed_t gvdevice_pov_types[] = {
927#ifdef HAVE_VSNPRINTF
928 {FORMAT_POV, "pov:pov", 1, NULL, &device_features_pov},
929#endif
930 {0, NULL, 0, NULL, NULL}
931};
932
933