/*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkOBJExporter.cxx,v $ 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 "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkPolyData.h" #include "vtkProperty.h" #include "vtkRenderWindow.h" #include "vtkRendererCollection.h" #include "vtkTransform.h" vtkCxxRevisionMacro(vtkOBJExporter, "$Revision: 1.57 $"); vtkStandardNewMacro(vtkOBJExporter); vtkOBJExporter::vtkOBJExporter() { this->FilePrefix = NULL; } vtkOBJExporter::~vtkOBJExporter() { if ( this->FilePrefix ) { delete [] this->FilePrefix; } } void vtkOBJExporter::WriteData() { vtkRenderer *ren; FILE *fpObj, *fpMtl; vtkActorCollection *ac; vtkActor *anActor, *aPart; char nameObj[80]; char nameMtl[80]; int idStart = 1; // make sure the user specified a filename if ( this->FilePrefix == NULL) { 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 sprintf(nameObj,"%s.obj",this->FilePrefix); sprintf(nameMtl,"%s.mtl",this->FilePrefix); fpObj = fopen(nameObj,"w"); fpMtl = fopen(nameMtl,"w"); if (!fpObj || !fpMtl) { vtkErrorMacro(<< "unable to open .obj and .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=(vtkActor *)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; vtkPolyData *pd; vtkGeometryFilter *gf = NULL; vtkPointData *pntData; vtkPoints *points; vtkDataArray *normals = NULL; vtkDataArray *tcoords; int i, i1, i2, idNext; vtkProperty *prop; double *tempd; double *p; vtkCellArray *cells; vtkTransform *trans = vtkTransform::New(); vtkIdType npts = 0; vtkIdType *indx = 0; // see if the actor has a mapper. it could be an assembly if (anActor->GetMapper() == NULL) { return; } // write out the material properties to the mat file prop = anActor->GetProperty(); 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,"Tf %g %g %g\n",1.0 - prop->GetOpacity(), 1.0 - prop->GetOpacity(),1.0 - 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 == NULL) { return; } ds->Update(); trans->SetMatrix(anActor->vtkProp3D::GetMatrix()); // we really want polydata if ( ds->GetDataObjectType() != VTK_POLY_DATA ) { gf = vtkGeometryFilter::New(); gf->SetInput(ds); gf->Update(); pd = gf->GetOutput(); } else { pd = (vtkPolyData *)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 + (int)(points->GetNumberOfPoints()); points->Delete(); // write out the point data pntData = pd->GetPointData(); if (pntData->GetNormals()) { normals = vtkFloatArray::New(); 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 ", ((int)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 ",((int)indx[i])+idStart, ((int)indx[i]) + idStart); } } else { for (i = 0; i < npts; i++) { // treating vtkIdType as int fprintf(fpObj,"%i ", ((int)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 (normals) { if (tcoords) { // treating vtkIdType as int fprintf(fpObj,"%i/%i/%i ", ((int)indx[i])+idStart, ((int)indx[i]) + idStart, ((int)indx[i]) + idStart); } else { // treating vtkIdType as int fprintf(fpObj,"%i//%i ",((int)indx[i])+idStart, ((int)indx[i]) + idStart); } } else { if (tcoords) { // treating vtkIdType as int fprintf(fpObj,"%i/%i ", ((int)indx[i])+idStart, ((int)indx[i]) + idStart); } else { // treating vtkIdType as int fprintf(fpObj,"%i ", ((int)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) { i1 = i - 1; i2 = i - 2; } else { i1 = i - 1; i2 = i - 2; } if (normals) { if (tcoords) { // treating vtkIdType as int fprintf(fpObj,"f %i/%i/%i ", ((int)indx[i1]) + idStart, ((int)indx[i1]) + idStart, ((int)indx[i1]) + idStart); fprintf(fpObj,"%i/%i/%i ", ((int)indx[i2])+ idStart, ((int)indx[i2]) + idStart, ((int)indx[i2]) + idStart); fprintf(fpObj,"%i/%i/%i\n", ((int)indx[i]) + idStart, ((int)indx[i]) + idStart, ((int)indx[i]) + idStart); } else { // treating vtkIdType as int fprintf(fpObj,"f %i//%i ", ((int)indx[i1]) + idStart, ((int)indx[i1]) + idStart); fprintf(fpObj,"%i//%i ", ((int)indx[i2]) + idStart, ((int)indx[i2]) + idStart); fprintf(fpObj,"%i//%i\n",((int)indx[i]) + idStart, ((int)indx[i]) + idStart); } } else { if (tcoords) { // treating vtkIdType as int fprintf(fpObj,"f %i/%i ", ((int)indx[i1]) + idStart, ((int)indx[i1]) + idStart); fprintf(fpObj,"%i/%i ", ((int)indx[i2]) + idStart, ((int)indx[i2]) + idStart); fprintf(fpObj,"%i/%i\n", ((int)indx[i]) + idStart, ((int)indx[i]) + idStart); } else { // treating vtkIdType as int fprintf(fpObj,"f %i %i %i\n", ((int)indx[i1]) + idStart, ((int)indx[i2]) + idStart, ((int)indx[i]) + idStart); } } } } } idStart = idNext; trans->Delete(); if (normals) { normals->Delete(); } if (gf) { gf->Delete(); } } 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"; } }