47#define BEZIERSUBDIVISION 10
59 double HeadHt, TailHt;
63static void vrml_begin_job(
GVJ_t *job) {
67static void vrml_end_job(
GVJ_t *job) {
75static strview_t gdirname(
const char *pathname){
77 size_t last = strlen(pathname);
79 while (
last > 0 && pathname[--
last] ==
'/');
87 else if (pathname[1] ==
'/')
93 if (
last == 0 && *pathname ==
'/' && pathname[1] ==
'/')
101static char *nodefilename(
const char *filename,
node_t *n,
agxbuf *buf) {
105 dir = gdirname(filename);
112static FILE *nodefile(
const char *filename,
node_t * n)
117 rv = fopen(nodefilename(filename, n, &buf),
"wb");
145 alpha = (255 -
color.u.rgba[3]) * gdAlphaMax / 255;
147 if(
alpha == gdAlphaMax)
148 return gdImageGetTransparent(im);
150 return gdImageColorResolveAlpha(im,
157static int set_penstyle(
GVJ_t * job, gdImagePtr im, gdImagePtr brush)
162 pen = pencolor = color_index(im, obj->
pencolor);
165 for (i = 0; i < 10; i++)
166 dashstyle[i] = pencolor;
169 gdImageSetStyle(im, dashstyle, 20);
172 for (i = 0; i < 2; i++)
173 dashstyle[i] = pencolor;
176 gdImageSetStyle(im, dashstyle, 12);
182 gdImageSetThickness(im, width);
185 brush = gdImageCreate(width, width);
186 gdImagePaletteCopy(brush, im);
187 gdImageFilledRectangle(brush, 0, 0, width - 1, width - 1, pencolor);
188 gdImageSetBrush(im, brush);
190 pen = gdStyledBrushed;
199static void vrml_begin_page(
GVJ_t *job)
203 gvputs(job,
"#VRML V2.0 utf8\n");
205 state->Saw_skycolor =
false;
206 state->MinZ = DBL_MAX;
207 gvputs(job,
"Group { children [\n"
209 gvprintf(job,
" scale %.3f %.3f %.3f\n", .0278, .0278, .0278);
210 gvputs(job,
" children [\n");
213static void vrml_end_page(
GVJ_t *job)
223 z = 0.6667 * d / tan(
M_PI / 8.0) + state->MinZ;
225 if (!state->Saw_skycolor)
226 gvputs(job,
" Background { skyColor 1 1 1 }\n");
228 gvprintf(job,
" Viewpoint {position %.3f %.3f %.3f}\n",
229 state->Scale * (bb.
UR.
x + bb.
LL.
x) / 72.,
230 state->Scale * (bb.
UR.
y + bb.
LL.
y) / 72.,
231 state->Scale * 2 *
z / 72.);
235static void vrml_begin_node(
GVJ_t *job)
248 if (state->PNGfile ==
NULL) {
249 agerrorf(
"failed to open file for writing PNG node image\n");
252 const int width =
d2i((
ND_lw(n) +
ND_rw(n)) * state->Scale + 2 * NODE_PAD);
253 const int height =
d2i((
ND_ht(n) ) * state->Scale + 2 * NODE_PAD);
254 state->im = gdImageCreate(width, height);
258 gdRedMax - 1, gdGreenMax,
259 gdBlueMax, gdAlphaTransparent);
264static void vrml_end_node(
GVJ_t *job)
268 if (state->PNGfile !=
NULL) {
269 gdImagePng(state->im, state->PNGfile);
270 fclose(state->PNGfile);
272 gdImageDestroy(state->im);
277static void vrml_begin_edge(
GVJ_t *job)
283 state->IsSegment = 0;
285 gvputs(job,
" Group { children [\n");
296 const double o_x = (p0.
x + p1.
x) / 2.0;
297 const double o_y = (p0.
y + p1.
y) / 2.0;
298 const double o_z = (state->Fstz + state->Sndz) / 2;
316 acos(2 * y / state->EdgeLen) + (p0.
y > p1.
y ?
M_PI : 0);
317 if (fabs(x) < 0.0005 && fabs(
z) < 0.0005)
320 const double y0 = (state->HeadHt - state->TailHt) / 2.0;
322 gvprintf(job,
" center 0 %.3f 0\n", y0);
323 gvprintf(job,
" rotation %.3f 0 %.3f %.3f\n", -
z, x, -theta);
324 gvprintf(job,
" translation %.3f %.3f %.3f\n", o_x, o_y - y0, o_z);
328static void vrml_end_edge(
GVJ_t *job)
332 if (state->IsSegment)
333 finishSegment(job, job->
obj->
u.
e);
343 if (!obj->
u.
n || !state->im)
346 switch (span->
just) {
360 spf = vrml_node_point(job, obj->
u.
n, p);
361 epf = vrml_node_point(job, obj->
u.
n, q);
364 color_index(state->im, obj->
pencolor),
389 return (fstz + sndz) / 2.0;
390 return fstz + (sndz - fstz) * (p1.
y - fst.
y) / (snd.
y - fst.
y);
394 return fstz + d * (sndz - fstz);
413static int straight(
pointf *
A,
size_t n) {
414 if (n != 4)
return 0;
415 return collinear(
A) && collinear(
A + 1);
423 double delx, dely, delz;
429 state->EdgeLen = sqrt(delx*delx + dely*dely + delz*delz);
432 state->CylHt = state->EdgeLen - d0 - d1;
433 state->TailHt = state->HeadHt = 0;
435 state->IsSegment = 1;
436 gvputs(job,
"Transform {\n"
439 " geometry Cylinder {\n"
440 " bottom FALSE top FALSE\n");
442 gvputs(job,
" appearance Appearance {\n"
443 " material Material {\n"
444 " ambientIntensity 0.33\n");
445 gvprintf(job,
" diffuseColor %.3f %.3f %.3f\n",
468#define GETZ(jp,op,p,e) (nearTail(jp,p,e)?op->tail_z:op->head_z)
470static void vrml_bezier(
GVJ_t *job,
pointf *
A,
size_t n,
int filled) {
482 fstz = state->Fstz = obj->
tail_z;
483 sndz = state->Sndz = obj->
head_z;
484 if (straight(
A, n)) {
489 gvputs(job,
"Shape { geometry Extrusion {\n"
492 for (
size_t i = 0; i + 3 < n; i += 3) {
494 for (
size_t j = 1; j <= 3; j++)
499 interpolate_zcoord(job, p1,
A[0], fstz,
A[n - 1], sndz));
503 gvprintf(job,
" crossSection [ %.3f %.3f, %.3f %.3f, %.3f %.3f, %.3f %.3f ]\n",
508 gvprintf(job,
" appearance DEF E%d Appearance {\n",
AGSEQ(e));
509 gvputs(job,
" material Material {\n"
510 " ambientIntensity 0.33\n");
511 gvprintf(job,
" diffuseColor %.3f %.3f %.3f\n",
531 p0.
x = (
A[0].x +
A[2].x)/2.0;
532 p0.
y = (
A[0].y +
A[2].y)/2.0;
533 rad =
DIST(
A[0],
A[2])/2.0;
536 y = (state->CylHt + ht)/2.0;
538 gvputs(job,
"Transform {\n");
539 if (nearTail (job,
A[1], e)) {
541 gvprintf(job,
" translation 0 %.3f 0\n", -y);
546 gvprintf(job,
" translation 0 %.3f 0\n", y);
548 gvputs(job,
" children [\n"
550 gvprintf(job,
" geometry Cone {bottomRadius %.3f height %.3f }\n",
552 gvputs(job,
" appearance Appearance {\n"
553 " material Material {\n"
554 " ambientIntensity 0.33\n");
555 gvprintf(job,
" diffuseColor %.3f %.3f %.3f\n",
566static void vrml_polygon(
GVJ_t *job,
pointf *
A,
size_t np,
int filled) {
574 gdImagePtr brush =
NULL;
580 gvprintf(job,
" Background { skyColor %.3f %.3f %.3f }\n",
584 state->Saw_skycolor =
true;
590 pen = set_penstyle(job, state->im, brush);
592 for (
size_t i = 0; i < np; i++) {
593 mp = vrml_node_point(job, n,
A[i]);
597 assert(np <= INT_MAX);
599 gdImageFilledPolygon(state->im,
points, (
int)np, color_index(state->im, obj->
fillcolor));
600 gdImagePolygon(state->im,
points, (
int)np, pen);
603 gdImageDestroy(brush);
606 " appearance Appearance {\n"
607 " material Material {\n"
608 " ambientIntensity 0.33\n"
609 " diffuseColor 1 1 1\n"
611 gvprintf(job,
" texture ImageTexture { url \"node%d.png\" }\n",
AGSEQ(n));
613 " geometry Extrusion {\n"
615 for (
size_t i = 0; i < np; i++) {
623 gvprintf(job,
" spine [ %.5g %.5g %.5g, %.5g %.5g %.5g ]\n",
632 static atomic_flag flag;
633 if (!atomic_flag_test_and_set(&flag)) {
635 "vrml_polygon: non-triangle arrowheads not supported - ignoring\n");
638 if (state->IsSegment) {
639 doArrowhead (job,
A);
643 for (
size_t i = 0; i < np; i++) {
652 atan2((
A[0].y +
A[2].y) / 2.0 -
A[1].y,
653 (
A[0].x +
A[2].x) / 2.0 -
A[1].x) +
M_PI / 2.0;
655 z = GETZ(job,obj,p,e);
658 gvputs(job,
"Transform {\n");
659 gvprintf(job,
" translation %.3f %.3f %.3f\n", p.
x, p.
y,
z);
660 gvputs(job,
" children [\n"
662 gvprintf(job,
" rotation 0 0 1 %.3f\n", theta);
663 gvputs(job,
" children [\n"
665 gvprintf(job,
" geometry Cone {bottomRadius %.3f height %.3f }\n",
682static void doSphere(
GVJ_t *job,
pointf p,
double z,
double rx) {
685 gvputs(job,
"Transform {\n");
686 gvprintf(job,
" translation %.3f %.3f %.3f\n", p.
x, p.
y,
z);
687 gvprintf(job,
" scale %.3f %.3f %.3f\n", rx, rx, rx);
688 gvputs(job,
" children [\n"
692 " geometry Sphere { radius 1.0 }\n"
693 " appearance Appearance {\n"
694 " material Material {\n"
695 " ambientIntensity 0.33\n");
696 gvprintf(job,
" diffuseColor %.3f %.3f %.3f\n",
709static void vrml_ellipse(
GVJ_t * job,
pointf *
A,
int filled)
720 gdImagePtr brush =
NULL;
723 rx =
A[1].x -
A[0].x;
724 ry =
A[1].y -
A[0].y;
733 doSphere(job,
A[0],
z, rx);
736 pen = set_penstyle(job, state->im, brush);
738 npf = vrml_node_point(job, n,
A[0]);
739 nqf = vrml_node_point(job, n,
A[1]);
747 gdImageFilledEllipse(state->im, np.
x, np.
y,
dx,
dy, color_index(state->im, obj->
fillcolor));
748 gdImageArc(state->im, np.
x, np.
y,
dx,
dy, 0, 360, pen);
751 gdImageDestroy(brush);
753 gvputs(job,
"Transform {\n");
754 gvprintf(job,
" translation %.3f %.3f %.3f\n",
A[0].x,
A[0].y,
z);
755 gvprintf(job,
" scale %.3f %.3f 1\n", rx, ry);
756 gvputs(job,
" children [\n"
758 " rotation 1 0 0 1.57\n"
761 " geometry Cylinder { side FALSE }\n"
762 " appearance Appearance {\n"
763 " material Material {\n"
764 " ambientIntensity 0.33\n"
765 " diffuseColor 1 1 1\n"
767 gvprintf(job,
" texture ImageTexture { url \"node%d.png\" }\n",
AGSEQ(n));
777 z = GETZ(job,obj,
A[0],e);
779 gvputs(job,
"Transform {\n");
780 gvprintf(job,
" translation %.3f %.3f %.3f\n",
A[0].x,
A[0].y,
z);
781 gvputs(job,
" children [\n"
783 gvprintf(job,
" geometry Sphere {radius %.3f }\n", rx);
846 {FORMAT_VRML,
"vrml", 1, &vrml_engine, &render_features_vrml},
853 {FORMAT_VRML,
"vrml:vrml", 1,
NULL, &device_features_vrml},
static agxbuf last
last message
Dynamically expanding string buffers.
static void agxbfree(agxbuf *xb)
free any malloced resources
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
static WUR char * agxbuse(agxbuf *xb)
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
static void * gv_alloc(size_t size)
abstract graph C library, Cgraph API
pointf Bezier(const pointf *V, double t, pointf *Left, pointf *Right)
void gdgen_text(gdImagePtr im, pointf spf, pointf epf, int fontcolor, double fontsize, int fontdpi, double fontangle, char *fontname, char *str)
static double len(glCompPoint p)
void agwarningf(const char *fmt,...)
void agerrorf(const char *fmt,...)
char * agnameof(void *)
returns a string descriptor for the object.
Arithmetic helper functions.
static bool is_exactly_zero(double v)
is a value precisely 0.0?
static bool is_exactly_equal(double a, double b)
are two values precisely the same?
#define GVDEVICE_NO_WRITER
#define GVDEVICE_BINARY_FORMAT
static void color(Agraph_t *g)
pointf gvrender_ptf(GVJ_t *job, pointf p)
int gvputs(GVJ_t *job, const char *s)
void gvprintf(GVJ_t *job, const char *format,...)
static const char transparent[]
gvplugin_installed_t gvrender_vrml_types[]
gvplugin_installed_t gvdevice_vrml_types[]
textitem scanner parser str
PATHUTIL_API int wind(Ppoint_t a, Ppoint_t b, Ppoint_t c)
shape_kind shapeOf(node_t *)
const char * output_filename
size_t size
number of characters in the buffer
information the ID allocator needs to do its job
a non-owning string reference
const char * data
start of the pointed to string
size_t size
extent of the string in bytes
Non-owning string references.
static strview_t strview(const char *referent, char terminator)
create a string reference
#define BEZIERSUBDIVISION