/*========================================================================= Program: Visualization Toolkit Module: vtkOBJExporter.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkOBJExporter.h" #include "vtkActorCollection.h" #include "vtkAssemblyNode.h" #include "vtkAssemblyPath.h" #include "vtkCellArray.h" #include "vtkDataSet.h" #include "vtkFloatArray.h" #include "vtkGeometryFilter.h" #include "vtkMapper.h" #include "vtkNew.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkPolyData.h" #include "vtkProperty.h" #include "vtkRenderWindow.h" #include "vtkRendererCollection.h" #include "vtkTransform.h" vtkStandardNewMacro(vtkOBJExporter); vtkOBJExporter::vtkOBJExporter() { this->FilePrefix = nullptr; } vtkOBJExporter::~vtkOBJExporter() { delete [] this->FilePrefix; } void vtkOBJExporter::WriteData() { vtkRenderer *ren; FILE *fpObj, *fpMtl; vtkActorCollection *ac; vtkActor *anActor, *aPart; char nameObj[2048]; char nameMtl[2048]; int idStart = 1; // make sure the user specified a filename if ( this->FilePrefix == nullptr) { vtkErrorMacro(<< "Please specify file prefix to use"); return; } // first make sure there is only one renderer in this rendering window if (this->RenderWindow->GetRenderers()->GetNumberOfItems() > 1) { vtkErrorMacro(<< "obj files only support on renderer per window."); return; } // get the renderer ren = this->RenderWindow->GetRenderers()->GetFirstRenderer(); // make sure it has at least one actor if (ren->GetActors()->GetNumberOfItems() < 1) { vtkErrorMacro(<< "no actors found for writing .obj file."); return; } // try opening the files snprintf(nameObj,sizeof(nameObj),"%s.obj",this->FilePrefix); snprintf(nameMtl,sizeof(nameMtl),"%s.mtl",this->FilePrefix); fpObj = fopen(nameObj,"w"); if (!fpObj) { vtkErrorMacro(<< "unable to open .obj files "); return; } fpMtl = fopen(nameMtl,"w"); if (!fpMtl) { fclose(fpObj); vtkErrorMacro(<< "unable to open .mtl files "); return; } // // Write header // vtkDebugMacro("Writing wavefront files"); fprintf(fpObj, "# wavefront obj file written by the visualization toolkit\n\n"); fprintf(fpObj, "mtllib %s\n\n", nameMtl); fprintf(fpMtl, "# wavefront mtl file written by the visualization toolkit\n\n"); ac = ren->GetActors(); vtkAssemblyPath *apath; vtkCollectionSimpleIterator ait; for (ac->InitTraversal(ait); (anActor = ac->GetNextActor(ait)); ) { for (anActor->InitPathTraversal(); (apath=anActor->GetNextPath()); ) { aPart=static_cast(apath->GetLastNode()->GetViewProp()); this->WriteAnActor(aPart, fpObj, fpMtl, idStart); } } fclose(fpObj); fclose(fpMtl); } void vtkOBJExporter::WriteAnActor(vtkActor *anActor, FILE *fpObj, FILE *fpMtl, int &idStart) { vtkDataSet *ds; vtkNew pd; vtkPointData *pntData; vtkPoints *points; vtkDataArray *tcoords; int i, i1, i2, idNext; vtkProperty *prop; double *tempd; double *p; vtkCellArray *cells; vtkNew trans; vtkIdType npts = 0; vtkIdType *indx = nullptr; // see if the actor has a mapper. it could be an assembly if (anActor->GetMapper() == nullptr) { return; } // write out the material properties to the mat file prop = anActor->GetProperty(); if (anActor->GetVisibility() == 0) { return; } fprintf(fpMtl,"newmtl mtl%i\n",idStart); tempd = prop->GetAmbientColor(); fprintf(fpMtl,"Ka %g %g %g\n",tempd[0], tempd[1], tempd[2]); tempd = prop->GetDiffuseColor(); fprintf(fpMtl,"Kd %g %g %g\n",tempd[0], tempd[1], tempd[2]); tempd = prop->GetSpecularColor(); fprintf(fpMtl,"Ks %g %g %g\n",tempd[0], tempd[1], tempd[2]); fprintf(fpMtl,"Ns %g\n",prop->GetSpecularPower()); fprintf(fpMtl,"Tr %g ", prop->GetOpacity()); fprintf(fpMtl,"illum 3\n\n"); // get the mappers input and matrix ds = anActor->GetMapper()->GetInput(); // see if the mapper has an input. if (ds == nullptr) { return; } anActor->GetMapper()->GetInputAlgorithm()->Update(); trans->SetMatrix(anActor->vtkProp3D::GetMatrix()); // we really want polydata if ( ds->GetDataObjectType() != VTK_POLY_DATA ) { vtkNew gf; gf->SetInputConnection( anActor->GetMapper()->GetInputConnection(0, 0)); gf->Update(); pd->DeepCopy(gf->GetOutput()); } else { pd->DeepCopy(ds); } // write out the points points = vtkPoints::New(); trans->TransformPoints(pd->GetPoints(),points); for (i = 0; i < points->GetNumberOfPoints(); i++) { p = points->GetPoint(i); fprintf (fpObj, "v %g %g %g\n", p[0], p[1], p[2]); } idNext = idStart + static_cast(points->GetNumberOfPoints()); points->Delete(); // write out the point data pntData = pd->GetPointData(); if (pntData->GetNormals()) { vtkNew normals; normals->SetNumberOfComponents(3); trans->TransformNormals(pntData->GetNormals(),normals); for (i = 0; i < normals->GetNumberOfTuples(); i++) { p = normals->GetTuple(i); fprintf (fpObj, "vn %g %g %g\n", p[0], p[1], p[2]); } } tcoords = pntData->GetTCoords(); if (tcoords) { for (i = 0; i < tcoords->GetNumberOfTuples(); i++) { p = tcoords->GetTuple(i); fprintf (fpObj, "vt %g %g\n", p[0], p[1]); } } // write out a group name and material fprintf (fpObj, "\ng grp%i\n", idStart); fprintf (fpObj, "usemtl mtl%i\n", idStart); // write out verts if any if (pd->GetNumberOfVerts() > 0) { cells = pd->GetVerts(); for (cells->InitTraversal(); cells->GetNextCell(npts,indx); ) { fprintf(fpObj,"p "); for (i = 0; i < npts; i++) { // treating vtkIdType as int fprintf(fpObj,"%i ", static_cast(indx[i])+idStart); } fprintf(fpObj,"\n"); } } // write out lines if any if (pd->GetNumberOfLines() > 0) { cells = pd->GetLines(); for (cells->InitTraversal(); cells->GetNextCell(npts,indx); ) { fprintf(fpObj,"l "); if (tcoords) { for (i = 0; i < npts; i++) { // treating vtkIdType as int fprintf(fpObj,"%i/%i ",static_cast(indx[i])+idStart, static_cast(indx[i]) + idStart); } } else { for (i = 0; i < npts; i++) { // treating vtkIdType as int fprintf(fpObj,"%i ", static_cast(indx[i])+idStart); } } fprintf(fpObj,"\n"); } } // write out polys if any if (pd->GetNumberOfPolys() > 0) { cells = pd->GetPolys(); for (cells->InitTraversal(); cells->GetNextCell(npts,indx); ) { fprintf(fpObj,"f "); for (i = 0; i < npts; i++) { if (pntData->GetNormals()) { if (tcoords) { // treating vtkIdType as int fprintf(fpObj,"%i/%i/%i ", static_cast(indx[i])+idStart, static_cast(indx[i])+ idStart, static_cast(indx[i]) + idStart); } else { // treating vtkIdType as int fprintf(fpObj,"%i//%i ",static_cast(indx[i])+idStart, static_cast(indx[i]) + idStart); } } else { if (tcoords) { // treating vtkIdType as int fprintf(fpObj,"%i/%i ", static_cast(indx[i])+idStart, static_cast(indx[i]) + idStart); } else { // treating vtkIdType as int fprintf(fpObj,"%i ", static_cast(indx[i])+idStart); } } } fprintf(fpObj,"\n"); } } // write out tstrips if any if (pd->GetNumberOfStrips() > 0) { cells = pd->GetStrips(); for (cells->InitTraversal(); cells->GetNextCell(npts,indx); ) { for (i = 2; i < npts; i++) { if (i%2 == 0) { i1 = i - 2; i2 = i - 1; } else { i1 = i - 1; i2 = i - 2; } if (pntData->GetNormals()) { if (tcoords) { // treating vtkIdType as int fprintf(fpObj,"f %i/%i/%i ", static_cast(indx[i1]) + idStart, static_cast(indx[i1]) + idStart, static_cast(indx[i1]) + idStart); fprintf(fpObj,"%i/%i/%i ", static_cast(indx[i2])+ idStart, static_cast(indx[i2]) + idStart, static_cast(indx[i2]) + idStart); fprintf(fpObj,"%i/%i/%i\n", static_cast(indx[i]) + idStart, static_cast(indx[i]) + idStart, static_cast(indx[i]) + idStart); } else { // treating vtkIdType as int fprintf(fpObj,"f %i//%i ", static_cast(indx[i1]) + idStart, static_cast(indx[i1]) + idStart); fprintf(fpObj,"%i//%i ", static_cast(indx[i2]) + idStart, static_cast(indx[i2]) + idStart); fprintf(fpObj,"%i//%i\n",static_cast(indx[i]) + idStart, static_cast(indx[i]) + idStart); } } else { if (tcoords) { // treating vtkIdType as int fprintf(fpObj,"f %i/%i ", static_cast(indx[i1]) + idStart, static_cast(indx[i1]) + idStart); fprintf(fpObj,"%i/%i ", static_cast(indx[i2]) + idStart, static_cast(indx[i2]) + idStart); fprintf(fpObj,"%i/%i\n", static_cast(indx[i]) + idStart, static_cast(indx[i]) + idStart); } else { // treating vtkIdType as int fprintf(fpObj,"f %i %i %i\n", static_cast(indx[i1]) + idStart, static_cast(indx[i2]) + idStart, static_cast(indx[i]) + idStart); } } } } } idStart = idNext; } void vtkOBJExporter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); if (this->FilePrefix) { os << indent << "FilePrefix: " << this->FilePrefix << "\n"; } else { os << indent << "FilePrefix: (null)\n"; } }