48#define BEZIERSUBDIVISION 10
60 double HeadHt, TailHt;
64static void vrml_begin_job(
GVJ_t *job) {
68static 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) {
161 pen = pencolor = color_index(im, obj->
pencolor);
164 for (i = 0; i < 10; i++)
165 dashstyle[i] = pencolor;
168 gdImageSetStyle(im, dashstyle, 20);
171 for (i = 0; i < 2; i++)
172 dashstyle[i] = pencolor;
175 gdImageSetStyle(im, dashstyle, 12);
181 gdImageSetThickness(im, width);
184 gdImagePtr
const brush = gdImageCreate(width, width);
185 gdImagePaletteCopy(brush, im);
186 gdImageFilledRectangle(brush, 0, 0, width - 1, width - 1, pencolor);
187 gdImageSetBrush(im, brush);
189 pen = gdStyledBrushed;
192 gdImageDestroy(brush);
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),
388 return (fstz + sndz) / 2.0;
391 const double len =
DIST(fst, snd);
392 const double d =
DIST(p1, fst) /
len;
393 return fstz + d * (sndz - fstz);
400 const double w =
wind(
A[0],
A[1],
A[2]);
407static int straight(
pointf *
A,
size_t n) {
408 if (n != 4)
return 0;
409 return collinear(
A) && collinear(
A + 1);
417 double delx, dely, delz;
423 state->EdgeLen = sqrt(delx*delx + dely*dely + delz*delz);
426 state->CylHt = state->EdgeLen - d0 - d1;
427 state->TailHt = state->HeadHt = 0;
429 state->IsSegment = 1;
430 gvputs(job,
"Transform {\n"
433 " geometry Cylinder {\n"
434 " bottom FALSE top FALSE\n");
436 gvputs(job,
" appearance Appearance {\n"
437 " material Material {\n"
438 " ambientIntensity 0.33\n");
439 gvprintf(job,
" diffuseColor %.3f %.3f %.3f\n",
461#define GETZ(jp,op,p,e) (nearTail(jp,p,e)?op->tail_z:op->head_z)
463static void vrml_bezier(
GVJ_t *job,
pointf *
A,
size_t n,
int filled) {
475 fstz = state->Fstz = obj->
tail_z;
476 sndz = state->Sndz = obj->
head_z;
477 if (straight(
A, n)) {
482 gvputs(job,
"Shape { geometry Extrusion {\n"
485 for (
size_t i = 0; i + 3 < n; i += 3) {
487 for (
size_t j = 1; j <= 3; j++)
492 interpolate_zcoord(job, p1,
A[0], fstz,
A[n - 1], sndz));
496 gvprintf(job,
" crossSection [ %.3f %.3f, %.3f %.3f, %.3f %.3f, %.3f %.3f ]\n",
501 gvprintf(job,
" appearance DEF E%d Appearance {\n",
AGSEQ(e));
502 gvputs(job,
" material Material {\n"
503 " ambientIntensity 0.33\n");
504 gvprintf(job,
" diffuseColor %.3f %.3f %.3f\n",
522 p0.
x = (
A[0].x +
A[2].x)/2.0;
523 p0.
y = (
A[0].y +
A[2].y)/2.0;
524 rad =
DIST(
A[0],
A[2])/2.0;
527 y = (state->CylHt + ht)/2.0;
529 gvputs(job,
"Transform {\n");
530 if (nearTail (job,
A[1], e)) {
532 gvprintf(job,
" translation 0 %.3f 0\n", -y);
537 gvprintf(job,
" translation 0 %.3f 0\n", y);
539 gvputs(job,
" children [\n"
541 gvprintf(job,
" geometry Cone {bottomRadius %.3f height %.3f }\n",
543 gvputs(job,
" appearance Appearance {\n"
544 " material Material {\n"
545 " ambientIntensity 0.33\n");
546 gvprintf(job,
" diffuseColor %.3f %.3f %.3f\n",
557static void vrml_polygon(
GVJ_t *job,
pointf *
A,
size_t np,
int filled) {
570 gvprintf(job,
" Background { skyColor %.3f %.3f %.3f }\n",
574 state->Saw_skycolor =
true;
580 pen = set_penstyle(job, state->im);
582 for (
size_t i = 0; i < np; i++) {
583 mp = vrml_node_point(job, n,
A[i]);
587 assert(np <= INT_MAX);
589 gdImageFilledPolygon(state->im,
points, (
int)np, color_index(state->im, obj->
fillcolor));
590 gdImagePolygon(state->im,
points, (
int)np, pen);
594 " appearance Appearance {\n"
595 " material Material {\n"
596 " ambientIntensity 0.33\n"
597 " diffuseColor 1 1 1\n"
599 gvprintf(job,
" texture ImageTexture { url \"node%d.png\" }\n",
AGSEQ(n));
601 " geometry Extrusion {\n"
603 for (
size_t i = 0; i < np; i++) {
611 gvprintf(job,
" spine [ %.5g %.5g %.5g, %.5g %.5g %.5g ]\n",
620 static atomic_flag flag;
621 if (!atomic_flag_test_and_set(&flag)) {
623 "vrml_polygon: non-triangle arrowheads not supported - ignoring\n");
626 if (state->IsSegment) {
627 doArrowhead (job,
A);
631 for (
size_t i = 0; i < np; i++) {
640 atan2((
A[0].y +
A[2].y) / 2.0 -
A[1].y,
641 (
A[0].x +
A[2].x) / 2.0 -
A[1].x) +
M_PI / 2.0;
643 z = GETZ(job,obj,p,e);
646 gvputs(job,
"Transform {\n");
647 gvprintf(job,
" translation %.3f %.3f %.3f\n", p.
x, p.
y,
z);
648 gvputs(job,
" children [\n"
650 gvprintf(job,
" rotation 0 0 1 %.3f\n", theta);
651 gvputs(job,
" children [\n"
653 gvprintf(job,
" geometry Cone {bottomRadius %.3f height %.3f }\n",
668static void doSphere(
GVJ_t *job,
pointf p,
double z,
double rx) {
671 gvputs(job,
"Transform {\n");
672 gvprintf(job,
" translation %.3f %.3f %.3f\n", p.
x, p.
y,
z);
673 gvprintf(job,
" scale %.3f %.3f %.3f\n", rx, rx, rx);
674 gvputs(job,
" children [\n"
678 " geometry Sphere { radius 1.0 }\n"
679 " appearance Appearance {\n"
680 " material Material {\n"
681 " ambientIntensity 0.33\n");
682 gvprintf(job,
" diffuseColor %.3f %.3f %.3f\n",
695static void vrml_ellipse(
GVJ_t * job,
pointf *
A,
int filled)
708 rx =
A[1].x -
A[0].x;
709 ry =
A[1].y -
A[0].y;
718 doSphere(job,
A[0],
z, rx);
721 pen = set_penstyle(job, state->im);
723 npf = vrml_node_point(job, n,
A[0]);
724 nqf = vrml_node_point(job, n,
A[1]);
732 gdImageFilledEllipse(state->im, np.
x, np.
y,
dx,
dy, color_index(state->im, obj->
fillcolor));
733 gdImageArc(state->im, np.
x, np.
y,
dx,
dy, 0, 360, pen);
735 gvputs(job,
"Transform {\n");
736 gvprintf(job,
" translation %.3f %.3f %.3f\n",
A[0].x,
A[0].y,
z);
737 gvprintf(job,
" scale %.3f %.3f 1\n", rx, ry);
738 gvputs(job,
" children [\n"
740 " rotation 1 0 0 1.57\n"
743 " geometry Cylinder { side FALSE }\n"
744 " appearance Appearance {\n"
745 " material Material {\n"
746 " ambientIntensity 0.33\n"
747 " diffuseColor 1 1 1\n"
749 gvprintf(job,
" texture ImageTexture { url \"node%d.png\" }\n",
AGSEQ(n));
759 z = GETZ(job,obj,
A[0],e);
761 gvputs(job,
"Transform {\n");
762 gvprintf(job,
" translation %.3f %.3f %.3f\n",
A[0].x,
A[0].y,
z);
763 gvputs(job,
" children [\n"
765 gvprintf(job,
" geometry Sphere {radius %.3f }\n", rx);
828 {FORMAT_VRML,
"vrml", 1, &vrml_engine, &render_features_vrml},
835 {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.
#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
arithmetic overflow helpers
static bool fdiv_overflow(double n, double d, double *res)
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