Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
pov-out.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * A simple utility for exporting Inkscape svg Shapes as PovRay bezier
4 * prisms. Note that this is output-only, and would thus seem to be
5 * better placed as an 'export' rather than 'output'. However, Export
6 * handles all or partial documents, while this outputs ALL shapes in
7 * the current SVG document.
8 *
9 * For information on the PovRay file format, see:
10 * http://www.povray.org
11 *
12 * Authors:
13 * Bob Jamison <ishmal@inkscape.org>
14 * Abhishek Sharma
15 *
16 * Copyright (C) 2004-2008 Authors
17 *
18 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
19 */
20
21#include "pov-out.h"
22#include <inkscape.h>
23#include <inkscape-version.h>
24#include <display/curve.h>
25#include <extension/system.h>
26#include <2geom/pathvector.h>
27#include <2geom/rect.h>
28#include <2geom/curves.h>
29#include "helper/geom.h"
30#include "helper/geom-curves.h"
31#include <io/sys.h>
32
33#include "object/sp-root.h"
34#include "object/sp-path.h"
35#include "style.h"
36
37#include <string>
38#include <cstdio>
39#include <cstdarg>
40#include "document.h"
41#include "extension/extension.h"
42#include "util/safe-printf.h"
43
44
45namespace Inkscape
46{
47namespace Extension
48{
49namespace Internal
50{
51
52
53//########################################################################
54//# M E S S A G E S
55//########################################################################
56
57static void err(const char *fmt, ...)
58{
59 va_list args;
60 g_log(nullptr, G_LOG_LEVEL_WARNING, "Pov-out err: ");
61 va_start(args, fmt);
62 g_logv(nullptr, G_LOG_LEVEL_WARNING, fmt, args);
63 va_end(args);
64 g_log(nullptr, G_LOG_LEVEL_WARNING, "\n");
65}
66
67
68
69
70//########################################################################
71//# U T I L I T Y
72//########################################################################
73
74
75
76static double effective_opacity(SPItem const *item)
77{
78 // TODO investigate this. The early return seems that it would abort early.
79 // Plus is will emit a warning, which may not be proper here.
80 double ret = 1.0;
81 for (SPObject const *obj = item; obj; obj = obj->parent) {
82 g_return_val_if_fail(obj->style, ret);
83 ret *= SP_SCALE24_TO_FLOAT(obj->style->opacity.value);
84 }
85 return ret;
86}
87
88
89
90
91
92//########################################################################
93//# OUTPUT FORMATTING
94//########################################################################
95
97 outbuf (),
98 nrNodes (0),
99 nrSegments (0),
100 nrShapes (0),
101 idIndex (0),
102 minx (0),
103 miny (0),
104 maxx (0),
105 maxy (0)
106{
107}
108
112static PovOutput::String dstr(double d)
113{
114 char dbuf[G_ASCII_DTOSTR_BUF_SIZE+1];
115 g_ascii_formatd(dbuf, G_ASCII_DTOSTR_BUF_SIZE,
116 "%.8f", (gdouble)d);
117 PovOutput::String s = dbuf;
118 return s;
119}
120
121#define DSTR(d) (dstr(d).c_str())
122
123
127void PovOutput::out(const char *fmt, ...)
128{
129 va_list args;
130 va_start(args, fmt);
131 gchar *output = g_strdup_vprintf(fmt, args);
132 va_end(args);
133 outbuf.append(output);
134 g_free(output);
135}
136
137
138
139
140
144void PovOutput::vec2(double a, double b)
145{
146 out("<%s, %s>", DSTR(a), DSTR(b));
147}
148
149
150
154void PovOutput::vec3(double a, double b, double c)
155{
156 out("<%s, %s, %s>", DSTR(a), DSTR(b), DSTR(c));
157}
158
159
160
164void PovOutput::vec4(double a, double b, double c, double d)
165{
166 out("<%s, %s, %s, %s>", DSTR(a), DSTR(b), DSTR(c), DSTR(d));
167}
168
169
170
174void PovOutput::rgbf(double r, double g, double b, double f)
175{
176 //"rgbf < %1.3f, %1.3f, %1.3f %1.3f>"
177 out("rgbf ");
178 vec4(r, g, b, f);
179}
180
181
182
186void PovOutput::segment(int segNr,
187 double startX, double startY,
188 double startCtrlX, double startCtrlY,
189 double endCtrlX, double endCtrlY,
190 double endX, double endY)
191{
192 //" /*%4d*/ <%f, %f>, <%f, %f>, <%f,%f>, <%f,%f>"
193 out(" /*%4d*/ ", segNr);
194 vec2(startX, startY);
195 out(", ");
196 vec2(startCtrlX, startCtrlY);
197 out(", ");
198 vec2(endCtrlX, endCtrlY);
199 out(", ");
200 vec2(endX, endY);
201}
202
203
204
205
206
211{
212 time_t tim = time(nullptr);
213 out("/*###################################################################\n");
214 out("### This PovRay document was generated by Inkscape\n");
215 out("### http://www.inkscape.org\n");
216 out("### Created: %s", ctime(&tim));
217 out("### Version: %s\n", Inkscape::version_string);
218 out("#####################################################################\n");
219 out("### NOTES:\n");
220 out("### ============\n");
221 out("### POVRay information can be found at\n");
222 out("### http://www.povray.org\n");
223 out("###\n");
224 out("### The 'AllShapes' objects at the bottom are provided as a\n");
225 out("### preview of how the output would look in a trace. However,\n");
226 out("### the main intent of this file is to provide the individual\n");
227 out("### shapes for inclusion in a POV project.\n");
228 out("###\n");
229 out("### For an example of how to use this file, look at\n");
230 out("### share/examples/istest.pov\n");
231 out("###\n");
232 out("### If you have any problems with this output, please see the\n");
233 out("### Inkscape project at http://www.inkscape.org, or visit\n");
234 out("### the #inkscape channel on irc.freenode.net . \n");
235 out("###\n");
236 out("###################################################################*/\n");
237 out("\n\n");
238 out("/*###################################################################\n");
239 out("## Exports in this file\n");
240 out("##==========================\n");
241 out("## Shapes : %d\n", nrShapes);
242 out("## Segments : %d\n", nrSegments);
243 out("## Nodes : %d\n", nrNodes);
244 out("###################################################################*/\n");
245 out("\n\n\n");
246 return true;
247}
248
249
250
255{
256 out("\n\n");
257 out("/*###################################################################\n");
258 out("### E N D F I L E\n");
259 out("###################################################################*/\n");
260 out("\n\n");
261 return true;
262}
263
264
265
270{
271 using Geom::X;
272 using Geom::Y;
273
274 //### Get the Shape
275 if (!is<SPShape>(item))//Bulia's suggestion. Allow all shapes
276 return true;
277
278 auto shape = cast<SPShape>(item);
279 if (shape->curve()->is_empty()) {
280 return true;
281 }
282
283 nrShapes++;
284
285 PovShapeInfo shapeInfo;
286 shapeInfo.id = id;
287 shapeInfo.color = "";
288
289 //Try to get the fill color of the shape
290 SPStyle *style = shape->style;
291 /* fixme: Handle other fill types, even if this means translating gradients to a single
292 flat colour. */
293 if (style && style->fill.isColor()) {
294 auto rgba = *style->fill.getColor().converted(Colors::Space::Type::RGB);
295 rgba.addOpacity(style->fill_opacity);
296 rgba.addOpacity(effective_opacity(shape));
297 String rgbf = "rgbf <";
298 rgbf.append(dstr(rgba[0])); rgbf.append(", ");
299 rgbf.append(dstr(rgba[1])); rgbf.append(", ");
300 rgbf.append(dstr(rgba[2])); rgbf.append(", ");
301 rgbf.append(dstr(1.0 - rgba[3])); rgbf.append(">");
302 shapeInfo.color += rgbf;
303 }
304
305 povShapes.push_back(shapeInfo); //passed all tests. save the info
306
307 // convert the path to only lineto's and cubic curveto's:
309 Geom::PathVector pathv = pathv_to_linear_and_cubic_beziers(shape->curve()->get_pathvector() * tf);
310
311 /*
312 * We need to know the number of segments (NR_CURVETOs/LINETOs, including
313 * closing line segment) before we write out segment data. Since we are
314 * going to skip degenerate (zero length) paths, we need to loop over all
315 * subpaths and segments first.
316 */
317 int segmentCount = 0;
321 for (const auto & pit : pathv)
322 {
326 for (Geom::Path::const_iterator cit = pit.begin(); cit != pit.end_closed(); ++cit)
327 {
328
329 // Skip zero length segments.
330 if( !cit->isDegenerate() ) ++segmentCount;
331 }
332 }
333
334 out("/*###################################################\n");
335 out("### PRISM: %s\n", id.c_str());
336 out("###################################################*/\n");
337 out("#declare %s = prism {\n", id.c_str());
338 out(" linear_sweep\n");
339 out(" bezier_spline\n");
340 out(" 1.0, //top\n");
341 out(" 0.0, //bottom\n");
342 out(" %d //nr points\n", segmentCount * 4);
343 int segmentNr = 0;
344
345 nrSegments += segmentCount;
346
350 Geom::Rect cminmax( pathv.front().initialPoint(), pathv.front().initialPoint() );
351
352
356 for (const auto & pit : pathv)
357 {
358
359 cminmax.expandTo(pit.initialPoint());
360
364 for (Geom::Path::const_iterator cit = pit.begin(); cit != pit.end_closed(); ++cit)
365 {
366
367 // Skip zero length segments
368 if( cit->isDegenerate() )
369 continue;
370
371 if( is_straight_curve(*cit) )
372 {
373 Geom::Point p0 = cit->initialPoint();
374 Geom::Point p1 = cit->finalPoint();
375 segment(segmentNr++,
376 p0[X], p0[Y], p0[X], p0[Y], p1[X], p1[Y], p1[X], p1[Y] );
377 nrNodes += 8;
378 }
379 else if(Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit))
380 {
381 std::vector<Geom::Point> points = cubic->controlPoints();
382 Geom::Point p0 = points[0];
383 Geom::Point p1 = points[1];
384 Geom::Point p2 = points[2];
385 Geom::Point p3 = points[3];
386 segment(segmentNr++,
387 p0[X],p0[Y], p1[X],p1[Y], p2[X],p2[Y], p3[X],p3[Y]);
388 nrNodes += 8;
389 }
390 else
391 {
392 err("logical error, because pathv_to_linear_and_cubic_beziers was used");
393 return false;
394 }
395
396 if (segmentNr < segmentCount)
397 out(",\n");
398 else
399 out("\n");
400 if (segmentNr > segmentCount)
401 {
402 err("Too many segments");
403 return false;
404 }
405
406 cminmax.expandTo(cit->finalPoint());
407
408 }
409 }
410
411 out("}\n");
412
413 double cminx = cminmax.min()[X];
414 double cmaxx = cminmax.max()[X];
415 double cminy = cminmax.min()[Y];
416 double cmaxy = cminmax.max()[Y];
417
418 out("#declare %s_MIN_X = %s;\n", id.c_str(), DSTR(cminx));
419 out("#declare %s_CENTER_X = %s;\n", id.c_str(), DSTR((cmaxx+cminx)/2.0));
420 out("#declare %s_MAX_X = %s;\n", id.c_str(), DSTR(cmaxx));
421 out("#declare %s_WIDTH = %s;\n", id.c_str(), DSTR(cmaxx-cminx));
422 out("#declare %s_MIN_Y = %s;\n", id.c_str(), DSTR(cminy));
423 out("#declare %s_CENTER_Y = %s;\n", id.c_str(), DSTR((cmaxy+cminy)/2.0));
424 out("#declare %s_MAX_Y = %s;\n", id.c_str(), DSTR(cmaxy));
425 out("#declare %s_HEIGHT = %s;\n", id.c_str(), DSTR(cmaxy-cminy));
426 if (shapeInfo.color.length()>0)
427 out("#declare %s_COLOR = %s;\n",
428 id.c_str(), shapeInfo.color.c_str());
429 out("/*###################################################\n");
430 out("### end %s\n", id.c_str());
431 out("###################################################*/\n\n\n\n");
432
433 if (cminx < minx)
434 minx = cminx;
435 if (cmaxx > maxx)
436 maxx = cmaxx;
437 if (cminy < miny)
438 miny = cminy;
439 if (cmaxy > maxy)
440 maxy = cmaxy;
441
442 return true;
443}
444
449{
450 String id;
451 if (!obj->getId()) {
452 char buf[16];
453 safeprintf(buf, "id%d", idIndex++);
454 id = buf;
455 }
456 else {
457 id = obj->getId();
458 }
459
460 if (is<SPItem>(obj)) {
461 auto item = cast<SPItem>(obj);
462 if (!doCurve(item, id)) {
463 return false;
464 }
465 }
466
470 for (auto &child: obj->children) {
471 if (!doTreeRecursive(doc, &child))
472 return false;
473 }
474
475 return true;
476}
477
482{
483 double bignum = 1000000.0;
484 minx = bignum;
485 maxx = -bignum;
486 miny = bignum;
487 maxy = -bignum;
488
489 if (!doTreeRecursive(doc, doc->getRoot()))
490 return false;
491
492 //## Let's make a union of all of the Shapes
493 if (!povShapes.empty())
494 {
495 String id = "AllShapes";
496 char *pfx = (char *)id.c_str();
497 out("/*###################################################\n");
498 out("### UNION OF ALL SHAPES IN DOCUMENT\n");
499 out("###################################################*/\n");
500 out("\n\n");
501 out("/**\n");
502 out(" * Allow the user to redefine the finish{}\n");
503 out(" * by declaring it before #including this file\n");
504 out(" */\n");
505 out("#ifndef (%s_Finish)\n", pfx);
506 out("#declare %s_Finish = finish {\n", pfx);
507 out(" phong 0.5\n");
508 out(" reflection 0.3\n");
509 out(" specular 0.5\n");
510 out("}\n");
511 out("#end\n");
512 out("\n\n");
513 out("#declare %s = union {\n", id.c_str());
514 for (auto & povShape : povShapes)
515 {
516 out(" object { %s\n", povShape.id.c_str());
517 out(" texture { \n");
518 if (povShape.color.length()>0)
519 out(" pigment { %s }\n", povShape.color.c_str());
520 else
521 out(" pigment { rgb <0,0,0> }\n");
522 out(" finish { %s_Finish }\n", pfx);
523 out(" } \n");
524 out(" } \n");
525 }
526 out("}\n\n\n\n");
527
528
529 double zinc = 0.2 / (double)povShapes.size();
530 out("/*#### Same union, but with Z-diffs (actually Y in pov) ####*/\n");
531 out("\n\n");
532 out("/**\n");
533 out(" * Allow the user to redefine the Z-Increment\n");
534 out(" */\n");
535 out("#ifndef (AllShapes_Z_Increment)\n");
536 out("#declare AllShapes_Z_Increment = %s;\n", DSTR(zinc));
537 out("#end\n");
538 out("\n");
539 out("#declare AllShapes_Z_Scale = 1.0;\n");
540 out("\n\n");
541 out("#declare %s_Z = union {\n", pfx);
542
543 for (auto & povShape : povShapes)
544 {
545 out(" object { %s\n", povShape.id.c_str());
546 out(" texture { \n");
547 if (povShape.color.length()>0)
548 out(" pigment { %s }\n", povShape.color.c_str());
549 else
550 out(" pigment { rgb <0,0,0> }\n");
551 out(" finish { %s_Finish }\n", pfx);
552 out(" } \n");
553 out(" scale <1, %s_Z_Scale, 1>\n", pfx);
554 out(" } \n");
555 out("#declare %s_Z_Scale = %s_Z_Scale + %s_Z_Increment;\n\n",
556 pfx, pfx, pfx);
557 }
558
559 out("}\n");
560
561 out("#declare %s_MIN_X = %s;\n", pfx, DSTR(minx));
562 out("#declare %s_CENTER_X = %s;\n", pfx, DSTR((maxx+minx)/2.0));
563 out("#declare %s_MAX_X = %s;\n", pfx, DSTR(maxx));
564 out("#declare %s_WIDTH = %s;\n", pfx, DSTR(maxx-minx));
565 out("#declare %s_MIN_Y = %s;\n", pfx, DSTR(miny));
566 out("#declare %s_CENTER_Y = %s;\n", pfx, DSTR((maxy+miny)/2.0));
567 out("#declare %s_MAX_Y = %s;\n", pfx, DSTR(maxy));
568 out("#declare %s_HEIGHT = %s;\n", pfx, DSTR(maxy-miny));
569 out("/*##############################################\n");
570 out("### end %s\n", id.c_str());
571 out("##############################################*/\n");
572 out("\n\n");
573 }
574
575 return true;
576}
577
578
579//########################################################################
580//# M A I N O U T P U T
581//########################################################################
582
583
584
589{
590 nrNodes = 0;
591 nrSegments = 0;
592 nrShapes = 0;
593 idIndex = 0;
594 outbuf.clear();
595 povShapes.clear();
596}
597
598
599
603void PovOutput::saveDocument(SPDocument *doc, gchar const *filename_utf8)
604{
605 reset();
606
607 //###### SAVE IN POV FORMAT TO BUFFER
608 //# Lets do the curves first, to get the stats
609 if (!doTree(doc))
610 {
611 err("Could not output curves for %s", filename_utf8);
612 return;
613 }
614
615 String curveBuf = outbuf;
616 outbuf.clear();
617
618 if (!doHeader())
619 {
620 err("Could not write header for %s", filename_utf8);
621 return;
622 }
623
624 outbuf.append(curveBuf);
625
626 if (!doTail())
627 {
628 err("Could not write footer for %s", filename_utf8);
629 return;
630 }
631
632
633
634
635 //###### WRITE TO FILE
636 Inkscape::IO::dump_fopen_call(filename_utf8, "L");
637 FILE *f = Inkscape::IO::fopen_utf8name(filename_utf8, "w");
638 if (!f)
639 return;
640
641 for (String::iterator iter = outbuf.begin() ; iter!=outbuf.end(); ++iter)
642 {
643 int ch = *iter;
644 fputc(ch, f);
645 }
646
647 fclose(f);
648}
649
650
651
652
653//########################################################################
654//# EXTENSION API
655//########################################################################
656
657
658
659#include "clear-n_.h"
660
661
662
666void
668 SPDocument *doc, gchar const *filename_utf8)
669{
670 /* See comments in JavaFSOutput::save re the name `filename_utf8'. */
671 saveDocument(doc, filename_utf8);
672}
673
674
675
680{
681 /* We don't need a Key
682 if (NULL == Inkscape::Extension::db.get(SP_MODULE_KEY_OUTPUT_POV))
683 return FALSE;
684 */
685
686 return true;
687}
688
689
690
696void
698{
699 // clang-format off
701 "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
702 "<name>" N_("PovRay Output") "</name>\n"
703 "<id>org.inkscape.output.pov</id>\n"
704 "<output>\n"
705 "<extension>.pov</extension>\n"
706 "<mimetype>text/x-povray-script</mimetype>\n"
707 "<filetypename>" N_("PovRay (*.pov) (paths and shapes only)") "</filetypename>\n"
708 "<filetypetooltip>" N_("PovRay Raytracer File") "</filetypetooltip>\n"
709 "</output>\n"
710 "</inkscape-extension>",
711 std::make_unique<PovOutput>());
712 // clang-format on
713}
714
715
716
717
718
719} // namespace Internal
720} // namespace Extension
721} // namespace Inkscape
722
723
724/*
725 Local Variables:
726 mode:c++
727 c-file-style:"stroustrup"
728 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
729 indent-tabs-mode:nil
730 fill-column:99
731 End:
732*/
733// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
3x3 matrix representing an affine transformation.
Definition affine.h:70
Bezier curve with compile-time specified order.
void expandTo(CPoint const &p)
Enlarge the rectangle to contain the given point.
CPoint min() const
Get the corner of the rectangle with smallest coordinate values.
CPoint max() const
Get the corner of the rectangle with largest coordinate values.
Sequence of subpaths.
Definition pathvector.h:122
Point initialPoint() const
Get the first point in the path.
Definition path.h:705
Two-dimensional point that doubles as a vector.
Definition point.h:66
Axis aligned, non-empty rectangle.
Definition rect.h:92
The object that is the basis for the Extension system.
Definition extension.h:133
used for saving information about shapes
Definition pov-out.h:140
void vec4(double a, double b, double c, double d)
Output a 4d vector.
Definition pov-out.cpp:164
void segment(int segNr, double a0, double a1, double b0, double b1, double c0, double c1, double d0, double d1)
Output one bezier's start, start-control, end-control, and end nodes.
Definition pov-out.cpp:186
static void init()
Inkscape runtime startup call.
Definition pov-out.cpp:697
void vec3(double a, double b, double c)
Output a 3d vector.
Definition pov-out.cpp:154
void reset()
Reset variables to initial state.
Definition pov-out.cpp:588
void rgbf(double r, double g, double b, double f)
Output an rgbf color vector.
Definition pov-out.cpp:174
void saveDocument(SPDocument *doc, gchar const *filename)
Actual method to save document.
Definition pov-out.cpp:603
bool doCurve(SPItem *item, const String &id)
Output the SVG document's curve data as POV curves.
Definition pov-out.cpp:269
bool doTreeRecursive(SPDocument *doc, SPObject *obj)
Descend the svg tree recursively, translating data.
Definition pov-out.cpp:448
void out(const char *fmt,...) G_GNUC_PRINTF(2
Format text to our output buffer.
Definition pov-out.cpp:127
bool doTail()
Output the file footer.
Definition pov-out.cpp:254
void void vec2(double a, double b)
Output a 2d vector.
Definition pov-out.cpp:144
bool doTree(SPDocument *doc)
Output the curve data to buffer.
Definition pov-out.cpp:481
std::vector< PovShapeInfo > povShapes
Definition pov-out.h:162
bool check(Inkscape::Extension::Extension *module) override
Check whether we can actually output using this module.
Definition pov-out.cpp:679
Glib::ustring String
Our internal String definition.
Definition pov-out.h:52
bool doHeader()
Output the file header.
Definition pov-out.cpp:210
void save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filename) override
API call to perform the output to a file.
Definition pov-out.cpp:667
Typed SVG document implementation.
Definition document.h:101
SPRoot * getRoot()
Returns our SPRoot.
Definition document.h:200
Base class for visual SVG elements.
Definition sp-item.h:109
Geom::Affine i2dt_affine() const
Returns the transformation from item to desktop coords.
Definition sp-item.cpp:1837
SPObject is an abstract base class of all of the document nodes at the SVG document level.
Definition sp-object.h:160
char const * getId() const
Returns the objects current ID string.
SPObject * parent
Definition sp-object.h:189
ChildrenList children
Definition sp-object.h:907
An SVG style object.
Definition style.h:45
T< SPAttr::FILL, SPIPaint > fill
fill
Definition style.h:240
T< SPAttr::FILL_OPACITY, SPIScale24 > fill_opacity
fill-opacity
Definition style.h:242
A way to clear the N_ macro, which is defined as an inline function.
Include all curve types.
double c[8][4]
Inkscape::Extension::Extension: Frontend to certain, possibly pluggable, actions.
Specific curve type functions for Inkscape, not provided by lib2geom.
bool is_straight_curve(Geom::BezierCurve const &c)
Definition geom-curves.h:22
@ Y
Definition coord.h:48
@ X
Definition coord.h:48
Geom::PathVector pathv_to_linear_and_cubic_beziers(Geom::PathVector const &pathv)
Definition geom.cpp:586
Specific geometry functions for Inkscape, not provided my lib2geom.
SPItem * item
Mini static library that contains the version of Inkscape.
static void err(const char *fmt,...)
Definition pov-out.cpp:57
static PovOutput::String dstr(double d)
We want to control floating output format.
Definition pov-out.cpp:112
static double effective_opacity(SPItem const *item)
Definition pov-out.cpp:76
void build_from_mem(gchar const *buffer, std::unique_ptr< Implementation::Implementation > in_imp)
Create a module from a buffer holding an XML description.
Definition system.cpp:459
void dump_fopen_call(char const *utf8name, char const *id)
Definition sys.cpp:37
FILE * fopen_utf8name(char const *utf8name, char const *mode)
Open a file with g_fopen().
Definition sys.cpp:72
Helper class to stream background task notifications as a series of messages.
char const * version_string
full version string
PathVector - a sequence of subpaths.
int buf
Ocnode * child[8]
Definition quantize.cpp:33
Axis-aligned rectangle.
va_end(args)
int const char * fmt
Definition safe-printf.h:18
int const char va_start(args, fmt)
SPRoot: SVG <svg> implementation.
SPStyle - a style object for SPItem objects.