Code

a couple of trivial %d -> %u changes.
[inkscape.git] / src / extension / internal / pov-out.cpp
index 8e224b4dcad5eedaab80fc5eb39c20f8c1be1908..6dd62206c20402ce101af71d7315ff91637ced89 100644 (file)
@@ -9,9 +9,9 @@
  *      http://www.povray.org
  *
  * Authors:
- *   Bob Jamison <ishmalius@gmail.com>
+ *   Bob Jamison <ishmal@inkscape.org>
  *
- * Copyright (C) 2004-2007 Authors
+ * Copyright (C) 2004-2008 Authors
  *
  * Released under GNU GPL, read the file 'COPYING' for more information
  */
@@ -32,6 +32,7 @@
 
 #include <string>
 #include <stdio.h>
+#include <stdarg.h>
 
 
 namespace Inkscape
@@ -41,7 +42,13 @@ namespace Extension
 namespace Internal
 {
 
-typedef std::string String;
+
+
+
+//########################################################################
+//# U T I L I T Y
+//########################################################################
+
 
 
 /**
@@ -63,30 +70,6 @@ findElementsByTagName(std::vector<Inkscape::XML::Node *> &results,
 }
 
 
-/**
- * used for saving information about shapes
- */
-class PovShapeInfo
-{
-public:
-    PovShapeInfo()
-        {}
-    PovShapeInfo(const PovShapeInfo &other)
-        { assign(other); }
-    PovShapeInfo operator=(const PovShapeInfo &other)
-        { assign(other); return *this; }
-    virtual ~PovShapeInfo()
-        {}
-    String id;
-    String color;
-
-private:
-    void assign(const PovShapeInfo &other)
-        {
-        id    = other.id;
-        color = other.color;
-        }
-};
 
 
 
@@ -104,153 +87,181 @@ effective_opacity(SPItem const *item)
 }
 
 
+
+
+
 //########################################################################
 //# OUTPUT FORMATTING
 //########################################################################
 
