1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkPOVExporter.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 /*=========================================================================
16 
17   Program:   VTK/ParaView Los Alamos National Laboratory Modules (PVLANL)
18   Module:    vtkPOVExporter.cxx
19 
20 Copyright (c) 2007, Los Alamos National Security, LLC
21 
22 All rights reserved.
23 
24 Copyright 2007. Los Alamos National Security, LLC.
25 This software was produced under U.S. Government contract DE-AC52-06NA25396
26 for Los Alamos National Laboratory (LANL), which is operated by
27 Los Alamos National Security, LLC for the U.S. Department of Energy.
28 The U.S. Government has rights to use, reproduce, and distribute this software.
29 NEITHER THE GOVERNMENT NOR LOS ALAMOS NATIONAL SECURITY, LLC MAKES ANY WARRANTY,
30 EXPRESS OR IMPLIED, OR ASSUMES ANY LIABILITY FOR THE USE OF THIS SOFTWARE.
31 If software is modified to produce derivative works, such modified software
32 should be clearly marked, so as not to confuse it with the version available
33 from LANL.
34 
35 Additionally, redistribution and use in source and binary forms, with or
36 without modification, are permitted provided that the following conditions
37 are met:
38 -   Redistributions of source code must retain the above copyright notice,
39     this list of conditions and the following disclaimer.
40 -   Redistributions in binary form must reproduce the above copyright notice,
41     this list of conditions and the following disclaimer in the documentation
42     and/or other materials provided with the distribution.
43 -   Neither the name of Los Alamos National Security, LLC, Los Alamos National
44     Laboratory, LANL, the U.S. Government, nor the names of its contributors
45     may be used to endorse or promote products derived from this software
46     without specific prior written permission.
47 
48 THIS SOFTWARE IS PROVIDED BY LOS ALAMOS NATIONAL SECURITY, LLC AND CONTRIBUTORS
49 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
50 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 ARE DISCLAIMED. IN NO EVENT SHALL LOS ALAMOS NATIONAL SECURITY, LLC OR
52 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
53 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
54 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
55 OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
56 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
57 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
58 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
59 
60 =========================================================================*/
61 
62 #include "vtkPOVExporter.h"
63 
64 #include "vtkAssemblyPath.h"
65 #include "vtkCamera.h"
66 #include "vtkCellArray.h"
67 #include "vtkCompositeDataGeometryFilter.h"
68 #include "vtkCompositeDataSet.h"
69 #include "vtkFloatArray.h"
70 #include "vtkGeometryFilter.h"
71 #include "vtkLightCollection.h"
72 #include "vtkLight.h"
73 #include "vtkMapper.h"
74 #include "vtkMatrix4x4.h"
75 #include "vtkPointData.h"
76 #include "vtkPolyData.h"
77 #include "vtkProperty.h"
78 #include "vtkRendererCollection.h"
79 #include "vtkRenderer.h"
80 #include "vtkRenderWindow.h"
81 #include "vtkSmartPointer.h"
82 #include "vtkTexture.h"
83 #include "vtkTypeTraits.h"
84 #include "vtkUnsignedCharArray.h"
85 
86 #include <vtksys/ios/sstream>
87 
88 #include "vtkObjectFactory.h"
89 
90 vtkStandardNewMacro(vtkPOVExporter);
91 
92 //Can't use printf("%d", a_vtkIdType) because vtkIdType is not always int.
93 //This internal class holds format strings vtkPOVExporter can use instead.
94 class vtkPOVInternals
95 {
96 public:
vtkPOVInternals()97   vtkPOVInternals()
98   {
99     this->CountFormat = new char[100]; //"\t\t%d,\n"
100     strcpy(this->CountFormat, "\t\t");
101     strcat(this->CountFormat, vtkTypeTraits<vtkIdType>::ParseFormat());
102     strcat(this->CountFormat, ",\n");
103 
104     char *triFormat = new char[100]; //"%d, %d, %d"
105     strcpy(triFormat, vtkTypeTraits<vtkIdType>::ParseFormat());
106     strcat(triFormat, ", ");
107     strcat(triFormat, vtkTypeTraits<vtkIdType>::ParseFormat());
108     strcat(triFormat, ", ");
109     strcat(triFormat, vtkTypeTraits<vtkIdType>::ParseFormat());
110 
111     this->TriangleFormat1 = new char[100]; //"\t\t<%d, %d, %d>,"
112     strcpy(this->TriangleFormat1, "\t\t<");
113     strcat(this->TriangleFormat1, triFormat);
114     strcat(this->TriangleFormat1, ">,");
115 
116     this->TriangleFormat2 = new char[100]; //" %d, %d, %d,\n"
117     strcpy(this->TriangleFormat2, " ");
118     strcat(this->TriangleFormat2, triFormat);
119     strcat(this->TriangleFormat2, ",\n");
120 
121     delete[] triFormat;
122   }
123 
~vtkPOVInternals()124   ~vtkPOVInternals()
125   {
126     delete[] this->CountFormat;
127     delete[] this->TriangleFormat1;
128     delete[] this->TriangleFormat2;
129   }
130 
131   char *CountFormat;
132   char *TriangleFormat1;
133   char *TriangleFormat2;
134 };
135 
136 #define VTKPOV_CNTFMT this->Internals->CountFormat
137 #define VTKPOV_TRIFMT1 this->Internals->TriangleFormat1
138 #define VTKPOV_TRIFMT2 this->Internals->TriangleFormat2
139 
140 //============================================================================
vtkPOVExporter()141 vtkPOVExporter::vtkPOVExporter()
142 {
143   this->FileName = NULL;
144   this->FilePtr = NULL;
145   this->Internals = new vtkPOVInternals;
146 }
147 
~vtkPOVExporter()148 vtkPOVExporter::~vtkPOVExporter()
149 {
150   delete[] this->FileName;
151   delete this->Internals;
152 }
153 
WriteData()154 void vtkPOVExporter::WriteData()
155 {
156   // make sure user specified a filename
157   if (this->FileName == NULL)
158     {
159     vtkErrorMacro(<< "Please specify file name to create");
160     return;
161     }
162 
163   //get the renderer
164   vtkRenderer *renderer =
165     this->RenderWindow->GetRenderers()->GetFirstRenderer();
166   // make sure it has at least one actor
167   if (renderer->GetActors()->GetNumberOfItems() < 1)
168     {
169     vtkErrorMacro(<< "no actors found for writing .pov file.");
170     return;
171     }
172 
173   // try opening the file
174   this->FilePtr = fopen(this->FileName, "w");
175   if (this->FilePtr == NULL)
176     {
177     vtkErrorMacro (<< "Cannot open " << this->FileName);
178     return;
179     }
180 
181 
182   // write header
183   this->WriteHeader(renderer);
184 
185   // write camera
186   this->WriteCamera(renderer->GetActiveCamera());
187 
188   // write lights
189   vtkLightCollection *lc = renderer->GetLights();
190   vtkCollectionSimpleIterator sit;
191   lc->InitTraversal(sit);
192   if (lc->GetNextLight(sit) == NULL)
193     {
194     vtkWarningMacro(<< "No light defined, creating one at camera position");
195     renderer->CreateLight();
196     }
197   vtkLight *light;
198   for (lc->InitTraversal(sit); (light = lc->GetNextLight(sit));)
199     {
200     if (light->GetSwitch())
201       {
202       this->WriteLight(light);
203       }
204     }
205 
206   // write actors
207   vtkActorCollection *ac = renderer->GetActors();
208   vtkAssemblyPath *apath;
209   vtkCollectionSimpleIterator ait;
210   vtkActor *anActor, *aPart;
211   for (ac->InitTraversal(ait); (anActor = ac->GetNextActor(ait)); )
212     {
213     for (anActor->InitPathTraversal(); (apath = anActor->GetNextPath()); )
214       {
215       aPart = static_cast<vtkActor *>(apath->GetLastNode()->GetViewProp());
216       this->WriteActor(aPart);
217       }
218     }
219 
220   fclose(this->FilePtr);
221 }
222 
WriteHeader(vtkRenderer * renderer)223 void vtkPOVExporter::WriteHeader(vtkRenderer *renderer)
224 {
225   fprintf(this->FilePtr, "// POVRay file exported by vtkPOVExporter\n");
226   fprintf(this->FilePtr, "//\n");
227 
228   // width and height of output image,
229   //and other default command line args to POVRay
230   int *size = renderer->GetSize();
231   fprintf(this->FilePtr, "// +W%d +H%d\n\n", size[0], size[1]);
232 
233   // global settings
234   fprintf(this->FilePtr, "global_settings {\n");
235   fprintf(this->FilePtr, "\tambient_light color rgb <1.0, 1.0, 1.0>\n");
236   fprintf(this->FilePtr, "\tassumed_gamma 2\n");
237   fprintf(this->FilePtr, "}\n\n");
238 
239   // background
240   double *color = renderer->GetBackground();
241   fprintf(this->FilePtr, "background { color rgb <%f, %f, %f>}\n\n",
242           color[0], color[1], color[2]);
243 }
244 
WriteCamera(vtkCamera * camera)245 void vtkPOVExporter::WriteCamera(vtkCamera *camera)
246 {
247   fprintf(this->FilePtr, "camera {\n");
248   if (camera->GetParallelProjection())
249     {
250     fprintf(this->FilePtr, "\torthographic\n");
251     }
252   else
253     {
254     fprintf(this->FilePtr, "\tperspective\n");
255     }
256 
257   double *position = camera->GetPosition();
258   fprintf(this->FilePtr, "\tlocation <%f, %f, %f>\n",
259           position[0], position[1], position[2]);
260 
261   double *up = camera->GetViewUp();
262   // the camera up vector is called "sky" in POVRay
263   fprintf(this->FilePtr, "\tsky <%f, %f, %f>\n", up[0], up[1], up[2]);
264 
265   // make POVRay to use left handed system to right handed
266   // TODO: aspect ratio
267   fprintf(this->FilePtr, "\tright <-1, 0, 0>\n");
268   //fprintf(this->FilePtr, "\tup <-1, 0, 0>\n");
269 
270   fprintf(this->FilePtr, "\tangle %f\n", camera->GetViewAngle());
271 
272   double *focal = camera->GetFocalPoint();
273   fprintf(this->FilePtr, "\tlook_at <%f, %f, %f>\n",
274           focal[0], focal[1], focal[2]);
275 
276   fprintf(this->FilePtr, "}\n\n");
277 }
278 
WriteLight(vtkLight * light)279 void vtkPOVExporter::WriteLight(vtkLight *light)
280 {
281   fprintf(this->FilePtr, "light_source {\n");
282 
283   double *position = light->GetPosition();
284   fprintf(this->FilePtr, "\t<%f, %f, %f>\n",
285           position[0], position[1], position[2]);
286 
287   double *color = light->GetDiffuseColor();
288   fprintf(this->FilePtr, "\tcolor <%f, %f, %f>*%f\n",
289           color[0], color[1], color[2],
290           light->GetIntensity());
291 
292   if (light->GetPositional())
293     {
294     fprintf(this->FilePtr, "\tspotlight\n");
295     fprintf(this->FilePtr, "\tradius %f\n", light->GetConeAngle());
296     fprintf(this->FilePtr, "\tfalloff %f\n", light->GetExponent());
297     }
298   else
299     {
300     fprintf(this->FilePtr, "\tparallel\n");
301     }
302   double *focal    = light->GetFocalPoint();
303   fprintf(this->FilePtr, "\tpoint_at <%f, %f, %f>\n",
304           focal[0], focal[1], focal[2]);
305 
306   fprintf(this->FilePtr, "}\n\n");
307 }
308 
WriteActor(vtkActor * actor)309 void vtkPOVExporter::WriteActor(vtkActor *actor)
310 {
311   if (actor->GetMapper() == NULL)
312     {
313     return;
314     }
315 
316   // write geometry, first ask the pipeline to update data
317   vtkDataSet *dataset = NULL;
318   vtkSmartPointer<vtkDataSet> tempDS;
319 
320   vtkDataObject* dObj = actor->GetMapper()->GetInputDataObject(0, 0);
321   vtkCompositeDataSet* cd = vtkCompositeDataSet::SafeDownCast(dObj);
322   if (cd)
323     {
324     vtkCompositeDataGeometryFilter* gf = vtkCompositeDataGeometryFilter::New();
325     gf->SetInputConnection(actor->GetMapper()->GetInputConnection(0, 0));
326     gf->Update();
327     tempDS = gf->GetOutput();
328     gf->Delete();
329 
330     dataset = tempDS;
331     }
332   else
333     {
334     dataset = actor->GetMapper()->GetInput();
335     }
336 
337   if (dataset == NULL)
338     {
339     return;
340     }
341   actor->GetMapper()->GetInputAlgorithm()->Update();
342 
343   // convert non polygon data to polygon data if needed
344   vtkGeometryFilter *geometryFilter = NULL;
345   vtkPolyData *polys = NULL;;
346   if (dataset->GetDataObjectType() != VTK_POLY_DATA)
347     {
348     geometryFilter = vtkGeometryFilter::New();
349     geometryFilter->SetInputConnection(
350       actor->GetMapper()->GetInputConnection(0, 0));
351     geometryFilter->Update();
352     polys = geometryFilter->GetOutput();
353     }
354   else
355     {
356     polys = static_cast<vtkPolyData *>(dataset);
357     }
358 
359   // we only export Polygons and Triangle Strips
360   if ((polys->GetNumberOfPolys() == 0) && (polys->GetNumberOfStrips() == 0))
361     {
362       return;
363     }
364 
365   // write point coordinates
366   vtkPoints *points = polys->GetPoints();
367 
368   // we use mesh2 since it maps better to how VTK stores
369   // polygons/triangle strips
370   fprintf(this->FilePtr, "mesh2 {\n");
371 
372   fprintf(this->FilePtr, "\tvertex_vectors {\n");
373   fprintf(this->FilePtr, VTKPOV_CNTFMT, points->GetNumberOfPoints());
374   for (vtkIdType i = 0; i < points->GetNumberOfPoints(); i++)
375     {
376     double *pos = points->GetPoint(i);
377     fprintf(this->FilePtr, "\t\t<%f, %f, %f>,\n", pos[0], pos[1], pos[2]);
378     }
379   fprintf(this->FilePtr, "\t}\n");
380 
381   // write vertex normal
382   vtkPointData *pointData = polys->GetPointData();
383   if (pointData->GetNormals())
384     {
385     vtkDataArray *normals = pointData->GetNormals();
386     fprintf(this->FilePtr, "\tnormal_vectors {\n");
387     fprintf(this->FilePtr, VTKPOV_CNTFMT, normals->GetNumberOfTuples());
388     for (vtkIdType i = 0; i < normals->GetNumberOfTuples(); i++)
389       {
390       double *normal = normals->GetTuple(i);
391       fprintf(this->FilePtr, "\t\t<%f, %f, %f>,\n",
392               normal[0], normal[1], normal[2]);
393       }
394     fprintf(this->FilePtr, "\t}\n");
395     }
396 
397   // TODO: write texture coordinates (uv vectors)
398 
399   // write vertex texture, ask mapper to generate color for each vertex if
400   // the scalar data visibility is on
401   bool scalar_visible = false;
402   if (actor->GetMapper()->GetScalarVisibility())
403     {
404     vtkUnsignedCharArray *color_array = actor->GetMapper()->MapScalars(1.0);
405     if (color_array != NULL)
406       {
407       scalar_visible = true;
408       fprintf(this->FilePtr, "\ttexture_list {\n");
409       fprintf(this->FilePtr, VTKPOV_CNTFMT, color_array->GetNumberOfTuples());
410       for (vtkIdType i = 0; i < color_array->GetNumberOfTuples(); i++) {
411         unsigned char *color = color_array->GetPointer(4*i);
412         fprintf(this->FilePtr,
413                 "\t\ttexture { pigment {color rgbf <%f, %f, %f, %f> } },\n",
414                 color[0]/255.0,
415                 color[1]/255.0,
416                 color[2]/255.0,
417                 1.0 - color[3]/255.0);
418         }
419       fprintf(this->FilePtr, "\t}\n");
420       }
421     }
422 
423   // write polygons
424   if (polys->GetNumberOfPolys() > 0)
425     {
426     this->WritePolygons(polys, scalar_visible);
427     }
428 
429   // write triangle strips
430   if (polys->GetNumberOfStrips() > 0)
431     {
432     this->WriteTriangleStrips(polys, scalar_visible);
433     }
434 
435   // write transformation for the actor, it is column major and looks like transposed
436   vtkMatrix4x4 *matrix = actor->GetMatrix();
437   fprintf(this->FilePtr, "\tmatrix < %f, %f, %f,\n",
438           matrix->GetElement(0, 0),
439           matrix->GetElement(1, 0),
440           matrix->GetElement(2, 0));
441   fprintf(this->FilePtr, "\t\t %f, %f, %f,\n",
442           matrix->GetElement(0, 1),
443           matrix->GetElement(1, 1),
444           matrix->GetElement(2, 1));
445   fprintf(this->FilePtr, "\t\t %f, %f, %f,\n",
446           matrix->GetElement(0, 2),
447           matrix->GetElement(1, 2),
448           matrix->GetElement(2, 2));
449   fprintf(this->FilePtr, "\t\t %f, %f, %f >\n",
450           matrix->GetElement(0, 3),
451           matrix->GetElement(1, 3),
452           matrix->GetElement(2, 3));
453 
454   // write property
455   this->WriteProperty(actor->GetProperty());
456 
457   // done with this actor
458   fprintf(this->FilePtr, "}\n\n");
459 
460   if (geometryFilter)
461     {
462     geometryFilter->Delete();
463     }
464 }
465 
WritePolygons(vtkPolyData * polys,bool scalar_visible)466 void vtkPOVExporter::WritePolygons(vtkPolyData *polys, bool scalar_visible)
467 {
468   // write polygons with on the fly triangulation,
469   // assuming polygon are simple and can be triangulated into "fans"
470   vtkIdType numtriangles = 0;
471   vtkCellArray *cells = polys->GetPolys();
472   vtkIdType npts = 0, *pts = 0;
473 
474   // first pass,
475   // calculate how many triangles there will be after triangulation
476   for (cells->InitTraversal(); cells->GetNextCell(npts, pts);)
477     {
478     // the number of triangles for each polygon will be # of vertex - 2
479     numtriangles += (npts - 2);
480     }
481 
482   // second pass, triangulate and write face indices
483   fprintf(this->FilePtr, "\tface_indices {\n");
484   fprintf(this->FilePtr, VTKPOV_CNTFMT, numtriangles);
485   for (cells->InitTraversal(); cells->GetNextCell(npts, pts);)
486     {
487     vtkIdType triangle[3];
488     // the first triangle
489     triangle[0] = pts[0];
490     triangle[1] = pts[1];
491     triangle[2] = pts[2];
492 
493     fprintf(this->FilePtr, VTKPOV_TRIFMT1,
494             triangle[0], triangle[1], triangle[2]);
495     if (scalar_visible)
496       {
497       fprintf(this->FilePtr, VTKPOV_TRIFMT2,
498               triangle[0], triangle[1], triangle[2]);
499       }
500     else
501       {
502       fprintf(this->FilePtr, "\n");
503       }
504 
505   // the rest of triangles
506     for (vtkIdType i = 3; i < npts; i++)
507       {
508       triangle[1] = triangle[2];
509       triangle[2] = pts[i];
510       fprintf(this->FilePtr, VTKPOV_TRIFMT1,
511               triangle[0], triangle[1], triangle[2]);
512       if (scalar_visible)
513         {
514         fprintf(this->FilePtr, VTKPOV_TRIFMT2,
515                 triangle[0], triangle[1], triangle[2]);
516         }
517       else
518         {
519         fprintf(this->FilePtr, "\n");
520         }
521       }
522     }
523   fprintf(this->FilePtr, "\t}\n");
524 
525   // third pass, the same thing as 2nd pass but for normal_indices
526   if (polys->GetPointData()->GetNormals())
527     {
528     fprintf(this->FilePtr, "\tnormal_indices {\n");
529     fprintf(this->FilePtr, VTKPOV_CNTFMT, numtriangles);
530     for (cells->InitTraversal(); cells->GetNextCell(npts, pts);)
531       {
532       vtkIdType triangle[3];
533       // the first triangle
534       triangle[0] = pts[0];
535       triangle[1] = pts[1];
536       triangle[2] = pts[2];
537 
538       fprintf(this->FilePtr, VTKPOV_TRIFMT1,
539               triangle[0], triangle[1], triangle[2]);
540       fprintf(this->FilePtr, "\n");
541 
542       // the rest of triangles
543       for (vtkIdType i = 3; i < npts; i++)
544         {
545         triangle[1] = triangle[2];
546         triangle[2] = pts[i];
547         fprintf(this->FilePtr, VTKPOV_TRIFMT1,
548                 triangle[0], triangle[1], triangle[2]);
549         fprintf(this->FilePtr, "\n");
550         }
551       }
552     fprintf(this->FilePtr, "\t}\n");
553     }
554 
555   // TODO: 4th pass, texture indices
556 
557 }
558 
WriteTriangleStrips(vtkPolyData * polys,bool scalar_visible)559 void vtkPOVExporter::WriteTriangleStrips(
560   vtkPolyData *polys, bool scalar_visible)
561 {
562   // convert triangle strips into triangles
563   vtkIdType numtriangles = 0;
564   vtkCellArray *cells = polys->GetStrips();
565   vtkIdType npts = 0, *pts = 0;
566 
567   // first pass, calculate how many triangles there will be after conversion
568   for (cells->InitTraversal(); cells->GetNextCell(npts, pts);)
569     {
570     // the number of triangles for each polygon will be # of vertex - 2
571     numtriangles += (npts - 2);
572     }
573 
574   // second pass, convert to triangles and write face indices
575   fprintf(this->FilePtr, "\tface_indices {\n");
576   fprintf(this->FilePtr, VTKPOV_CNTFMT, numtriangles);
577   for (cells->InitTraversal(); cells->GetNextCell(npts, pts);)
578     {
579     vtkIdType triangle[3];
580     // the first triangle
581     triangle[0] = pts[0];
582     triangle[1] = pts[1];
583     triangle[2] = pts[2];
584 
585     fprintf(this->FilePtr, VTKPOV_TRIFMT1,
586             triangle[0], triangle[1], triangle[2]);
587     if (scalar_visible)
588       {
589       fprintf(this->FilePtr, VTKPOV_TRIFMT2,
590               triangle[0], triangle[1], triangle[2]);
591       }
592     else
593       {
594       fprintf(this->FilePtr, "\n");
595       }
596 
597   // the rest of triangles
598     for (vtkIdType i = 3; i < npts; i++)
599       {
600       triangle[0] = triangle[1];
601       triangle[1] = triangle[2];
602       triangle[2] = pts[i];
603       fprintf(this->FilePtr, VTKPOV_TRIFMT1,
604               triangle[0], triangle[1], triangle[2]);
605       if (scalar_visible)
606         {
607         fprintf(this->FilePtr, VTKPOV_TRIFMT2,
608                 triangle[0], triangle[1], triangle[2]);
609         }
610       else
611         {
612         fprintf(this->FilePtr, "\n");
613         }
614       }
615     }
616   fprintf(this->FilePtr, "\t}\n");
617 
618   // third pass, the same thing as 2nd pass but for normal_indices
619   if (polys->GetPointData()->GetNormals())
620     {
621     fprintf(this->FilePtr, "\tnormal_indices {\n");
622     fprintf(this->FilePtr, VTKPOV_CNTFMT, numtriangles);
623     for (cells->InitTraversal(); cells->GetNextCell(npts, pts);)
624       {
625       vtkIdType triangle[3];
626       // the first triangle
627       triangle[0] = pts[0];
628       triangle[1] = pts[1];
629       triangle[2] = pts[2];
630 
631       fprintf(this->FilePtr, VTKPOV_TRIFMT1,
632               triangle[0], triangle[1], triangle[2]);
633       fprintf(this->FilePtr, "\n");
634 
635       // the rest of triangles
636       for (vtkIdType i = 3; i < npts; i++)
637         {
638         triangle[0] = triangle[1];
639         triangle[1] = triangle[2];
640         triangle[2] = pts[i];
641         fprintf(this->FilePtr, VTKPOV_TRIFMT1,
642                 triangle[0], triangle[1], triangle[2]);
643         fprintf(this->FilePtr, "\n");
644         }
645       }
646     fprintf(this->FilePtr, "\t}\n");
647     }
648 
649   // TODO: 4th pass, texture indices
650 }
651 
WriteProperty(vtkProperty * property)652 void vtkPOVExporter::WriteProperty(vtkProperty *property)
653 {
654   fprintf(this->FilePtr, "\ttexture {\n");
655 
656   /* write color */
657   fprintf(this->FilePtr, "\t\tpigment {\n");
658   double *color   = property->GetColor();
659   fprintf(this->FilePtr, "\t\t\tcolor rgbf <%f, %f, %f %f>\n",
660           color[0], color[1], color[2], 1.0 - property->GetOpacity());
661   fprintf(this->FilePtr, "\t\t}\n");
662 
663   /* write ambient, diffuse and specular coefficients */
664   fprintf(this->FilePtr, "\t\tfinish {\n\t\t\t");
665   fprintf(this->FilePtr, "ambient %f  ", property->GetAmbient());
666   fprintf(this->FilePtr, "diffuse %f  ", property->GetDiffuse());
667   fprintf(this->FilePtr, "phong %f  ", property->GetSpecular());
668   fprintf(this->FilePtr, "phong_size %f  ", property->GetSpecularPower());
669   fprintf(this->FilePtr, "\n\t\t}\n");
670 
671   fprintf(this->FilePtr, "\t}\n");
672 }
673 
PrintSelf(ostream & os,vtkIndent indent)674 void vtkPOVExporter::PrintSelf(ostream& os, vtkIndent indent)
675 {
676   this->Superclass::PrintSelf(os, indent);
677   if (this->FileName)
678     {
679     os << indent << "FileName: " << this->FileName << "\n";
680     }
681   else
682     {
683     os << indent << "FileName: (null)\n";
684     }
685 }
686