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!
298 pigment
299 { image_map
300 { gif "image.gif"
301 map_type 1
302 }
303 }
304 */
305
306 /*
307 #declare Sphere =
308 sphere {
309 <0,0,0>, 1
310 pigment { rgb <1,0,0> }
311 }
312 #declare Min = min_extent ( Sphere );
313 #declare Max = max_extent ( Sphere );
314 object { Sphere }
315 box {
316 Min, Max
317 pigment { rgbf <1,1,1,0.5> }
318 scale<20,20,20>
319 }
320 */
321
322 /*
323 STRING functions
324
325 str( float , min_len , digits_after_dot )
326 concat( STRING , STRING , [STRING ,...])
327 chr( INT )
328 substr( STRING , INT , INT )
329 strupr( STRING )
330 strlwr( STRING )
331 vstr( vec_dimension , vec, sep_str, min_len, digits_after_dot )
332
333 examples:
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
342 typedef 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
359 static char *pov_knowncolors[] = { POV_COLORS };
360
361 static float layerz = 0;
362 static float z = 0;
363
el(GVJ_t * job,char * template,...)364 char *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
pov_color_as_str(GVJ_t * job,gvcolor_t color,float transparency)405 static 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
pov_comment(GVJ_t * job,char * str)443 static void pov_comment(GVJ_t * job, char *str)
444 {
445 gvprintf(job, "//*** comment: %s\n", str);
446 }
447
pov_begin_job(GVJ_t * job)448 static 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
pov_begin_graph(GVJ_t * job)458 static 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
pov_end_graph(GVJ_t * job)517 static void pov_end_graph(GVJ_t * job)
518 {
519 gvputs(job, "//*** end_graph\n");
520 }
521
pov_begin_layer(GVJ_t * job,char * layername,int layerNum,int numLayers)522 static 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
pov_end_layer(GVJ_t * job)529 static void pov_end_layer(GVJ_t * job)
530 {
531 gvputs(job, "//*** end_layer\n");
532 }
533
pov_begin_page(GVJ_t * job)534 static void pov_begin_page(GVJ_t * job)
535 {
536 gvputs(job, "//*** begin_page\n");
537 }
538
pov_end_page(GVJ_t * job)539 static void pov_end_page(GVJ_t * job)
540 {
541 gvputs(job, "//*** end_page\n");
542 }
543
pov_begin_cluster(GVJ_t * job)544 static void pov_begin_cluster(GVJ_t * job)
545 {
546 gvputs(job, "//*** begin_cluster\n");
547 layerz -= 2;
548 }
549
pov_end_cluster(GVJ_t * job)550 static void pov_end_cluster(GVJ_t * job)
551 {
552 gvputs(job, "//*** end_cluster\n");
553 }
554
pov_begin_node(GVJ_t * job)555 static void pov_begin_node(GVJ_t * job)
556 {
557 gvprintf(job, "//*** begin_node: %s\n", agnameof(job->obj->u.n));
558 }
559
pov_end_node(GVJ_t * job)560 static void pov_end_node(GVJ_t * job)
561 {
562 gvputs(job, "//*** end_node\n");
563 }
564
pov_begin_edge(GVJ_t * job)565 static 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
pov_end_edge(GVJ_t * job)574 static 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
pov_textspan(GVJ_t * job,pointf c,textspan_t * span)583 static 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
pov_ellipse(GVJ_t * job,pointf * A,int filled)638 static 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
pov_bezier(GVJ_t * job,pointf * A,int n,int arrow_at_start,int arrow_at_end,int filled)696 static 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
pov_polygon(GVJ_t * job,pointf * A,int n,int filled)750 static 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
pov_polyline(GVJ_t * job,pointf * A,int n)826 static 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
862 gvrender_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
895 gvrender_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
912 gvdevice_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
919 gvplugin_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
926 gvplugin_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