/*========================================================================= Program: Visualization Toolkit Module: vtkX3DExporter.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen, Kristian Sons 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 "vtkX3DExporter.h" #include "vtkActor2D.h" #include "vtkActor2DCollection.h" #include "vtkAssemblyPath.h" #include "vtkCamera.h" #include "vtkCellArray.h" #include "vtkCellData.h" #include "vtkCompositeDataIterator.h" #include "vtkCompositeDataSet.h" #include "vtkGeometryFilter.h" #include "vtkImageData.h" #include "vtkInformation.h" #include "vtkLight.h" #include "vtkLightCollection.h" #include "vtkMath.h" #include "vtkNew.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkPolyData.h" #include "vtkPolyDataMapper.h" #include "vtkPolyDataMapper2D.h" #include "vtkProperty.h" #include "vtkRenderWindow.h" #include "vtkRendererCollection.h" #include "vtkSmartPointer.h" #include "vtkTextActor.h" #include "vtkTextProperty.h" #include "vtkTexture.h" #include "vtkTransform.h" #include "vtkUnsignedCharArray.h" #include "vtkX3D.h" #include "vtkX3DExporterFIWriter.h" #include "vtkX3DExporterXMLWriter.h" #include #include using namespace vtkX3D; // forward declarations static bool vtkX3DExporterWriterUsingCellColors(vtkMapper* mapper); static bool vtkX3DExporterWriterRenderFaceSet(int cellType, int representation, vtkPoints* points, vtkIdType cellOffset, vtkCellArray* cells, vtkUnsignedCharArray* colors, bool cell_colors, vtkDataArray* normals, bool cell_normals, vtkDataArray* tcoords, bool common_data_written, int index, vtkX3DExporterWriter* writer); static void vtkX3DExporterWriteData(vtkPoints* points, vtkDataArray* normals, vtkDataArray* tcoords, vtkUnsignedCharArray* colors, int index, vtkX3DExporterWriter* writer); static void vtkX3DExporterUseData( bool normals, bool tcoords, bool colors, int index, vtkX3DExporterWriter* writer); static bool vtkX3DExporterWriterRenderVerts(vtkPoints* points, vtkCellArray* cells, vtkUnsignedCharArray* colors, bool cell_colors, vtkX3DExporterWriter* writer); static bool vtkX3DExporterWriterRenderPoints( vtkPolyData* pd, vtkUnsignedCharArray* colors, bool cell_colors, vtkX3DExporterWriter* writer); //------------------------------------------------------------------------------ vtkStandardNewMacro(vtkX3DExporter); //------------------------------------------------------------------------------ vtkX3DExporter::vtkX3DExporter() { this->Speed = 4.0; this->FileName = nullptr; this->Binary = 0; this->Fastest = 0; this->WriteToOutputString = 0; this->OutputString = nullptr; this->OutputStringLength = 0; } //------------------------------------------------------------------------------ vtkX3DExporter::~vtkX3DExporter() { this->SetFileName(nullptr); delete[] this->OutputString; } //------------------------------------------------------------------------------ void vtkX3DExporter::WriteData() { vtkSmartPointer writer; vtkActorCollection* ac; vtkActor2DCollection* a2Dc; vtkActor *anActor, *aPart; vtkActor2D *anTextActor2D, *aPart2D; vtkLightCollection* lc; vtkLight* aLight; vtkCamera* cam; // make sure the user specified a FileName or FilePointer if (this->FileName == nullptr && (!this->WriteToOutputString)) { vtkErrorMacro(<< "Please specify FileName to use"); return; } // get the renderer vtkRenderer* ren = this->ActiveRenderer; if (!ren) { ren = this->RenderWindow->GetRenderers()->GetFirstRenderer(); } // make sure it has at least one actor if (ren->GetActors()->GetNumberOfItems() < 1) { vtkErrorMacro(<< "no actors found for writing X3D file."); return; } // try opening the files if (this->Binary) { vtkX3DExporterFIWriter* temp = vtkX3DExporterFIWriter::New(); temp->SetFastest(this->GetFastest()); writer.TakeReference(temp); } else { writer = vtkSmartPointer::New(); } if (this->WriteToOutputString) { if (!writer->OpenStream()) { vtkErrorMacro(<< "unable to open X3D stream"); return; } } else { if (!writer->OpenFile(this->FileName)) { vtkErrorMacro(<< "unable to open X3D file " << this->FileName); return; } } // // Write header // vtkDebugMacro("Writing X3D file"); writer->StartDocument(); writer->StartNode(X3D); writer->SetField(profile, "Immersive"); writer->SetField(vtkX3D::version, "3.0"); writer->StartNode(head); writer->StartNode(meta); writer->SetField(name, "filename"); writer->SetField(content, this->FileName ? this->FileName : "Stream"); writer->EndNode(); writer->StartNode(meta); writer->SetField(name, "generator"); writer->SetField(content, "Visualization ToolKit X3D exporter v0.9.1"); writer->EndNode(); writer->StartNode(meta); writer->SetField(name, "numberofelements"); std::ostringstream ss; ss << ren->GetActors()->GetNumberOfItems(); writer->SetField(content, ss.str().c_str()); writer->EndNode(); writer->EndNode(); // head writer->StartNode(Scene); // Start write the Background writer->StartNode(Background); writer->SetField(skyColor, SFVEC3F, ren->GetBackground()); writer->EndNode(); // End of Background // Start write the Camera cam = ren->GetActiveCamera(); writer->StartNode(Viewpoint); writer->SetField( fieldOfView, static_cast(vtkMath::RadiansFromDegrees(cam->GetViewAngle()))); writer->SetField(position, SFVEC3F, cam->GetPosition()); writer->SetField(description, "Default View"); writer->SetField(orientation, SFROTATION, cam->GetOrientationWXYZ()); writer->SetField(centerOfRotation, SFVEC3F, cam->GetFocalPoint()); writer->EndNode(); // End of Camera // do the lights first the ambient then the others writer->StartNode(NavigationInfo); writer->SetField(type, "\"EXAMINE\" \"FLY\" \"ANY\"", true); writer->SetField(speed, static_cast(this->Speed)); writer->SetField(headlight, this->HasHeadLight(ren) != 0); writer->EndNode(); writer->StartNode(DirectionalLight); writer->SetField(ambientIntensity, 1.0f); writer->SetField(intensity, 0.0f); writer->SetField(color, SFCOLOR, ren->GetAmbient()); writer->EndNode(); // label ROOT static double n[] = { 0.0, 0.0, 0.0 }; writer->StartNode(Transform); writer->SetField(DEF, "ROOT"); writer->SetField(translation, SFVEC3F, n); // make sure we have a default light // if we don't then use a headlight lc = ren->GetLights(); vtkCollectionSimpleIterator lsit; for (lc->InitTraversal(lsit); (aLight = lc->GetNextLight(lsit));) { if (!aLight->LightTypeIsHeadlight()) { this->WriteALight(aLight, writer); } } // do the actors now ac = ren->GetActors(); vtkAssemblyPath* apath; vtkCollectionSimpleIterator ait; int index = 0; for (ac->InitTraversal(ait); (anActor = ac->GetNextActor(ait));) { for (anActor->InitPathTraversal(); (apath = anActor->GetNextPath());) { if (anActor->GetVisibility() != 0) { aPart = static_cast(apath->GetLastNode()->GetViewProp()); this->WriteAnActor(aPart, writer, index); index++; } } } writer->EndNode(); // ROOT Transform ////////////////////////////////////////////// // do the 2D actors now a2Dc = ren->GetActors2D(); if (a2Dc->GetNumberOfItems() != 0) { static double s[] = { 1000000.0, 1000000.0, 1000000.0 }; writer->StartNode(ProximitySensor); writer->SetField(DEF, "PROX_LABEL"); writer->SetField(size, SFVEC3F, s); writer->EndNode(); // disable collision for the text annotations writer->StartNode(Collision); writer->SetField(enabled, false); // add a Label TRANS_LABEL for the text annotations and the sensor writer->StartNode(Transform); writer->SetField(DEF, "TRANS_LABEL"); vtkAssemblyPath* apath2D; vtkCollectionSimpleIterator ait2D; for (a2Dc->InitTraversal(ait2D); (anTextActor2D = a2Dc->GetNextActor2D(ait2D));) { for (anTextActor2D->InitPathTraversal(); (apath2D = anTextActor2D->GetNextPath());) { aPart2D = static_cast(apath2D->GetLastNode()->GetViewProp()); this->WriteATextActor2D(aPart2D, writer); } } writer->EndNode(); // Transform writer->EndNode(); // Collision writer->StartNode(ROUTE); writer->SetField(fromNode, "PROX_LABEL"); writer->SetField(fromField, "position_changed"); writer->SetField(toNode, "TRANS_LABEL"); writer->SetField(toField, "set_translation"); writer->EndNode(); // Route writer->StartNode(ROUTE); writer->SetField(fromNode, "PROX_LABEL"); writer->SetField(fromField, "orientation_changed"); writer->SetField(toNode, "TRANS_LABEL"); writer->SetField(toField, "set_rotation"); writer->EndNode(); // Route } ///////////////////////////////////////////////// this->WriteAdditionalNodes(writer); writer->EndNode(); // Scene writer->EndNode(); // X3D writer->Flush(); writer->EndDocument(); writer->CloseFile(); if (this->WriteToOutputString) { this->OutputStringLength = writer->GetOutputStringLength(); this->OutputString = writer->RegisterAndGetOutputString(); } } //------------------------------------------------------------------------------ void vtkX3DExporter::WriteALight(vtkLight* aLight, vtkX3DExporterWriter* writer) { double *pos, *focus, *colord; double dir[3]; pos = aLight->GetPosition(); focus = aLight->GetFocalPoint(); colord = aLight->GetDiffuseColor(); dir[0] = focus[0] - pos[0]; dir[1] = focus[1] - pos[1]; dir[2] = focus[2] - pos[2]; vtkMath::Normalize(dir); if (aLight->GetPositional()) { if (aLight->GetConeAngle() >= 90.0) { writer->StartNode(PointLight); } else { writer->StartNode(SpotLight); writer->SetField(direction, SFVEC3F, dir); writer->SetField(cutOffAngle, static_cast(aLight->GetConeAngle())); } writer->SetField(location, SFVEC3F, pos); writer->SetField(attenuation, SFVEC3F, aLight->GetAttenuationValues()); } else { writer->StartNode(DirectionalLight); writer->SetField(direction, SFVEC3F, dir); } // TODO: Check correct color writer->SetField(color, SFCOLOR, colord); writer->SetField(intensity, static_cast(aLight->GetIntensity())); writer->SetField(on, aLight->GetSwitch() != 0); writer->EndNode(); writer->Flush(); } //------------------------------------------------------------------------------ void vtkX3DExporter::WriteAnActor(vtkActor* anActor, vtkX3DExporterWriter* writer, int index) { // see if the actor has a mapper. it could be an assembly vtkMapper* mapper = anActor->GetMapper(); if (mapper == nullptr) { return; } mapper->Update(); // validate mapper input dataset. vtkDataObject* dObj = mapper->GetInputDataObject(0, 0); vtkCompositeDataSet* cd = vtkCompositeDataSet::SafeDownCast(dObj); vtkPolyData* pd = vtkPolyData::SafeDownCast(dObj); if (cd == nullptr && pd == nullptr) { // we don't support the input dataset or is empty. return; } // first stuff out the transform vtkSmartPointer trans = vtkSmartPointer::New(); trans->SetMatrix(anActor->vtkProp3D::GetMatrix()); writer->StartNode(Transform); writer->SetField(translation, SFVEC3F, trans->GetPosition()); writer->SetField(rotation, SFROTATION, trans->GetOrientationWXYZ()); writer->SetField(scale, SFVEC3F, trans->GetScale()); if (cd) { vtkSmartPointer iter; iter.TakeReference(cd->NewIterator()); for (iter->InitTraversal(); !iter->IsDoneWithTraversal(); iter->GoToNextItem()) { if (vtkPolyData* currentPD = vtkPolyData::SafeDownCast(iter->GetCurrentDataObject())) { writer->StartNode(Group); if (iter->HasCurrentMetaData() && iter->GetCurrentMetaData()->Has(vtkCompositeDataSet::NAME())) { if (const char* aname = iter->GetCurrentMetaData()->Get(vtkCompositeDataSet::NAME())) { std::string mfname = "\"" + std::string(aname) + "\""; writer->StartNode(MetadataString); writer->SetField(name, "name", false); writer->SetField(value, mfname.c_str(), true); writer->EndNode(); } } this->WriteAPiece(currentPD, anActor, writer, index); writer->EndNode(); // close the Group. } } } else { assert(pd != nullptr); this->WriteAPiece(pd, anActor, writer, index); } writer->EndNode(); } //------------------------------------------------------------------------------ void vtkX3DExporter::WriteAPiece( vtkPolyData* pd, vtkActor* anActor, vtkX3DExporterWriter* writer, int index) { vtkPointData* pntData; vtkCellData* cellData; vtkPoints* points; vtkDataArray* normals = nullptr; vtkDataArray* tcoords = nullptr; vtkProperty* prop; vtkUnsignedCharArray* colors; vtkSmartPointer trans; // see if the actor has a mapper. it could be an assembly if (anActor->GetMapper() == nullptr) { return; } if (pd == nullptr) { return; } // Create a temporary poly-data mapper that we use. vtkSmartPointer mapper = vtkSmartPointer::New(); mapper->SetInputData(pd); mapper->SetScalarRange(anActor->GetMapper()->GetScalarRange()); mapper->SetScalarVisibility(anActor->GetMapper()->GetScalarVisibility()); mapper->SetLookupTable(anActor->GetMapper()->GetLookupTable()); mapper->SetScalarMode(anActor->GetMapper()->GetScalarMode()); // Essential to turn of interpolate scalars otherwise GetScalars() may return // nullptr. We restore value before returning. mapper->SetInterpolateScalarsBeforeMapping(0); if (mapper->GetScalarMode() == VTK_SCALAR_MODE_USE_POINT_FIELD_DATA || mapper->GetScalarMode() == VTK_SCALAR_MODE_USE_CELL_FIELD_DATA) { if (anActor->GetMapper()->GetArrayAccessMode() == VTK_GET_ARRAY_BY_ID) { mapper->ColorByArrayComponent( anActor->GetMapper()->GetArrayId(), anActor->GetMapper()->GetArrayComponent()); } else { mapper->ColorByArrayComponent( anActor->GetMapper()->GetArrayName(), anActor->GetMapper()->GetArrayComponent()); } } prop = anActor->GetProperty(); points = pd->GetPoints(); pntData = pd->GetPointData(); tcoords = pntData->GetTCoords(); cellData = pd->GetCellData(); colors = mapper->MapScalars(255.0); // Are we using cell colors? Pass the temporary mapper we created here since // we're assured that that mapper only has vtkPolyData as input and hence // don't run into issue when dealing with composite datasets. bool cell_colors = vtkX3DExporterWriterUsingCellColors(mapper); normals = pntData->GetNormals(); // Are we using cell normals. bool cell_normals = false; if (prop->GetInterpolation() == VTK_FLAT || !normals) { // use cell normals, if any. normals = cellData->GetNormals(); cell_normals = true; } // if we don't have colors and we have only lines & points // use emissive to color them bool writeEmissiveColor = !(normals || colors || pd->GetNumberOfPolys() || pd->GetNumberOfStrips()); // write out the material properties to the mat file int representation = prop->GetRepresentation(); if (representation == VTK_POINTS) { // If representation is points, then we don't have to render different cell // types in separate shapes, since the cells type no longer matter. { writer->StartNode(Shape); this->WriteAnAppearance(anActor, writeEmissiveColor, writer); vtkX3DExporterWriterRenderPoints(pd, colors, cell_colors, writer); writer->EndNode(); } } else { // When rendering as lines or surface, we need to respect the cell // structure. This requires rendering polys, tstrips, lines, verts in // separate shapes. vtkCellArray* verts = pd->GetVerts(); vtkCellArray* lines = pd->GetLines(); vtkCellArray* polys = pd->GetPolys(); vtkCellArray* tstrips = pd->GetStrips(); vtkIdType numVerts = verts->GetNumberOfCells(); vtkIdType numLines = lines->GetNumberOfCells(); vtkIdType numPolys = polys->GetNumberOfCells(); vtkIdType numStrips = tstrips->GetNumberOfCells(); bool common_data_written = false; if (numPolys > 0) { writer->StartNode(Shape); // Write Appearance this->WriteAnAppearance(anActor, writeEmissiveColor, writer); // Write Geometry vtkX3DExporterWriterRenderFaceSet(VTK_POLYGON, representation, points, (numVerts + numLines), polys, colors, cell_colors, normals, cell_normals, tcoords, common_data_written, index, writer); writer->EndNode(); // close the Shape common_data_written = true; } if (numStrips > 0) { writer->StartNode(Shape); // Write Appearance this->WriteAnAppearance(anActor, writeEmissiveColor, writer); // Write Geometry vtkX3DExporterWriterRenderFaceSet(VTK_TRIANGLE_STRIP, representation, points, (numVerts + numLines + numPolys), tstrips, colors, cell_colors, normals, cell_normals, tcoords, common_data_written, index, writer); writer->EndNode(); // close the Shape common_data_written = true; } if (numLines > 0) { writer->StartNode(Shape); // Write Appearance this->WriteAnAppearance(anActor, writeEmissiveColor, writer); // Write Geometry vtkX3DExporterWriterRenderFaceSet(VTK_POLY_LINE, (representation == VTK_SURFACE ? VTK_WIREFRAME : representation), points, (numVerts), lines, colors, cell_colors, normals, cell_normals, tcoords, common_data_written, index, writer); writer->EndNode(); // close the Shape common_data_written = true; } if (numVerts > 0) { writer->StartNode(Shape); this->WriteAnAppearance(anActor, writeEmissiveColor, writer); vtkX3DExporterWriterRenderVerts(points, verts, colors, cell_normals, writer); writer->EndNode(); // close the Shape } } } //------------------------------------------------------------------------------ void vtkX3DExporter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); if (this->FileName) { os << indent << "FileName: " << this->FileName << "\n"; } else { os << indent << "FileName: (null)\n"; } os << indent << "Speed: " << this->Speed << "\n"; os << indent << "Binary: " << this->Binary << "\n"; os << indent << "Fastest: " << this->Fastest << endl; os << indent << "WriteToOutputString: " << (this->WriteToOutputString ? "On" : "Off") << std::endl; os << indent << "OutputStringLength: " << this->OutputStringLength << std::endl; if (this->OutputString) { os << indent << "OutputString: " << this->OutputString << std::endl; } } //------------------------------------------------------------------------------ void vtkX3DExporter::WriteATextActor2D(vtkActor2D* anTextActor2D, vtkX3DExporterWriter* writer) { char* ds; vtkTextActor* ta; vtkTextProperty* tp; if (!anTextActor2D->IsA("vtkTextActor")) { return; } ta = static_cast(anTextActor2D); tp = ta->GetTextProperty(); ds = ta->GetInput(); if (ds == nullptr) { return; } double temp[3]; writer->StartNode(Transform); temp[0] = ((ta->GetPosition()[0]) / (this->RenderWindow->GetSize()[0])) - 0.5; temp[1] = ((ta->GetPosition()[1]) / (this->RenderWindow->GetSize()[1])) - 0.5; temp[2] = -2.0; writer->SetField(translation, SFVEC3F, temp); temp[0] = temp[1] = temp[2] = 0.002; writer->SetField(scale, SFVEC3F, temp); writer->StartNode(Shape); writer->StartNode(Appearance); writer->StartNode(Material); temp[0] = 0.0; temp[1] = 0.0; temp[2] = 1.0; writer->SetField(diffuseColor, SFCOLOR, temp); tp->GetColor(temp); writer->SetField(emissiveColor, SFCOLOR, temp); writer->EndNode(); // Material writer->EndNode(); // Appearance writer->StartNode(Text); writer->SetField(vtkX3D::string, ds); std::string familyStr; switch (tp->GetFontFamily()) { case 0: default: familyStr = "\"SANS\""; break; case 1: familyStr = "\"TYPEWRITER\""; break; case 2: familyStr = "\"SERIF\""; break; } std::string justifyStr; switch (tp->GetJustification()) { case 0: default: justifyStr += "\"BEGIN\""; break; case 2: justifyStr += "\"END\""; break; } justifyStr += " \"BEGIN\""; writer->StartNode(FontStyle); writer->SetField(family, familyStr.c_str(), true); writer->SetField(topToBottom, tp->GetVerticalJustification() == 2); writer->SetField(justify, justifyStr.c_str(), true); writer->SetField(size, tp->GetFontSize()); writer->EndNode(); // FontStyle writer->EndNode(); // Text writer->EndNode(); // Shape writer->EndNode(); // Transform } void vtkX3DExporter::WriteAnAppearance( vtkActor* anActor, bool emissive, vtkX3DExporterWriter* writer) { double tempd[3]; double tempf2; vtkProperty* prop = anActor->GetProperty(); writer->StartNode(Appearance); writer->StartNode(Material); writer->SetField(ambientIntensity, static_cast(prop->GetAmbient())); if (emissive) { tempf2 = prop->GetAmbient(); prop->GetAmbientColor(tempd); tempd[0] *= tempf2; tempd[1] *= tempf2; tempd[2] *= tempf2; } else { tempd[0] = tempd[1] = tempd[2] = 0.0f; } writer->SetField(emissiveColor, SFCOLOR, tempd); // Set diffuse color tempf2 = prop->GetDiffuse(); prop->GetDiffuseColor(tempd); tempd[0] *= tempf2; tempd[1] *= tempf2; tempd[2] *= tempf2; writer->SetField(diffuseColor, SFCOLOR, tempd); // Set specular color tempf2 = prop->GetSpecular(); prop->GetSpecularColor(tempd); tempd[0] *= tempf2; tempd[1] *= tempf2; tempd[2] *= tempf2; writer->SetField(specularColor, SFCOLOR, tempd); // Material shininess writer->SetField(shininess, static_cast(prop->GetSpecularPower() / 128.0)); // Material transparency writer->SetField(transparency, static_cast(1.0 - prop->GetOpacity())); writer->EndNode(); // close material // is there a texture map if (anActor->GetTexture()) { this->WriteATexture(anActor, writer); } writer->EndNode(); // close appearance } void vtkX3DExporter::WriteATexture(vtkActor* anActor, vtkX3DExporterWriter* writer) { vtkTexture* aTexture = anActor->GetTexture(); int *size, xsize, ysize; vtkDataArray* scalars; vtkDataArray* mappedScalars; unsigned char* txtrData; int totalValues; // make sure it is updated and then get some info if (aTexture->GetInput() == nullptr) { vtkErrorMacro(<< "texture has no input!\n"); return; } aTexture->Update(); size = aTexture->GetInput()->GetDimensions(); scalars = aTexture->GetInput()->GetPointData()->GetScalars(); // make sure scalars are non null if (!scalars) { vtkErrorMacro(<< "No scalar values found for texture input!\n"); return; } // make sure using unsigned char data of color scalars type if (aTexture->GetColorMode() == VTK_COLOR_MODE_MAP_SCALARS || (scalars->GetDataType() != VTK_UNSIGNED_CHAR)) { mappedScalars = aTexture->GetMappedScalars(); } else { mappedScalars = scalars; } // we only support 2d texture maps right now // so one of the three sizes must be 1, but it // could be any of them, so lets find it if (size[0] == 1) { xsize = size[1]; ysize = size[2]; } else { xsize = size[0]; if (size[1] == 1) { ysize = size[2]; } else { ysize = size[1]; if (size[2] != 1) { vtkErrorMacro(<< "3D texture maps currently are not supported!\n"); return; } } } std::vector imageDataVec; imageDataVec.push_back(xsize); imageDataVec.push_back(ysize); imageDataVec.push_back(mappedScalars->GetNumberOfComponents()); totalValues = xsize * ysize; txtrData = static_cast(mappedScalars)->GetPointer(0); for (int i = 0; i < totalValues; i++) { int result = 0; for (int j = 0; j < imageDataVec[2]; j++) { result = result << 8; result += *txtrData; txtrData++; } imageDataVec.push_back(result); } writer->StartNode(PixelTexture); writer->SetField(image, &(imageDataVec.front()), imageDataVec.size(), true); if (!(aTexture->GetRepeat())) { writer->SetField(repeatS, false); writer->SetField(repeatT, false); } writer->EndNode(); } //------------------------------------------------------------------------------ int vtkX3DExporter::HasHeadLight(vtkRenderer* ren) { // make sure we have a default light // if we don't then use a headlight vtkLightCollection* lc = ren->GetLights(); vtkCollectionSimpleIterator lsit; vtkLight* aLight = nullptr; for (lc->InitTraversal(lsit); (aLight = lc->GetNextLight(lsit));) { if (aLight->LightTypeIsHeadlight()) { return 1; } } return 0; } // Determine if we're using cell data for scalar coloring. Returns true if // that's the case. static bool vtkX3DExporterWriterUsingCellColors(vtkMapper* mapper) { int cellFlag = 0; vtkAbstractMapper::GetScalars(mapper->GetInput(), mapper->GetScalarMode(), mapper->GetArrayAccessMode(), mapper->GetArrayId(), mapper->GetArrayName(), cellFlag); return (cellFlag == 1); } //------------------------------------------------------------------------------ static bool vtkX3DExporterWriterRenderFaceSet(int cellType, int representation, vtkPoints* points, vtkIdType cellOffset, vtkCellArray* cells, vtkUnsignedCharArray* colors, bool cell_colors, vtkDataArray* normals, bool cell_normals, vtkDataArray* tcoords, bool common_data_written, int index, vtkX3DExporterWriter* writer) { std::vector coordIndexVector; std::vector cellIndexVector; vtkIdType npts = 0; const vtkIdType* indx = nullptr; if (cellType == VTK_POLYGON || cellType == VTK_POLY_LINE) { for (cells->InitTraversal(); cells->GetNextCell(npts, indx); cellOffset++) { for (vtkIdType cc = 0; cc < npts; cc++) { coordIndexVector.push_back(static_cast(indx[cc])); } if (representation == VTK_WIREFRAME && npts > 2 && cellType == VTK_POLYGON) { // close the polygon. coordIndexVector.push_back(static_cast(indx[0])); } coordIndexVector.push_back(-1); vtkIdType cellid = cellOffset; cellIndexVector.push_back(cellid); } } else // cellType == VTK_TRIANGLE_STRIP { for (cells->InitTraversal(); cells->GetNextCell(npts, indx); cellOffset++) { for (vtkIdType cc = 2; cc < npts; cc++) { vtkIdType i1; vtkIdType i2; if (cc % 2) { i1 = cc - 1; i2 = cc - 2; } else { i1 = cc - 2; i2 = cc - 1; } coordIndexVector.push_back(static_cast(indx[i1])); coordIndexVector.push_back(static_cast(indx[i2])); coordIndexVector.push_back(static_cast(indx[cc])); if (representation == VTK_WIREFRAME) { // close the polygon when drawing lines coordIndexVector.push_back(static_cast(indx[i1])); } coordIndexVector.push_back(-1); vtkIdType cellid = cellOffset; cellIndexVector.push_back(static_cast(cellid)); } } } if (representation == VTK_SURFACE) { writer->StartNode(IndexedFaceSet); writer->SetField(solid, false); writer->SetField(colorPerVertex, !cell_colors); writer->SetField(normalPerVertex, !cell_normals); writer->SetField(coordIndex, &(coordIndexVector.front()), coordIndexVector.size()); } else { // don't save normals/tcoords when saving wireframes. normals = nullptr; tcoords = nullptr; writer->StartNode(IndexedLineSet); writer->SetField(colorPerVertex, !cell_colors); writer->SetField(coordIndex, &(coordIndexVector.front()), coordIndexVector.size()); } if (normals && cell_normals && representation == VTK_SURFACE) { writer->SetField(normalIndex, &(cellIndexVector.front()), cellIndexVector.size()); } if (colors && cell_colors) { writer->SetField(colorIndex, &(cellIndexVector.front()), cellIndexVector.size()); } // Now save Coordinate, Color, Normal TextureCoordinate nodes. // Use DEF/USE to avoid duplicates. if (!common_data_written) { vtkX3DExporterWriteData(points, normals, tcoords, colors, index, writer); } else { vtkX3DExporterUseData( (normals != nullptr), (tcoords != nullptr), (colors != nullptr), index, writer); } writer->EndNode(); // end IndexedFaceSet or IndexedLineSet return true; } static void vtkX3DExporterWriteData(vtkPoints* points, vtkDataArray* normals, vtkDataArray* tcoords, vtkUnsignedCharArray* colors, int index, vtkX3DExporterWriter* writer) { char indexString[100]; snprintf(indexString, sizeof(indexString), "%04d", index); // write out the points std::string defString = "VTKcoordinates"; writer->StartNode(Coordinate); writer->SetField(DEF, defString.append(indexString).c_str()); writer->SetField(point, MFVEC3F, points->GetData()); writer->EndNode(); // write out the point data if (normals) { defString = "VTKnormals"; writer->StartNode(Normal); writer->SetField(DEF, defString.append(indexString).c_str()); writer->SetField(vtkX3D::vector, MFVEC3F, normals); writer->EndNode(); } // write out the point data if (tcoords) { defString = "VTKtcoords"; writer->StartNode(TextureCoordinate); writer->SetField(DEF, defString.append(indexString).c_str()); writer->SetField(point, MFVEC2F, tcoords); writer->EndNode(); } // write out the point data if (colors) { defString = "VTKcolors"; writer->StartNode(Color); writer->SetField(DEF, defString.append(indexString).c_str()); std::vector colorVec; unsigned char c[4]; for (int i = 0; i < colors->GetNumberOfTuples(); i++) { colors->GetTypedTuple(i, c); colorVec.push_back(c[0] / 255.0); colorVec.push_back(c[1] / 255.0); colorVec.push_back(c[2] / 255.0); } writer->SetField(color, &(colorVec.front()), colorVec.size()); writer->EndNode(); } } static void vtkX3DExporterUseData( bool normals, bool tcoords, bool colors, int index, vtkX3DExporterWriter* writer) { char indexString[100]; snprintf(indexString, sizeof(indexString), "%04d", index); std::string defString = "VTKcoordinates"; writer->StartNode(Coordinate); writer->SetField(USE, defString.append(indexString).c_str()); writer->EndNode(); // write out the point data if (normals) { defString = "VTKnormals"; writer->StartNode(Normal); writer->SetField(USE, defString.append(indexString).c_str()); writer->EndNode(); } // write out the point data if (tcoords) { defString = "VTKtcoords"; writer->StartNode(TextureCoordinate); writer->SetField(USE, defString.append(indexString).c_str()); writer->EndNode(); } // write out the point data if (colors) { defString = "VTKcolors"; writer->StartNode(Color); writer->SetField(USE, defString.append(indexString).c_str()); writer->EndNode(); } } static bool vtkX3DExporterWriterRenderVerts(vtkPoints* points, vtkCellArray* cells, vtkUnsignedCharArray* colors, bool cell_colors, vtkX3DExporterWriter* writer) { std::vector colorVector; if (colors) { vtkIdType cellId = 0; vtkIdType npts = 0; const vtkIdType* indx = nullptr; for (cells->InitTraversal(); cells->GetNextCell(npts, indx); cellId++) { for (vtkIdType cc = 0; cc < npts; cc++) { unsigned char color[4]; if (cell_colors) { colors->GetTypedTuple(cellId, color); } else { colors->GetTypedTuple(indx[cc], color); } colorVector.push_back(color[0] / 255.0); colorVector.push_back(color[1] / 255.0); colorVector.push_back(color[2] / 255.0); } } } writer->StartNode(PointSet); writer->StartNode(Coordinate); writer->SetField(point, MFVEC3F, points->GetData()); writer->EndNode(); if (colors) { writer->StartNode(Color); writer->SetField(point, &(colorVector.front()), colorVector.size()); writer->EndNode(); } return true; } static bool vtkX3DExporterWriterRenderPoints( vtkPolyData* pd, vtkUnsignedCharArray* colors, bool cell_colors, vtkX3DExporterWriter* writer) { if (pd->GetNumberOfCells() == 0) { return false; } std::vector colorVec; std::vector coordinateVec; vtkPoints* points = pd->GetPoints(); // We render as cells so that even when coloring with cell data, the points // are assigned colors correctly. if ((colors != nullptr) && cell_colors) { // Cell colors are used, however PointSet element can only have point // colors, hence we use this method. Although here we end up with duplicate // points, that's exactly what happens in case of OpenGL rendering, so it's // okay. vtkIdType numCells = pd->GetNumberOfCells(); vtkSmartPointer pointIds = vtkSmartPointer::New(); for (vtkIdType cid = 0; cid < numCells; cid++) { pointIds->Reset(); pd->GetCellPoints(cid, pointIds); // Get the color for this cell. unsigned char color[4]; colors->GetTypedTuple(cid, color); double dcolor[3]; dcolor[0] = color[0] / 255.0; dcolor[1] = color[1] / 255.0; dcolor[2] = color[2] / 255.0; for (vtkIdType cc = 0; cc < pointIds->GetNumberOfIds(); cc++) { vtkIdType pid = pointIds->GetId(cc); double* point = points->GetPoint(pid); coordinateVec.push_back(point[0]); coordinateVec.push_back(point[1]); coordinateVec.push_back(point[2]); colorVec.push_back(dcolor[0]); colorVec.push_back(dcolor[1]); colorVec.push_back(dcolor[2]); } } } else { // Colors are point colors, simply render all the points and corresponding // colors. vtkIdType numPoints = points->GetNumberOfPoints(); for (vtkIdType pid = 0; pid < numPoints; pid++) { double* point = points->GetPoint(pid); coordinateVec.push_back(point[0]); coordinateVec.push_back(point[1]); coordinateVec.push_back(point[2]); if (colors) { unsigned char color[4]; colors->GetTypedTuple(pid, color); colorVec.push_back(color[0] / 255.0); colorVec.push_back(color[1] / 255.0); colorVec.push_back(color[2] / 255.0); } } } writer->StartNode(PointSet); writer->StartNode(Coordinate); writer->SetField(point, &(coordinateVec.front()), coordinateVec.size()); writer->EndNode(); // Coordinate if (colors) { writer->StartNode(Color); writer->SetField(color, &(colorVec.front()), colorVec.size()); writer->EndNode(); // Color } writer->EndNode(); // PointSet return true; } //------------------------------------------------------------------------------ char* vtkX3DExporter::RegisterAndGetOutputString() { char* tmp = this->OutputString; this->OutputString = nullptr; this->OutputStringLength = 0; return tmp; }