-static const char *formatDouble(gchar *sbuffer, double d)
-{
-    return (const char *)g_ascii_formatd(sbuffer,
-                G_ASCII_DTOSTR_BUF_SIZE, "%.8g", (gdouble)d);
 
+/**
+ * We want to control floating output format
+ */
+static PovOutput::String dstr(double d)
+{
+    char dbuf[G_ASCII_DTOSTR_BUF_SIZE+1];
+    g_ascii_formatd(dbuf, G_ASCII_DTOSTR_BUF_SIZE,
+                  "%.8f", (gdouble)d);
+    PovOutput::String s = dbuf;
+    return s;
 }
 
 
+
+
 /**
- * Not-threadsafe version
+ *  Output data to the buffer, printf()-style
  */
-static char _dstr_buf[G_ASCII_DTOSTR_BUF_SIZE+1];
-
-static const char *dstr(double d)
+void PovOutput::out(const char *fmt, ...)
 {
-    return formatDouble(_dstr_buf, d);
+    va_list args;
+    va_start(args, fmt);
+    gchar *output = g_strdup_vprintf(fmt, args);
+    va_end(args);
+    outbuf.append(output);
+    g_free(output);
 }
 
 
 
 
-static String vec2Str(double a, double b)
+
+/**
+ *  Output a 2d vector
+ */
+void PovOutput::vec2(double a, double b)
 {
-    String str;
-    str.append("<");
-    str.append(dstr(a));
-    str.append(", ");
-    str.append(dstr(b));
-    str.append(">");
-    return str;
+    out("<%s, %s>", dstr(a).c_str(), dstr(b).c_str());
 }
 
-/*
-static String vec3Str(double a, double b, double c)
+
+
+/**
+ * Output a 3d vector
+ */
+void PovOutput::vec3(double a, double b, double c)
 {
-    String str;
-    str.append("<");
-    str.append(dstr(a));
-    str.append(", ");
-    str.append(dstr(b));
-    str.append(", ");
-    str.append(dstr(c));
-    str.append(">");
-    return str;
+    out("<%s, %s, %s>", dstr(a).c_str(), dstr(b).c_str(), dstr(c).c_str());
 }
-*/
 
-static String vec4Str(double a, double b, double c, double d)
+
+
+/**
+ *  Output a v4d ector
+ */
+void PovOutput::vec4(double a, double b, double c, double d)
 {
-    String str;
-    str.append("<");
-    str.append(dstr(a));
-    str.append(", ");
-    str.append(dstr(b));
-    str.append(", ");
-    str.append(dstr(c));
-    str.append(", ");
-    str.append(dstr(d));
-    str.append(">");
-    return str;
+    out("<%s, %s, %s, %s>", dstr(a).c_str(), dstr(b).c_str(),
+                dstr(c).c_str(), dstr(d).c_str());
 }
 
 
-static String formatRgbf(double r, double g, double b, double f)
+
+/**
+ *  Output an rgbf color vector
+ */
+void PovOutput::rgbf(double r, double g, double b, double f)
 {
     //"rgbf < %1.3f, %1.3f, %1.3f %1.3f>"
-    String str;
-    str.append("rgbf ");
-    str.append(vec4Str(r, g, b, f));
-    return str;
+    out("rgbf ");
+    vec4(r, g, b, f);
 }
 
-static String formatSeg(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
+ */
+void PovOutput::segment(int segNr,
+                        double startX,     double startY,
+                        double startCtrlX, double startCtrlY,
+                        double endCtrlX,   double endCtrlY,
+                        double endX,       double endY)
 {
     //"    /*%4d*/ <%f, %f>, <%f, %f>, <%f,%f>, <%f,%f>"
-    String str;
-    char buf[32];
-    snprintf(buf, 31, "    /*%4d*/ ", segNr);
-    str.append(buf);
-    str.append(vec2Str(a0, a1));
-    str.append(", ");
-    str.append(vec2Str(b0, b1));
-    str.append(", ");
-    str.append(vec2Str(c0, c1));
-    str.append(", ");
-    str.append(vec2Str(d0, d1));
-    return str;
+    out("    /*%4d*/ ", segNr);
+    vec2(startX,     startY);
+    out(", ");
+    vec2(startCtrlX, startCtrlY);
+    out(", ");
+    vec2(endCtrlX,   endCtrlY);
+    out(", ");
+    vec2(endX,       endY);
 }
 
 
 
 
 
+/**
+ * Output the file header
+ */
+void PovOutput::doHeader()
+{
+    time_t tim = time(NULL);
+    out("/*###################################################################\n");
+    out("### This PovRay document was generated by Inkscape\n");
+    out("### http://www.inkscape.org\n");
+    out("### Created: %s", ctime(&tim));
+    out("### Version: %s\n", VERSION);
+    out("#####################################################################\n");
+    out("### NOTES:\n");
+    out("### ============\n");
+    out("### POVRay information can be found at\n");
+    out("### http://www.povray.org\n");
+    out("###\n");
+    out("### The 'AllShapes' objects at the bottom are provided as a\n");
+    out("### preview of how the output would look in a trace.  However,\n");
+    out("### the main intent of this file is to provide the individual\n");
+    out("### shapes for inclusion in a POV project.\n");
+    out("###\n");
+    out("### For an example of how to use this file, look at\n");
+    out("### share/examples/istest.pov\n");
+    out("###\n");
+    out("### If you have any problems with this output, please see the\n");
+    out("### Inkscape project at http://www.inkscape.org, or visit\n");
+    out("### the #inkscape channel on irc.freenode.net . \n");
+    out("###\n");
+    out("###################################################################*/\n");
+    out("\n\n");
+    out("/*###################################################################\n");
+    out("##   Exports in this file\n");
+    out("##==========================\n");
+    out("##    Shapes   : %d\n", nrShapes);
+    out("##    Segments : %d\n", nrSegments);
+    out("##    Nodes    : %d\n", nrNodes);
+    out("###################################################################*/\n");
+    out("\n\n\n");
+}
 
-//########################################################################
-//# M A I N    O U T P U T
-//########################################################################
 
 
 /**
- * Saves the <paths> of an Inkscape SVG file as PovRay spline definitions
-*/
-void
-PovOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *uri)
+ *  Output the file footer
+ */
+void PovOutput::doTail()
+{
+    out("\n\n");
+    out("/*###################################################################\n");
+    out("### E N D    F I L E\n");
+    out("###################################################################*/\n");
+    out("\n\n");
+}
+
+
+
+/**
+ *  Output the curve data to buffer
+ */
+void PovOutput::doCurves(SPDocument *doc)
 {
     std::vector<Inkscape::XML::Node *>results;
     //findElementsByTagName(results, SP_ACTIVE_DOCUMENT->rroot, "path");
-    findElementsByTagName(results, SP_ACTIVE_DOCUMENT->rroot, NULL);//Check all nodes
+    findElementsByTagName(results, SP_ACTIVE_DOCUMENT->rroot, NULL);
     if (results.size() == 0)
         return;
 
-    Inkscape::IO::dump_fopen_call(uri, "L");
-    FILE *f = Inkscape::IO::fopen_utf8name(uri, "w");
-    if (!f)
-        return;
-
-    time_t tim = time(NULL);
-    fprintf(f, "/*###################################################################\n");
-    fprintf(f, "### This PovRay document was generated by Inkscape\n");
-    fprintf(f, "### http://www.inkscape.org\n");
-    fprintf(f, "### Created: %s", ctime(&tim));
-    fprintf(f, "### Version: %s\n", VERSION);
-    fprintf(f, "#####################################################################\n");
-    fprintf(f, "### NOTES:\n");
-    fprintf(f, "### ============\n");
-    fprintf(f, "### POVRay information can be found at\n");
-    fprintf(f, "### http://www.povray.org\n");
-    fprintf(f, "###\n");
-    fprintf(f, "### The 'AllShapes' objects at the bottom are provided as a\n");
-    fprintf(f, "### preview of how the output would look in a trace.  However,\n");
-    fprintf(f, "### the main intent of this file is to provide the individual\n");
-    fprintf(f, "### shapes for inclusion in a POV project.\n");
-    fprintf(f, "###\n");
-    fprintf(f, "### For an example of how to use this file, look at\n");
-    fprintf(f, "### share/examples/istest.pov\n");
-    fprintf(f, "####################################################################*/\n\n\n");
-
-    //A list for saving information about the shapes
-    std::vector<PovShapeInfo>povShapes;
-
     double bignum = 1000000.0;
     double minx  =  bignum;
     double maxx  = -bignum;
@@ -283,8 +294,10 @@ PovOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *
 
         SPShape *shape = SP_SHAPE(reprobj);
         SPCurve *curve = shape->curve;
-        if (sp_curve_empty(curve))
+        if (curve->is_empty())
             continue;
+            
+        nrShapes++;
 
         PovShapeInfo shapeInfo;
         shapeInfo.id    = id;
@@ -294,7 +307,7 @@ PovOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *
         SPStyle *style = SP_OBJECT_STYLE(shape);
         /* fixme: Handle other fill types, even if this means translating gradients to a single
            flat colour. */
-        if (style && (style->fill.type == SP_PAINT_TYPE_COLOR))
+        if (style && (style->fill.isColor()))
             {
             // see color.h for how to parse SPColor
             float rgb[3];
@@ -303,7 +316,12 @@ PovOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *
                                       * effective_opacity(shape) );
             //gchar *str = g_strdup_printf("rgbf < %1.3f, %1.3f, %1.3f %1.3f>",
             //                             rgb[0], rgb[1], rgb[2], 1.0 - dopacity);
-            shapeInfo.color += formatRgbf(rgb[0], rgb[1], rgb[2], 1.0 - dopacity);
+            String rgbf = "rgbf <";
+            rgbf.append(dstr(rgb[0]));         rgbf.append(", ");
+            rgbf.append(dstr(rgb[1]));         rgbf.append(", ");
+            rgbf.append(dstr(rgb[2]));         rgbf.append(", ");
+            rgbf.append(dstr(1.0 - dopacity)); rgbf.append(">");
+            shapeInfo.color += rgbf;
             }
 
         povShapes.push_back(shapeInfo); //passed all tests.  save the info
@@ -312,7 +330,7 @@ PovOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *
 
         //Count the NR_CURVETOs/LINETOs
         int segmentCount=0;
-        NArtBpath *bp = SP_CURVE_BPATH(curve);
+        NArtBpath const *bp = SP_CURVE_BPATH(curve);
         for (int curveNr=0 ; curveNr<curveLength ; curveNr++, bp++)
             if (bp->code == NR_CURVETO || bp->code == NR_LINETO)
                 segmentCount++;
@@ -324,21 +342,25 @@ PovOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *
         double lastx  = 0.0;
         double lasty  = 0.0;
 
-        fprintf(f, "/*###################################################\n");
-        fprintf(f, "### PRISM:  %s\n", id.c_str());
-        fprintf(f, "###################################################*/\n");
-        fprintf(f, "#declare %s = prism {\n", id.c_str());
-        fprintf(f, "    linear_sweep\n");
-        fprintf(f, "    bezier_spline\n");
-        fprintf(f, "    1.0, //top\n");
-        fprintf(f, "    0.0, //bottom\n");
-        fprintf(f, "    %d, //nr points\n", segmentCount * 4);
+        out("/*###################################################\n");
+        out("### PRISM:  %s\n", id.c_str());
+        out("###################################################*/\n");
+        out("#declare %s = prism {\n", id.c_str());
+        out("    linear_sweep\n");
+        out("    bezier_spline\n");
+        out("    1.0, //top\n");
+        out("    0.0, //bottom\n");
+        out("    %d //nr points\n", segmentCount * 4);
         int segmentNr = 0;
         bp = SP_CURVE_BPATH(curve);
+        
+        nrSegments += curveLength;
+
         for (int curveNr=0 ; curveNr < curveLength ; curveNr++)
             {
             using NR::X;
             using NR::Y;
+            //transform points.  note overloaded '*'
             NR::Point const p1(bp->c(1) * tf);
             NR::Point const p2(bp->c(2) * tf);
             NR::Point const p3(bp->c(3) * tf);
@@ -358,14 +380,14 @@ PovOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *
                     {
                     //fprintf(f, "    /*%4d*/ <%f, %f>, <%f, %f>, <%f,%f>, <%f,%f>",
                     //        segmentNr++, lastx, lasty, x1, y1, x2, y2, x3, y3);
-                    String seg = formatSeg(segmentNr++,
-                               lastx, lasty, x1, y1, x2, y2, x3, y3);
-                    fprintf(f, "%s", seg.c_str());
+                    segment(segmentNr++,
+                            lastx, lasty, x1, y1, x2, y2, x3, y3);
+                    nrNodes += 8;
 
                     if (segmentNr < segmentCount)
-                        fprintf(f, ",\n");
+                        out(",\n");
                     else
-                        fprintf(f, "\n");
+                        out("\n");
 
                     if (lastx < cminx)
                         cminx = lastx;
@@ -379,16 +401,18 @@ PovOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *
                     }
                 case NR_LINETO:
                     {
+                    //NOTE: we need to carefully handle line->curve and curve->line
+                    //    transitions.
                     //fprintf(f, "    /*%4d*/ <%f, %f>, <%f, %f>, <%f,%f>, <%f,%f>",
                     //        segmentNr++, lastx, lasty, lastx, lasty, x3, y3, x3, y3);
-                    String seg = formatSeg(segmentNr++,
-                               lastx, lasty, lastx, lasty, x3, y3, x3, y3);
-                    fprintf(f, "%s", seg.c_str());
+                    segment(segmentNr++,
+                            lastx, lasty, lastx, lasty, x3, y3, x3, y3);
+                    nrNodes += 8;
 
                     if (segmentNr < segmentCount)
-                        fprintf(f, ",\n");
+                        out(",\n");
                     else
-                        fprintf(f, "\n");
+                        out("\n");
 
                     //fprintf(f, "lineto\n");
                     if (lastx < cminx)
@@ -411,25 +435,26 @@ PovOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *
             lasty = y3;
             bp++;
             }
-        fprintf(f, "}\n");
+        out("}\n");
 
 
+        //# prefix for following declarations
            char *pfx = (char *)id.c_str();
 
-        fprintf(f, "#declare %s_MIN_X    = %s;\n", pfx, dstr(cminx));
-        fprintf(f, "#declare %s_CENTER_X = %s;\n", pfx, dstr((cmaxx+cminx)/2.0));
-        fprintf(f, "#declare %s_MAX_X    = %s;\n", pfx, dstr(cmaxx));
-        fprintf(f, "#declare %s_WIDTH    = %s;\n", pfx, dstr(cmaxx-cminx));
-        fprintf(f, "#declare %s_MIN_Y    = %s;\n", pfx, dstr(cminy));
-        fprintf(f, "#declare %s_CENTER_Y = %s;\n", pfx, dstr((cmaxy+cminy)/2.0));
-        fprintf(f, "#declare %s_MAX_Y    = %s;\n", pfx, dstr(cmaxy));
-        fprintf(f, "#declare %s_HEIGHT   = %s;\n", pfx, dstr(cmaxy-cminy));
+        out("#declare %s_MIN_X    = %s;\n", pfx, dstr(cminx).c_str());
+        out("#declare %s_CENTER_X = %s;\n", pfx, dstr((cmaxx+cminx)/2.0).c_str());
+        out("#declare %s_MAX_X    = %s;\n", pfx, dstr(cmaxx).c_str());
+        out("#declare %s_WIDTH    = %s;\n", pfx, dstr(cmaxx-cminx).c_str());
+        out("#declare %s_MIN_Y    = %s;\n", pfx, dstr(cminy).c_str());
+        out("#declare %s_CENTER_Y = %s;\n", pfx, dstr((cmaxy+cminy)/2.0).c_str());
+        out("#declare %s_MAX_Y    = %s;\n", pfx, dstr(cmaxy).c_str());
+        out("#declare %s_HEIGHT   = %s;\n", pfx, dstr(cmaxy-cminy).c_str());
         if (shapeInfo.color.length()>0)
-            fprintf(f, "#declare %s_COLOR    = %s;\n",
+            out("#declare %s_COLOR    = %s;\n",
                     pfx, shapeInfo.color.c_str());
-        fprintf(f, "/*###################################################\n");
-        fprintf(f, "### end %s\n", id.c_str());
-        fprintf(f, "###################################################*/\n\n\n\n");
+        out("/*###################################################\n");
+        out("### end %s\n", id.c_str());
+        out("###################################################*/\n\n\n\n");
         if (cminx < minx)
             minx = cminx;
         if (cmaxx > maxx)
@@ -448,84 +473,143 @@ PovOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *
         {
         String id = "AllShapes";
         char *pfx = (char *)id.c_str();
-        fprintf(f, "/*###################################################\n");
-        fprintf(f, "### UNION OF ALL SHAPES IN DOCUMENT\n");
-        fprintf(f, "###################################################*/\n");
-        fprintf(f, "\n\n");
-        fprintf(f, "/**\n");
-        fprintf(f, " * Allow the user to redefine the finish{}\n");
-        fprintf(f, " * by declaring it before #including this file\n");
-        fprintf(f, " */\n");
-        fprintf(f, "#ifndef (%s_Finish)\n", pfx);
-        fprintf(f, "#declare %s_Finish = finish {\n", pfx);
-        fprintf(f, "    phong 0.5\n");
-        fprintf(f, "    reflection 0.3\n");
-        fprintf(f, "    specular 0.5\n");
-        fprintf(f, "}\n");
-        fprintf(f, "#end\n");
-        fprintf(f, "\n\n");
-        fprintf(f, "#declare %s = union {\n", id.c_str());
+        out("/*###################################################\n");
+        out("### UNION OF ALL SHAPES IN DOCUMENT\n");
+        out("###################################################*/\n");
+        out("\n\n");
+        out("/**\n");
+        out(" * Allow the user to redefine the finish{}\n");
+        out(" * by declaring it before #including this file\n");
+        out(" */\n");
+        out("#ifndef (%s_Finish)\n", pfx);
+        out("#declare %s_Finish = finish {\n", pfx);
+        out("    phong 0.5\n");
+        out("    reflection 0.3\n");
+        out("    specular 0.5\n");
+        out("}\n");
+        out("#end\n");
+        out("\n\n");
+        out("#declare %s = union {\n", id.c_str());
         for (unsigned i = 0 ; i < povShapes.size() ; i++)
             {
-            fprintf(f, "    object { %s\n", povShapes[i].id.c_str());
-            fprintf(f, "        texture { \n");
+            out("    object { %s\n", povShapes[i].id.c_str());
+            out("        texture { \n");
             if (povShapes[i].color.length()>0)
-                fprintf(f, "            pigment { %s }\n", povShapes[i].color.c_str());
+                out("            pigment { %s }\n", povShapes[i].color.c_str());
             else
-                fprintf(f, "            pigment { rgb <0,0,0> }\n");
-            fprintf(f, "            finish { %s_Finish }\n", pfx);
-            fprintf(f, "            } \n");
-            fprintf(f, "        } \n");
+                out("            pigment { rgb <0,0,0> }\n");
+            out("            finish { %s_Finish }\n", pfx);
+            out("            } \n");
+            out("        } \n");
             }
-        fprintf(f, "}\n\n\n\n");
+        out("}\n\n\n\n");
 
 
         double zinc   = 0.2 / (double)povShapes.size();
-        fprintf(f, "/*#### Same union, but with Z-diffs (actually Y in pov) ####*/\n");
-        fprintf(f, "\n\n");
-        fprintf(f, "/**\n");
-        fprintf(f, " * Allow the user to redefine the Z-Increment\n");
-        fprintf(f, " */\n");
-        fprintf(f, "#ifndef (AllShapes_Z_Increment)\n");
-        fprintf(f, "#declare AllShapes_Z_Increment = %s;\n", dstr(zinc));
-        fprintf(f, "#end\n");
-        fprintf(f, "\n");
-        fprintf(f, "#declare AllShapes_Z_Scale = 1.0;\n");
-        fprintf(f, "\n\n");
-        fprintf(f, "#declare %s_Z = union {\n", pfx);
+        out("/*#### Same union, but with Z-diffs (actually Y in pov) ####*/\n");
+        out("\n\n");
+        out("/**\n");
+        out(" * Allow the user to redefine the Z-Increment\n");
+        out(" */\n");
+        out("#ifndef (AllShapes_Z_Increment)\n");
+        out("#declare AllShapes_Z_Increment = %s;\n", dstr(zinc).c_str());
+        out("#end\n");
+        out("\n");
+        out("#declare AllShapes_Z_Scale = 1.0;\n");
+        out("\n\n");
+        out("#declare %s_Z = union {\n", pfx);
 
         for (unsigned i = 0 ; i < povShapes.size() ; i++)
             {
-            fprintf(f, "    object { %s\n", povShapes[i].id.c_str());
-            fprintf(f, "        texture { \n");
+            out("    object { %s\n", povShapes[i].id.c_str());
+            out("        texture { \n");
             if (povShapes[i].color.length()>0)
-                fprintf(f, "            pigment { %s }\n", povShapes[i].color.c_str());
+                out("            pigment { %s }\n", povShapes[i].color.c_str());
             else
-                fprintf(f, "            pigment { rgb <0,0,0> }\n");
-            fprintf(f, "            finish { %s_Finish }\n", pfx);
-            fprintf(f, "            } \n");
-            fprintf(f, "        scale <1, %s_Z_Scale, 1>\n", pfx);
-            fprintf(f, "        } \n");
-            fprintf(f, "#declare %s_Z_Scale = %s_Z_Scale + %s_Z_Increment;\n\n",
+                out("            pigment { rgb <0,0,0> }\n");
+            out("            finish { %s_Finish }\n", pfx);
+            out("            } \n");
+            out("        scale <1, %s_Z_Scale, 1>\n", pfx);
+            out("        } \n");
+            out("#declare %s_Z_Scale = %s_Z_Scale + %s_Z_Increment;\n\n",
                     pfx, pfx, pfx);
             }
 
-        fprintf(f, "}\n");
-
-        fprintf(f, "#declare %s_MIN_X    = %s;\n", pfx, dstr(minx));
-        fprintf(f, "#declare %s_CENTER_X = %s;\n", pfx, dstr((maxx+minx)/2.0));
-        fprintf(f, "#declare %s_MAX_X    = %s;\n", pfx, dstr(maxx));
-        fprintf(f, "#declare %s_WIDTH    = %s;\n", pfx, dstr(maxx-minx));
-        fprintf(f, "#declare %s_MIN_Y    = %s;\n", pfx, dstr(miny));
-        fprintf(f, "#declare %s_CENTER_Y = %s;\n", pfx, dstr((maxy+miny)/2.0));
-        fprintf(f, "#declare %s_MAX_Y    = %s;\n", pfx, dstr(maxy));
-        fprintf(f, "#declare %s_HEIGHT   = %s;\n", pfx, dstr(maxy-miny));
-        fprintf(f, "/*##############################################\n");
-        fprintf(f, "### end %s\n", id.c_str());
-        fprintf(f, "##############################################*/\n\n\n\n");
+        out("}\n");
+
+        out("#declare %s_MIN_X    = %s;\n", pfx, dstr(minx).c_str());
+        out("#declare %s_CENTER_X = %s;\n", pfx, dstr((maxx+minx)/2.0).c_str());
+        out("#declare %s_MAX_X    = %s;\n", pfx, dstr(maxx).c_str());
+        out("#declare %s_WIDTH    = %s;\n", pfx, dstr(maxx-minx).c_str());
+        out("#declare %s_MIN_Y    = %s;\n", pfx, dstr(miny).c_str());
+        out("#declare %s_CENTER_Y = %s;\n", pfx, dstr((maxy+miny)/2.0).c_str());
+        out("#declare %s_MAX_Y    = %s;\n", pfx, dstr(maxy).c_str());
+        out("#declare %s_HEIGHT   = %s;\n", pfx, dstr(maxy-miny).c_str());
+        out("/*##############################################\n");
+        out("### end %s\n", id.c_str());
+        out("##############################################*/\n");
+        out("\n\n");
         }
 
-    //All done
+}
+
+
+
+
+//########################################################################
+//# M A I N    O U T P U T
+//########################################################################
+
+
+
+/**
+ *  Set values back to initial state
+ */
+void PovOutput::reset()
+{
+    nrNodes    = 0;
+    nrSegments = 0;
+    nrShapes   = 0;
+    outbuf.clear();
+    povShapes.clear();
+}
+
+
+
+/**
+ * Saves the <paths> of an Inkscape SVG file as PovRay spline definitions
+ */
+void PovOutput::saveDocument(SPDocument *doc, gchar const *uri)
+{
+    reset();
+
+    //###### SAVE IN POV FORMAT TO BUFFER
+    //# Lets do the curves first, to get the stats
+    doCurves(doc);
+    String curveBuf = outbuf;
+    outbuf.clear();
+
+    doHeader();
+    
+    outbuf.append(curveBuf);
+    
+    doTail();
+
+
+
+
+    //###### WRITE TO FILE
+    Inkscape::IO::dump_fopen_call(uri, "L");
+    FILE *f = Inkscape::IO::fopen_utf8name(uri, "w");
+    if (!f)
+        return;
+
+    for (String::iterator iter = outbuf.begin() ; iter!=outbuf.end(); iter++)
+        {
+        int ch = *iter;
+        fputc(ch, f);
+        }
+        
     fclose(f);
 }
 
@@ -542,6 +626,18 @@ PovOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *
 
 
 
+/**
+ * API call to save document
+*/
+void
+PovOutput::save(Inkscape::Extension::Output *mod,
+                        SPDocument *doc, gchar const *uri)
+{
+    saveDocument(doc, uri);
+}
+
+
+
 /**
  * Make sure that we are in the database
  */
@@ -566,7 +662,7 @@ void
 PovOutput::init()
 {
     Inkscape::Extension::build_from_mem(
-        "<inkscape-extension>\n"
+        "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
             "<name>" N_("PovRay Output") "</name>\n"
             "<id>org.inkscape.output.pov</id>\n"
             "<output>\n"
@@ -583,9 +679,9 @@ PovOutput::init()
 
 
 
-}  //namespace Internal
-}  //namespace Extension
-}  //namespace Inkscape
+}  // namespace Internal
+}  // namespace Extension
+}  // namespace Inkscape
 
 
 /*