Commit 8674ca6b authored by Ken Martin's avatar Ken Martin

rework the mtl file handling for obj/mtl files

also add a new exporter designed to work with
obj file although it will work with any scene
in vtk.

The new exporter takes all the actors in a scene
and stores them as a single vtp file. It also takes
all the texturs and combines them into a single texture.
The exporter is designed to take OBJ files that may
consist of mulitple parts each with their own texture
and convert them into a singlke vtp file so that they are
easier to work with in ParaView/etc.
parent 35430caa
......@@ -3,14 +3,31 @@ cmake_minimum_required(VERSION 3.3 FATAL_ERROR)
PROJECT (IO)
find_package(VTK COMPONENTS
find_package(VTK REQUIRED)
if (vtkIOExport_LOADED AND vtkIOImport_LOADED)
vtk_module_config(VTK
vtkCommonCore
vtkIOLegacy
vtkIOXML
vtkIOGeometry
vtkTestingRendering
vtkInteractionStyle
vtkIOImport
vtkIOExport
vtksys
)
else()
vtk_module_config(VTK
vtkCommonCore
vtkIOLegacy
vtkIOXML
vtkIOGeometry
vtkTestingRendering
vtkInteractionStyle
vtkIOImport
vtksys
)
endif()
include(${VTK_USE_FILE})
add_executable(DumpXMLFile MACOSX_BUNDLE DumpXMLFile.cxx)
......@@ -19,6 +36,11 @@ target_link_libraries(DumpXMLFile ${VTK_LIBRARIES})
add_executable(ParticleReader MACOSX_BUNDLE ParticleReader.cxx)
target_link_libraries(ParticleReader ${VTK_LIBRARIES})
if (vtkIOExport_LOADED AND vtkIOImport_LOADED)
add_executable(objtovtp objtovtp.cxx)
target_link_libraries(objtovtp ${VTK_LIBRARIES})
endif()
if(BUILD_TESTING)
if(vtkTestingRendering_LOADED)
######## Regression Testing ########
......
/*=========================================================================
Program: Visualization Toolkit
Module: vtkSingleVTPExporter.h
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 "vtkNew.h"
#include "vtkOBJImporter.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkSingleVTPExporter.h"
#include "vtksys/SystemTools.hxx"
#include <sstream>
int main( int argc, char * argv [] )
{
if(argc < 2)
{
std::cerr<<"expected objtovtk File1.obj [File2.obj.mtl]"<<std::endl;
return -1;
}
std::string filenameOBJ(argv[1]);
std::string filenameMTL;
if(argc >= 3)
{
filenameMTL = argv[2];
}
std::string texturePath = vtksys::SystemTools::GetFilenamePath(filenameOBJ);
vtkNew<vtkOBJImporter> importer;
importer->SetFileName(filenameOBJ.data());
importer->SetFileNameMTL(filenameMTL.data());
importer->SetTexturePath(texturePath.data());
vtkNew<vtkRenderer> ren;
vtkNew<vtkRenderWindow> renWin;
vtkNew<vtkRenderWindowInteractor> iren;
renWin->AddRenderer(ren);
iren->SetRenderWindow(renWin);
importer->SetRenderWindow(renWin);
importer->Update();
renWin->SetSize(800,600);
ren->SetBackground(0.4,0.5,0.6);
ren->ResetCamera();
renWin->Render();
// export to a single vtk file
vtkNew<vtkSingleVTPExporter> exporter;
std::string outputPrefix = "o2v";
outputPrefix += vtksys::SystemTools::GetFilenameWithoutLastExtension(filenameOBJ);
exporter->SetFilePrefix(outputPrefix.c_str());
exporter->SetRenderWindow(renWin);
exporter->Write();
iren->Start();
return 0;
}
......@@ -12,6 +12,7 @@ set(Module_SRCS
vtkRIBProperty.cxx
vtkSVGContextDevice2D.cxx
vtkSVGExporter.cxx
vtkSingleVTPExporter.cxx
vtkVRMLExporter.cxx
vtkX3D.cxx
vtkX3DExporter.cxx
......
......@@ -42,6 +42,7 @@ endif()
vtk_add_test_cxx(vtkIOExportCxxTests tests
X3DTest.cxx,NO_DATA,NO_VALID
TestOBJExporter.cxx,NO_DATA,NO_VALID
TestSingleVTPExporter.cxx,NO_DATA,NO_VALID
${GL2PSTests} ${GL2PSTestsPDF} ${PDFTests} ${SVGTests}
TestRIBExporter.cxx,NO_VALID
UnitTestRIB.cxx,NO_DATA,NO_VALID
......
/*=========================================================================
Program: Visualization Toolkit
Module: TestOBJExporter.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 "vtkActor.h"
#include "vtkNew.h"
#include "vtkSingleVTPExporter.h"
#include "vtkPolyDataMapper.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkSphereSource.h"
#include "vtkTestUtilities.h"
#include <cstdlib>
namespace {
size_t fileSize(const std::string & filename)
{
size_t size = 0;
FILE* f = fopen(filename.c_str(), "r");
if (f)
{
fseek(f, 0, SEEK_END);
size = ftell(f);
fclose(f);
}
else
{
std::cerr << "Error: cannot open file " << filename << std::endl;
}
return size;
}
}
int TestSingleVTPExporter(int argc, char *argv[])
{
char *tempDir = vtkTestUtilities::GetArgOrEnvOrDefault(
"-T", argc, argv, "VTK_TEMP_DIR", "Testing/Temporary");
if (!tempDir)
{
std::cout << "Could not determine temporary directory.\n";
return EXIT_FAILURE;
}
std::string testDirectory = tempDir;
delete[] tempDir;
std::string filename = testDirectory
+ std::string("/") + std::string("Export");
vtkNew<vtkSphereSource> sphere;
vtkNew<vtkPolyDataMapper> mapper;
mapper->SetInputConnection(sphere->GetOutputPort());
vtkNew<vtkActor> actor;
actor->SetMapper(mapper);
vtkNew<vtkRenderer> renderer;
renderer->AddActor(actor);
vtkNew<vtkRenderWindow> window;
window->AddRenderer(renderer);
vtkNew<vtkSingleVTPExporter> exporter;
exporter->SetRenderWindow(window);
exporter->SetFilePrefix(filename.c_str());
exporter->Write();
filename += ".vtp";
size_t correctSize = fileSize(filename);
if (correctSize == 0)
{
return EXIT_FAILURE;
}
actor->VisibilityOff();
exporter->Write();
size_t noDataSize = fileSize(filename);
if (noDataSize == 0)
{
return EXIT_FAILURE;
}
if (noDataSize >= correctSize)
{
std::cerr << "Error: file should contain data for a visible actor"
"and not for a hidden one." << std::endl;
return EXIT_FAILURE;
}
actor->VisibilityOn();
actor->SetMapper(nullptr);
exporter->Write();
size_t size = fileSize(filename);
if (size == 0)
{
return EXIT_FAILURE;
}
if (size > noDataSize)
{
std::cerr << "Error: file should not contain geometry"
" (actor has no mapper)" << std::endl;
return EXIT_FAILURE;
}
actor->SetMapper(mapper);
mapper->RemoveAllInputConnections(0);
exporter->Write();
size = fileSize(filename);
if (size == 0)
{
return EXIT_FAILURE;
}
if (size > noDataSize)
{
std::cerr << "Error: file should not contain geometry"
" (mapper has no input)" << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
......@@ -26,6 +26,7 @@ vtk_module(vtkIOExport
vtkCommonCore
vtkIOCore
vtkIOImage
vtkIOXML
vtkRenderingContext2D
vtkRenderingCore
vtkRenderingFreeType
......
This diff is collapsed.
/*=========================================================================
Program: Visualization Toolkit
Module: vtkSingleVTPExporter.h
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.
=========================================================================*/
/**
* @class vtkSingleVTPExporter
* @brief export a scene into a single vtp file and png texture
*
* vtkSingleVTPExporter is a concrete subclass of vtkExporter that writes
* a .vtp file and a .png file containing the polydata and texture
* elements of the scene.
*
* @sa
* vtkExporter
*/
#ifndef vtkSingleVTPExporter_h
#define vtkSingleVTPExporter_h
#include "vtkIOExportModule.h" // For export macro
#include "vtkExporter.h"
#include <vector> // for method args
class vtkActor;
class vtkTexture;
class VTKIOEXPORT_EXPORT vtkSingleVTPExporter : public vtkExporter
{
public:
static vtkSingleVTPExporter *New();
vtkTypeMacro(vtkSingleVTPExporter,vtkExporter);
void PrintSelf(ostream& os, vtkIndent indent) override;
//@{
/**
* Specify the prefix of the files to write out. The resulting filenames
* will have .vtp and .png appended to them.
*/
vtkSetStringMacro(FilePrefix);
vtkGetStringMacro(FilePrefix);
//@}
protected:
vtkSingleVTPExporter();
~vtkSingleVTPExporter() override;
void WriteData() override;
class actorData
{
public:
vtkActor *Actor;
vtkTexture *Texture;
int ImagePosition[2];
};
int TextureSize[2];
void WriteTexture(std::vector<actorData> &actors);
void WriteVTP(std::vector<actorData> &actors);
char *FilePrefix;
private:
vtkSingleVTPExporter(const vtkSingleVTPExporter&) = delete;
void operator=(const vtkSingleVTPExporter&) = delete;
};
#endif
bda5e85e0fca1a0eec745617b868fb54
58442cb7bb47c93f9fb345689d790d19
#line 1 "..\\vtk3\\vtk\\io\\import\\mtlsyntax.rl"
// This is a ragel file for generating a paser for MTL files
// Note that some MTL files are whitespace sensitive
// Mainly with unquoted string names with spaces
// ala
//
// newmtl material name with spaces and no quotes
//
// or
//
// map_Kd my texture file.png
//
#line 83 "..\\vtk3\\vtk\\io\\import\\mtlsyntax.rl"
#line 20 "..\\vtk3\\vtk\\io\\import\\mtlsyntax.c"
static const char _simple_lexer_actions[] = {
0, 1, 0, 1, 1, 1, 3, 1,
4, 1, 8, 1, 9, 1, 10, 1,
11, 1, 12, 1, 13, 1, 14, 1,
15, 2, 2, 0, 2, 5, 0, 4,
5, 2, 0, 7, 4, 5, 2, 6,
0
};
static const char _simple_lexer_key_offsets[] = {
0, 2, 3, 13, 16, 20, 21, 26,
31, 37
};
static const char _simple_lexer_trans_keys[] = {
10, 13, 10, 10, 13, 32, 35, 43,
45, 9, 12, 48, 57, 32, 9, 13,
9, 32, 11, 12, 10, 10, 13, 32,
9, 12, 32, 9, 13, 48, 57, 32,
46, 9, 13, 48, 57, 32, 9, 13,
48, 57, 0
};
static const char _simple_lexer_single_lengths[] = {
2, 1, 6, 1, 2, 1, 3, 1,
2, 1
};
static const char _simple_lexer_range_lengths[] = {
0, 0, 2, 1, 1, 0, 1, 2,
2, 2
};
static const char _simple_lexer_index_offsets[] = {
0, 3, 5, 14, 17, 21, 23, 28,
32, 37
};
static const char _simple_lexer_indicies[] = {
2, 3, 1, 2, 0, 6, 7, 5,
8, 9, 9, 5, 10, 4, 11, 11,
4, 5, 5, 5, 12, 6, 13, 2,
3, 1, 1, 8, 11, 11, 10, 4,
14, 15, 14, 10, 4, 16, 16, 17,
4, 0
};
static const char _simple_lexer_trans_targs[] = {
2, 0, 2, 1, 3, 4, 2, 5,
6, 7, 8, 2, 2, 2, 2, 9,
2, 9
};
static const char _simple_lexer_trans_actions[] = {
21, 0, 9, 0, 1, 3, 11, 0,
28, 25, 25, 15, 17, 19, 13, 31,
23, 36
};
static const char _simple_lexer_to_state_actions[] = {
0, 0, 5, 0, 0, 0, 0, 0,
0, 0
};
static const char _simple_lexer_from_state_actions[] = {
0, 0, 7, 0, 0, 0, 0, 0,
0, 0
};
static const char _simple_lexer_eof_trans[] = {
1, 1, 0, 12, 13, 14, 12, 12,
15, 17
};
static const int simple_lexer_start = 2;
static const int simple_lexer_first_final = 2;
static const int simple_lexer_error = -1;
static const int simple_lexer_en_main = 2;
#line 86 "..\\vtk3\\vtk\\io\\import\\mtlsyntax.rl"
int parseMTL(
const char *start,
std::vector<Token> &tokens
)
{
int act, cs, res = 0;
const char *p = start;
const char *pe = p + strlen(start) + 1;
const char *eof = pe;
const char *ts = nullptr;
const char *te = nullptr;
std::string recentString;
std::string recentSpace;
std::string currentNum;
#line 121 "..\\vtk3\\vtk\\io\\import\\mtlsyntax.c"
{
cs = simple_lexer_start;
ts = 0;
te = 0;
act = 0;
}
#line 104 "..\\vtk3\\vtk\\io\\import\\mtlsyntax.rl"
#line 131 "..\\vtk3\\vtk\\io\\import\\mtlsyntax.c"
{
int _klen;
unsigned int _trans;
const char *_acts;
unsigned int _nacts;
const char *_keys;
if ( p == pe )
goto _test_eof;
_resume:
_acts = _simple_lexer_actions + _simple_lexer_from_state_actions[cs];
_nacts = (unsigned int) *_acts++;
while ( _nacts-- > 0 ) {
switch ( *_acts++ ) {
case 4:
#line 1 "NONE"
{ts = p;}
break;
#line 150 "..\\vtk3\\vtk\\io\\import\\mtlsyntax.c"
}
}
_keys = _simple_lexer_trans_keys + _simple_lexer_key_offsets[cs];
_trans = _simple_lexer_index_offsets[cs];
_klen = _simple_lexer_single_lengths[cs];
if ( _klen > 0 ) {
const char *_lower = _keys;
const char *_mid;
const char *_upper = _keys + _klen - 1;
while (1) {
if ( _upper < _lower )
break;
_mid = _lower + ((_upper-_lower) >> 1);
if ( (*p) < *_mid )
_upper = _mid - 1;
else if ( (*p) > *_mid )
_lower = _mid + 1;
else {
_trans += (unsigned int)(_mid - _keys);
goto _match;
}
}
_keys += _klen;
_trans += _klen;
}
_klen = _simple_lexer_range_lengths[cs];
if ( _klen > 0 ) {
const char *_lower = _keys;
const char *_mid;
const char *_upper = _keys + (_klen<<1) - 2;
while (1) {
if ( _upper < _lower )
break;
_mid = _lower + (((_upper-_lower) >> 1) & ~1);
if ( (*p) < _mid[0] )
_upper = _mid - 2;
else if ( (*p) > _mid[1] )
_lower = _mid + 2;
else {
_trans += (unsigned int)((_mid - _keys)>>1);
goto _match;
}
}
_trans += _klen;
}
_match:
_trans = _simple_lexer_indicies[_trans];
_eof_trans:
cs = _simple_lexer_trans_targs[_trans];
if ( _simple_lexer_trans_actions[_trans] == 0 )
goto _again;
_acts = _simple_lexer_actions + _simple_lexer_trans_actions[_trans];
_nacts = (unsigned int) *_acts++;
while ( _nacts-- > 0 )
{
switch ( *_acts++ )
{
case 0:
#line 20 "..\\vtk3\\vtk\\io\\import\\mtlsyntax.rl"
{ recentString += *p; }
break;
case 1:
#line 33 "..\\vtk3\\vtk\\io\\import\\mtlsyntax.rl"
{ recentSpace += *p; }
break;
case 2:
#line 46 "..\\vtk3\\vtk\\io\\import\\mtlsyntax.rl"
{ currentNum += *p; }
break;
case 5:
#line 1 "NONE"
{te = p+1;}
break;
case 6:
#line 48 "..\\vtk3\\vtk\\io\\import\\mtlsyntax.rl"
{act = 2;}
break;
case 7:
#line 22 "..\\vtk3\\vtk\\io\\import\\mtlsyntax.rl"
{act = 3;}
break;
case 8:
#line 62 "..\\vtk3\\vtk\\io\\import\\mtlsyntax.rl"
{te = p+1;{ currentNum.clear(); recentString.clear(); recentSpace.clear(); }}
break;
case 9:
#line 72 "..\\vtk3\\vtk\\io\\import\\mtlsyntax.rl"
{te = p+1;{
Token tok;
tok.Type = Token::LineEnd;
tokens.push_back(tok);
currentNum.clear(); recentString.clear(); recentSpace.clear();
}}
break;
case 10:
#line 48 "..\\vtk3\\vtk\\io\\import\\mtlsyntax.rl"
{te = p;p--;{
currentNum += '\0';
Token tok;
tok.StringValue = currentNum;
tok.NumberValue = std::atof(currentNum.c_str());
tok.Type = Token::Number;
tokens.push_back(tok);
currentNum.clear();
recentString.clear();
recentSpace.clear();
}}
break;
case 11:
#line 22 "..\\vtk3\\vtk\\io\\import\\mtlsyntax.rl"
{te = p;p--;{
Token tok;
tok.StringValue = recentString;
tok.Type = Token::String;
tokens.push_back(tok);
recentString.clear();
currentNum.clear();
recentSpace.clear();
}}
break;
case 12:
#line 35 "..\\vtk3\\vtk\\io\\import\\mtlsyntax.rl"
{te = p;p--;{
Token tok;
tok.StringValue = recentSpace;
tok.Type = Token::Space;
tokens.push_back(tok);
recentSpace.clear();
currentNum.clear();
recentString.clear();
}}
break;
case 13:
#line 79 "..\\vtk3\\vtk\\io\\import\\mtlsyntax.rl"
{te = p;p--;{ std::string value = "Error unknown text: "; value += std::string(ts, te-ts); cerr << value << "\n"; }}
break;
case 14:
#line 22 "..\\vtk3\\vtk\\io\\import\\mtlsyntax.rl"
{{p = ((te))-1;}{
Token tok;
tok.StringValue = recentString;
tok.Type = Token::String;
tokens.push_back(tok);
recentString.clear();
currentNum.clear();
recentSpace.clear();
}}
break;
case 15:
#line 1 "NONE"
{ switch( act ) {
case 2:
{{p = ((te))-1;}
currentNum += '\0';
Token tok;
tok.StringValue = currentNum;
tok.NumberValue = std::atof(currentNum.c_str());
tok.Type = Token::Number;
tokens.push_back(tok);
currentNum.clear();
recentString.clear();
recentSpace.clear();
}
break;
case 3:
{{p = ((te))-1;}
Token tok;
tok.StringValue = recentString;
tok.Type = Token::String;
tokens.push_back(tok);
recentString.clear();
currentNum.clear();
recentSpace.clear();
}
break;
}
}
break;
#line 337 "..\\vtk3\\vtk\\io\\import\\mtlsyntax.c"
}
}
_again:
_acts = _simple_lexer_actions + _simple_lexer_to_state_actions[cs];
_nacts = (unsigned int) *_acts++;
while ( _nacts-- > 0 ) {
switch ( *_acts++ ) {
case 3:
#line 1 "NONE"
{ts = 0;}
break;
#line 350 "..\\vtk3\\vtk\\io\\import\\mtlsyntax.c"
}
}
if ( ++p != pe )
goto _resume;
_test_eof: {}
if ( p == eof )
{
if ( _simple_lexer_eof_trans[cs] > 0 ) {
_trans = _simple_lexer_eof_trans[cs] - 1;
goto _eof_trans;
}
}
}
#line 105 "..\\vtk3\\vtk\\io\\import\\mtlsyntax.rl"
return res;
}
// This is a ragel file for generating a paser for MTL files
// Note that some MTL files are whitespace sensitive