@ -28,8 +28,7 @@
# include <fstream>
# include <limits>
# include <sstream>
# include <tuple>
# include <stdlib.h>
# include <cstdlib>
# include <unordered_map>
# include <Corrade/Containers/ArrayView.h>
# include <Corrade/Utility/String.h>
@ -72,28 +71,26 @@ struct ObjMesh;
struct ObjMeshData {
ObjGroup & group ;
int materialId ; /* f rom 'usemtl' keyword */
Int materialId ; /* F rom 'usemtl' keyword */
ObjMesh * poi nts = nullptr ;
ObjMesh * poI nts = nullptr ;
ObjMesh * lines = nullptr ;
ObjMesh * faces = nullptr ;
ObjMeshData ( ) = delete ;
ObjMeshData ( ObjGroup & g , int matId ) : group ( g ) , materialId ( matId ) { }
explicit ObjMeshData ( ObjGroup & g , Int matId ) : group ( g ) , materialId ( matId ) { }
} ;
struct ObjGroup {
ObjObject & object ;
std : : string name ; /* f rom 'g' keyword */
std : : string name ; /* F rom 'g' keyword */
std : : vector < std : : unique_ptr < ObjMeshData > > meshes ;
std : : unordered_map < int , i nt> meshPerMaterial ;
std : : unordered_map < Int , I nt> meshPerMaterial ;
ObjGroup ( ) = delete ;
ObjGroup ( ObjObject & o ) : object ( o ) { }
explicit ObjGroup ( ObjObject & o ) : object ( o ) { }
/* Create or get mesh for given material id */
ObjMeshData & meshDataForMaterial ( i nt materialId ) {
ObjMeshData & meshDataForMaterial ( I nt materialId ) {
if ( meshPerMaterial . find ( materialId ) ! = meshPerMaterial . end ( ) ) {
return * meshes [ meshPerMaterial [ materialId ] ] ;
} else {
@ -106,25 +103,25 @@ struct ObjGroup {
} ;
struct ObjObject {
std : : string name ; /* f rom 'o' keyword */
std : : string name ; /* F rom 'o' keyword */
std : : vector < std : : unique_ptr < ObjGroup > > groups ;
ObjObject ( ) : name { " " } { }
ObjObject ( ArrayView < char > name ) : name { name . data ( ) , name . size ( ) } { }
ObjObject ( ArrayView < const char > name ) : name { name . data ( ) , name . size ( ) } { }
} ;
/* An i ntermediate object representing a mesh and it's properties as well as
/* An I ntermediate object representing a mesh and it's properties as well as
* where to find the data associated to it */
struct ObjMesh {
ObjMeshData & data ; /* p arent object containing data shared meshes for different primitives */
ObjMeshData & data ; /* P arent object containing data shared meshes for different primitives */
MeshPrimitive primitive ;
/* Sections of the file belonging to this mesh */
std : : vector < ArrayView < char > > sections ;
std : : vector < ArrayView < const char > > sections ;
i nt minPrimitives = 0 ; /* For smarter vector memory allocation later */
I nt minPrimitives = 0 ; /* For smarter vector memory allocation later */
ObjMesh ( ObjMeshData & d , MeshPrimitive p ) : data ( d ) , primitive ( p ) { }
explicit ObjMesh ( ObjMeshData & d , MeshPrimitive p ) : data ( d ) , primitive ( p ) { }
std : : string name ( ) {
std : : string name = data . group . object . name ;
@ -137,8 +134,8 @@ struct ObjMesh {
name + = " $ " + std : : to_string ( data . materialId ) ;
}
const i nt numPrimitiveTypes =
( ( data . poi nts ) ? 1 : 0 )
const I nt numPrimitiveTypes =
( ( data . poI nts ) ? 1 : 0 )
+ ( ( data . lines ) ? 1 : 0 )
+ ( ( data . faces ) ? 1 : 0 ) ;
if ( numPrimitiveTypes > 1 ) {
@ -154,19 +151,22 @@ struct ObjMesh {
/* The state of the imported generated by openData() */
struct ImporterState {
Containers : : Array < char > in ;
std : : string fileRoot ;
std : : vector < ObjMaterial > materials ;
std : : unordered_map < std : : string , int > materialIds ;
std : : unordered_map < std : : string , I nt> materialIds ;
std : : vector < std : : string > textures ;
std : : unordered_map < std : : string , i nt> textureIds ;
std : : unordered_map < std : : string , I nt> textureIds ;
std : : vector < std : : unique_ptr < ObjObject > > objects ;
std : : vector < std : : unique_ptr < ObjMesh > > meshes ;
std : : unordered_map < std : : string , i nt> meshIds ;
std : : unordered_map < std : : string , I nt> meshIds ;
std : : vector < std : : string > meshlessObjects ;
std : : unordered_map < std : : string , i nt> meshlessObjectIds ;
std : : unordered_map < std : : string , I nt> meshlessObjectIds ;
std : : vector < Vector3 > positions ;
std : : vector < Vector2 > texCoords ;
@ -175,9 +175,10 @@ struct ImporterState {
namespace {
int strToInt ( const ArrayView < char > str ) {
/* Returns the given string parsed as Int */
Int strToInt ( const ArrayView < const char > str ) {
char * err ;
const int i = i nt( strtol ( str . data ( ) , & err , 10 ) ) ;
const Int i = I nt( strtol ( str . data ( ) , & err , 10 ) ) ;
if ( err = = nullptr ) {
Error ( ) < < " Trade::ObjImporter::mesh3D(): error while converting numeric data " ;
return 0 ;
@ -186,9 +187,10 @@ int strToInt(const ArrayView<char> str) {
return i ;
}
float strToFloat ( const ArrayView < char > str ) {
/* Returns the given string parsed as Float */
Float strToFloat ( const ArrayView < const char > str ) {
char * err ;
const f loat f = strtof ( str . data ( ) , & err ) ;
const F loat f = strtof ( str . data ( ) , & err ) ;
if ( err = = nullptr ) {
Error ( ) < < " Trade::ObjImporter::mesh3D(): error while converting numeric data " ;
return 0 ;
@ -197,10 +199,15 @@ float strToFloat(const ArrayView<char> str) {
return f ;
}
// find first index of c in pos, cancel search at newline or whitespace if flag set.
int findNext ( const ArrayView < char > pos , char c , bool termByNewline = false , bool termByWhitespace = false ) {
const int size = pos . size ( ) ;
for ( int i = 0 ; i < size ; + + i ) {
/*
* Returns the index of the next occurrence of ` c ` or - 1 , if it could not be found .
*
* @ param termByNewline if ` true ` , the search will terminate at ' \n ' and return - 1.
* @ param termByWhitespace if ` true ` , the search will terminate at ' ' and return - 1.
*/
Int findNext ( const ArrayView < const char > pos , char c , bool termByNewline = false , bool termByWhitespace = false ) {
const Int size = pos . size ( ) ;
for ( Int i = 0 ; i < size ; + + i ) {
if ( pos [ i ] = = c ) {
return i ;
}
@ -212,11 +219,13 @@ int findNext(const ArrayView<char> pos, char c, bool termByNewline=false, bool t
return - 1 ;
}
// find next non-whitespace char and return suffix at that point.
// param newlineIsWhitespace if "true", '\n' and '\r' are skipped also
ArrayView < char > skipWhitespaces ( const ArrayView < char > pos , bool newlineIsWhitespace = true ) {
const int size = pos . size ( ) ;
for ( int i = 0 ; i < size ; + + i ) {
/*
* Return suffix beginning at next non - whitespace character
* @ param newlineIsWhitespace if ` true ` , ' \n ' and ' \r ' are skipped also
*/
ArrayView < const char > skipWhitespaces ( const ArrayView < const char > pos , bool newlineIsWhitespace = true ) {
const Int size = pos . size ( ) ;
for ( Int i = 0 ; i < size ; + + i ) {
const char c = pos [ i ] ;
if ( c ! = ' ' & & c ! = ' \t ' & & c ! = ' \0 ' & & ( ! newlineIsWhitespace | | ( c ! = ' \n ' & & c ! = ' \r ' ) ) ) {
return pos . suffix ( i ) ;
@ -225,53 +234,53 @@ ArrayView<char> skipWhitespaces(const ArrayView<char> pos, bool newlineIsWhitesp
return { } ;
}
// returns suffix after next '\n'
ArrayView < char > ignoreLine ( const ArrayView < char > pos ) {
/* Returns suffix after the next '\n' or the given ArrayView if no newline could be found */
ArrayView < const char > ignoreLine ( const ArrayView < const char > pos ) {
return pos . suffix ( findNext ( pos , ' \n ' ) + 1 ) ;
}
// same as ignoreLine, but also returns the content "ignored".
// Different description: Get string until next '\n' and return ArrayView of data
// after it.
std : : tuple < ArrayView < char > , ArrayView < char > > nextLine ( const ArrayView < char > & pos ) {
int i = Math : : min ( findNext ( pos , ' \n ' ) , findNext ( pos , ' \r ' ) ) ;
/* Returns a prefix until the next '\n' and the suffix after the newline. */
std : : pair < ArrayView < const char > , ArrayView < const char > > nextLine ( const ArrayView < const char > & pos ) {
Int i = Math : : min ( findNext ( pos , ' \n ' ) , findNext ( pos , ' \r ' ) ) ;
if ( i = = - 1 ) {
i = pos . size ( ) ;
return std : : make_tuple ( pos . prefix ( i ) , pos . suffix ( i ) ) ;
return { pos . prefix ( i ) , pos . suffix ( i ) } ;
}
return std : : make_tuple ( pos . prefix ( i ) , pos . suffix ( i + 1 ) ) ;
return { pos . prefix ( i ) , pos . suffix ( i + 1 ) } ;
}
bool atEndOfLine ( const ArrayView < char > pos ) {
int i = 0 ;
/* Returns true if the next non-whitespace character is a newline character */
bool atEndOfLine ( const ArrayView < const char > pos ) {
Int i = 0 ;
while ( pos [ i ] = = ' ' ) + + i ;
return ( pos [ i ] = = ' \n ' | | pos [ i ] = = ' \r ' ) ;
}
// get string of content until next ' ' and also return ArrayView for data after the word.
std : : tuple < ArrayView < char > , ArrayView < char > > nextWord ( const ArrayView < char > pos ) {
i nt i = 0 ;
const i nt size = pos . size ( ) ;
/* Returns the prefix until the next ' ' character and the suffix starting with it */
std : : pair < ArrayView < const char > , ArrayView < const char > > nextWord ( const ArrayView < const char > pos ) {
I nt i = 0 ;
const I nt size = pos . size ( ) ;
for ( ; i < size ; + + i ) {
if ( pos [ i ] = = ' ' | | pos [ i ] = = ' \r ' | | pos [ i ] = = ' \n ' | | pos [ i ] = = ' \0 ' ) {
break ;
}
}
return std : : make_tuple ( pos . prefix ( i ) , pos . suffix ( i ) ) ;
return { pos . prefix ( i ) , pos . suffix ( i ) } ;
}
std : : tuple < std : : array < int , 2 > , ArrayView < char > > parseLine ( const ArrayView < char > pos ) {
std : : array < int , 2 > indices { 0 , 0 } ;
ArrayView < char > endpos { } ;
/* Parse indices for a line, e.g. "1/2" */
std : : pair < std : : array < Int , 2 > , ArrayView < const char > > parseLine ( const ArrayView < const char > pos ) {
std : : array < Int , 2 > indices { 0 , 0 } ;
ArrayView < const char > endpos { } ;
i nt i = findNext ( pos , ' / ' , true , true ) ;
I nt i = findNext ( pos , ' / ' , true , true ) ;
if ( i = = - 1 ) {
/* v1 v2 rather than v1/t1 v2/t2 or v1/ v2/ */
ArrayView < char > word ;
ArrayView < const char > word ;
std : : tie ( word , endpos ) = nextWord ( pos ) ;
indices [ 0 ] = strToInt ( word ) ;
return std : : make_tuple ( indices , endpos ) ;
return { indices , endpos } ;
}
indices [ 0 ] = strToInt ( pos . prefix ( i ) ) ;
@ -291,30 +300,28 @@ std::tuple<std::array<int, 2>, ArrayView<char>> parseLine(const ArrayView<char>
}
}
return std : : make_tuple ( indices , endpos ) ;
return { indices , endpos } ;
}
// Parse a "v/n/t" string to indices
// Warning: I'm not handing cases like "v/n", where the normal is not terminated by '/', but ' '!
// Same for "v", where even the normal is omitted.
std : : tuple < std : : array < int , 3 > , ArrayView < char > > parseVertex ( const ArrayView < char > pos ) {
std : : array < int , 3 > indices { 0 , 0 , 0 } ;
ArrayView < char > endpos { } ;
/* Parse a "v/n/t" string to indices for a face */
std : : pair < std : : array < Int , 3 > , ArrayView < const char > > parseVertex ( const ArrayView < const char > pos ) {
std : : array < Int , 3 > indices { 0 , 0 , 0 } ;
ArrayView < const char > endpos { } ;
i nt i = findNext ( pos , ' / ' , true , true ) ;
Int i = findNext ( pos , ' / ' , true , true ) ;
if ( i = = - 1 ) {
/* v1 v2 rather than v1/t1 v2/t2 or v1/ v2/ */
ArrayView < char > word ;
ArrayView < const char > word ;
std : : tie ( word , endpos ) = nextWord ( pos ) ;
indices [ 0 ] = strToInt ( word ) ;
return std : : make_tuple ( indices , endpos ) ;
return { indices , endpos } ;
}
indices [ 0 ] = strToInt ( pos . prefix ( i ) ) ;
endpos = pos . suffix ( i + 1 ) ;
i = findNext ( endpos , ' / ' , true , true ) ;
if ( i ! = - 1 ) { /* t here may not be a normal! Eg. "1//2", in which case the indices of the / are 1 apart */
if ( i ! = - 1 ) { /* T here may not be a normal! Eg. "1//2", in which case the indices of the / are 1 apart */
auto prefix = endpos . prefix ( i ) ;
if ( ! prefix . empty ( ) ) {
indices [ 1 ] = strToInt ( prefix ) ;
@ -322,13 +329,13 @@ std::tuple<std::array<int, 3>, ArrayView<char>> parseVertex(const ArrayView<char
endpos = endpos . suffix ( i + 1 ) ;
}
i = findNext ( endpos , ' ' , true , true ) ; /* t exture coordinates are not terminated by '/', but ' ' or newline */
i = findNext ( endpos , ' ' , true , true ) ; /* T exture coordinates are not terminated by '/', but ' ' or newline */
if ( i = = - 1 )
i = findNext ( endpos , ' \r ' , true , true ) ;
if ( i = = - 1 )
i = findNext ( endpos , ' \n ' , true , true ) ;
if ( i ! = - 1 ) { // there may not be a texCoord! Eg. "1//"
if ( i ! = - 1 ) { /* There may not be a texCoord! Eg. "1//" */
auto prefix = endpos . prefix ( i ) ;
if ( ! prefix . empty ( ) ) {
indices [ 2 ] = strToInt ( prefix ) ;
@ -336,27 +343,26 @@ std::tuple<std::array<int, 3>, ArrayView<char>> parseVertex(const ArrayView<char
}
}
return std : : make_tuple ( indices , endpos ) ;
return { indices , endpos } ;
}
template < UnsignedInt D >
ArrayView < char > ge tVector ( ArrayView < char > pos , Math : : Vector < D , Float > & v ) {
ArrayView < char > word ;
template < UnsignedInt dimensions > Math : : Vector < dimensions , Float > parseVector ( ArrayView < const char > & pos ) {
ArrayView < cons t char > word ;
Math : : Vector < dimensions , Float > v ;
for ( int i = 0 ; i < int ( D ) ; + + i ) {
pos = skipWhitespaces ( pos ) ;
std : : tie ( word , pos ) = nextWord ( pos ) ;
for ( Int i = 0 ; i < Int ( dimensions ) ; + + i ) {
std : : tie ( word , pos ) = nextWord ( skipWhitespaces ( pos ) ) ;
v [ i ] = strToFloat ( word ) ;
}
return pos ;
return v ;
}
template < class T > std : : vector < T > reindex ( const std : : vector < UnsignedInt > & indices , std : : vector < T > & data ) {
template < class T > std : : vector < T > reindex ( const std : : vector < UnsignedInt > & indices , const std : : vector < T > & data ) {
/* Check that indices are in range */
for ( UnsignedInt i : indices ) if ( i > = data . size ( ) ) {
Error ( ) < < " Trade::ObjImporter::mesh3D(): index out of range " ;
throw 0 ;
return { } ;
}
return MeshTools : : duplicate ( indices , data ) ;
@ -372,32 +378,32 @@ ObjImporter::~ObjImporter() = default;
auto ObjImporter : : doFeatures ( ) const - > Features { return Feature : : OpenData ; }
bool ObjImporter : : doIsOpened ( ) const { return _in ; }
void ObjImporter : : doClose ( ) { _state - > in = nullptr ; }
void ObjImporter : : doClose ( ) { _in = nullptr ; }
bool ObjImporter : : doIsOpened ( ) const { return _state - > in ; }
void ObjImporter : : doOpenFile ( const std : : string & filename ) {
_fileRoot = filename . substr ( 0 , filename . find_last_of ( ' / ' ) + 1 ) ;
_state - > fileRoot = Utility : : Directory : : path ( filename ) ;
AbstractImporter : : doOpenFile ( filename ) ;
}
void ObjImporter : : doOpenData ( Containers : : ArrayView < const char > data ) {
_in = Containers : : Array < char > { data . size ( ) } ;
std : : copy ( data . begin ( ) , data . end ( ) , _in . begin ( ) ) ;
_state - > in = Containers : : Array < char > { data . size ( ) } ;
std : : copy ( data . begin ( ) , data . end ( ) , _state - > in . begin ( ) ) ;
_state . reset ( new ImporterState ) ;
parse ( ) ;
}
void ObjImporter : : parse ( ) {
ArrayView < char > line = _in ; /* p oints to beginning of current line */
ArrayView < char > pos = _in ; /* p oints to current character in line */
ArrayView < const char > line = _state - > in ; /* P oints to beginning of current line */
ArrayView < const char > pos = _state - > in ; /* P oints to current character in line */
ObjObject * object = nullptr ;
ObjGroup * group = nullptr ;
ObjMeshData * meshData = nullptr ;
ArrayView < char > section { nullptr } ;
i nt minSectionPrimitives = 0 ;
ArrayView < const char > section { nullptr } ;
I nt minSectionPrimitives = 0 ;
char sectionPrimitive = ' ? ' ;
/* Set index 0 of data to default value */
@ -444,12 +450,12 @@ void ObjImporter::parse() {
ObjMesh * mesh ;
if ( sectionPrimitive = = ' p ' ) {
if ( ! meshData - > poi nts ) {
if ( ! meshData - > poI nts ) {
// TODO: C++ 17
_state - > meshes . emplace_back ( new ObjMesh { * meshData , MeshPrimitive : : Points } ) ;
meshData - > poi nts = _state - > meshes . back ( ) . get ( ) ;
meshData - > poI nts = _state - > meshes . back ( ) . get ( ) ;
}
mesh = meshData - > poi nts ;
mesh = meshData - > poI nts ;
} else if ( sectionPrimitive = = ' l ' ) {
if ( ! meshData - > lines ) {
// TODO: C++ 17
@ -457,13 +463,15 @@ void ObjImporter::parse() {
meshData - > lines = _state - > meshes . back ( ) . get ( ) ;
}
mesh = meshData - > lines ;
} else { /* sectionPrimitive == 'f' */
} else if ( sectionPrimitive = = ' f ' ) {
if ( ! meshData - > faces ) {
// TODO: C++ 17
_state - > meshes . emplace_back ( new ObjMesh { * meshData , MeshPrimitive : : Triangles } ) ;
meshData - > faces = _state - > meshes . back ( ) . get ( ) ;
}
mesh = meshData - > faces ;
} else {
CORRADE_ASSERT_UNREACHABLE ( ) ;
}
if ( line . data ( ) = = nullptr ) {
/* Usually for the last line */
@ -495,7 +503,7 @@ void ObjImporter::parse() {
/* Parse the keyword */
std : : string keyword ;
ArrayView < char > word ;
ArrayView < const char > word ;
std : : tie ( word , pos ) = nextWord ( pos ) ;
keyword = std : : string ( word . data ( ) , word . size ( ) ) ;
@ -504,23 +512,15 @@ void ObjImporter::parse() {
/* Vertex position */
if ( keyword = = " v " ) {
// TODO C++17: Could be one slick line with emplace_back ref return.
Vector3 v ;
pos = getVector < 3 > ( pos , v ) ;
_state - > positions . push_back ( v ) ;
_state - > positions . push_back ( parseVector < 3 > ( pos ) ) ;
/* Texture coordinate */
} else if ( keyword = = " vt " ) {
// TODO C++17: Could be one slick line with emplace_back ref return.
Vector2 tc ;
pos = getVector < 2 > ( pos , tc ) ;
_state - > texCoords . push_back ( tc ) ;
_state - > texCoords . push_back ( parseVector < 2 > ( pos ) ) ;
/* Normal */
} else if ( keyword = = " vn " ) {
// TODO C++17: Could be one slick line with emplace_back ref return.
Vector3 n ;
pos = getVector < 3 > ( pos , n ) ;
_state - > normals . push_back ( n ) ;
_state - > normals . push_back ( parseVector < 3 > ( pos ) ) ;
/* Indices */
} else if ( keyword = = " f " | | keyword = = " l " | | keyword = = " p " ) {
@ -544,7 +544,7 @@ void ObjImporter::parse() {
finishSection ( ) ;
finishObject ( ) ;
ArrayView < char > name ;
ArrayView < const char > name ;
std : : tie ( name , pos ) = nextWord ( pos ) ;
_state - > objects . emplace_back ( new ObjObject { name } ) ;
@ -561,13 +561,13 @@ void ObjImporter::parse() {
meshData = nullptr ;
ArrayView < char > name ;
ArrayView < const char > name ;
std : : tie ( name , pos ) = nextWord ( pos ) ;
group - > name = std : : string { name . data ( ) , name . size ( ) } ;
/* Load a material library */
} else if ( keyword = = " mtllib " ) {
ArrayView < char > word ;
ArrayView < const char > word ;
pos = skipWhitespaces ( pos ) ;
std : : tie ( word , pos ) = nextWord ( pos ) ;
@ -575,11 +575,11 @@ void ObjImporter::parse() {
/* Set current material and add a new mesh for it */
} else if ( keyword = = " usemtl " ) {
ArrayView < char > word ;
ArrayView < const char > word ;
pos = skipWhitespaces ( pos ) ;
std : : tie ( word , pos ) = nextWord ( pos ) ;
const i nt materialIndex = _state - > materialIds [ std : : string { word . data ( ) , word . size ( ) } ] ;
const I nt materialIndex = _state - > materialIds [ std : : string { word . data ( ) , word . size ( ) } ] ;
if ( meshData = = nullptr | | materialIndex ! = meshData - > materialId ) {
/* Switching the material here, need to create a new mesh */
//TODO C++17
@ -603,14 +603,14 @@ void ObjImporter::parse() {
finishSection ( ) ;
finishObject ( ) ;
i nt i = _state - > meshes . size ( ) ;
I nt i = _state - > meshes . size ( ) ;
for ( auto name : _state - > meshlessObjects ) {
_state - > meshlessObjectIds [ name ] = i + + ;
}
}
void ObjImporter : : parseMaterialLibrary ( const ArrayView < char > libname ) {
std : : string filename = _fileRoot + std : : string ( libname . data ( ) , libname . size ( ) ) ;
void ObjImporter : : parseMaterialLibrary ( const ArrayView < const char > libname ) {
std : : string filename = _state - > fileRoot + std : : string ( libname . data ( ) , libname . size ( ) ) ;
/* Open file */
if ( ! Utility : : Directory : : fileExists ( filename ) ) {
@ -619,7 +619,7 @@ void ObjImporter::parseMaterialLibrary(const ArrayView<char> libname) {
}
Containers : : Array < char > contents = Utility : : Directory : : read ( filename ) ;
ArrayView < char > pos = contents ; /* p oints to current character in line */
ArrayView < const char > pos = contents ; /* P oints to current character in line */
ObjMaterial * mat = nullptr ;
@ -633,7 +633,7 @@ void ObjImporter::parseMaterialLibrary(const ArrayView<char> libname) {
}
/* Parse the keyword */
ArrayView < char > word ;
ArrayView < const char > word ;
std : : tie ( word , pos ) = nextWord ( pos ) ;
std : : string keyword { word . data ( ) , word . size ( ) } ;
@ -659,49 +659,49 @@ void ObjImporter::parseMaterialLibrary(const ArrayView<char> libname) {
/* Ambient color */
if ( keyword = = " Ka " ) {
ArrayView < char > word ;
ArrayView < const char > word ;
for ( i nt i : { 0 , 1 , 2 } ) {
for ( I nt i : { 0 , 1 , 2 } ) {
std : : tie ( word , pos ) = nextWord ( pos ) ;
mat - > ambient [ i ] = strToFloat ( word ) ;
}
/* Diffuse color */
} else if ( keyword = = " Kd " ) {
ArrayView < char > word ;
ArrayView < const char > word ;
for ( i nt i : { 0 , 1 , 2 } ) {
for ( I nt i : { 0 , 1 , 2 } ) {
std : : tie ( word , pos ) = nextWord ( pos ) ;
mat - > diffuse [ i ] = strToFloat ( word ) ;
}
/* Specular color */
} else if ( keyword = = " Ks " ) {
ArrayView < char > word ;
ArrayView < const char > word ;
for ( i nt i : { 0 , 1 , 2 } ) {
for ( I nt i : { 0 , 1 , 2 } ) {
std : : tie ( word , pos ) = nextWord ( pos ) ;
mat - > specular [ i ] = strToFloat ( word ) ;
}
/* Specularity */
} else if ( keyword = = " Ns " ) {
ArrayView < char > word ;
ArrayView < const char > word ;
std : : tie ( word , pos ) = nextWord ( pos ) ;
const f loat f = strToFloat ( word ) ;
const F loat f = strToFloat ( word ) ;
mat - > specularity = f ;
/* Ambient texture */
} else if ( keyword . substr ( 0 , 4 ) = = " map_ " ) {
ArrayView < char > line ;
ArrayView < const char > line ;
std : : tie ( line , pos ) = nextLine ( pos ) ;
std : : string texture { line . data ( ) , line . size ( ) } ;
i nt textureId = - 1 ;
I nt textureId = - 1 ;
if ( _state - > textureIds . find ( texture ) = = _state - > textureIds . end ( ) ) {
/* new texture, create it */
i nt index = _state - > textures . size ( ) ;
I nt index = _state - > textures . size ( ) ;
_state - > textures . push_back ( texture ) ;
_state - > textureIds [ texture ] = index ;
@ -731,12 +731,6 @@ void ObjImporter::parseMaterialLibrary(const ArrayView<char> libname) {
}
}
UnsignedInt ObjImporter : : doMesh3DCount ( ) const { return _state - > meshes . size ( ) ; }
UnsignedInt ObjImporter : : doMaterialCount ( ) const { return _state - > materials . size ( ) ; }
UnsignedInt ObjImporter : : doImage2DCount ( ) const { return _state - > textures . size ( ) ; }
UnsignedInt ObjImporter : : doObject3DCount ( ) const { return _state - > meshes . size ( ) + _state - > meshlessObjects . size ( ) ; }
Int ObjImporter : : doObject3DForName ( const std : : string & name ) {
@ -754,23 +748,25 @@ Int ObjImporter::doObject3DForName(const std::string& name) {
}
std : : string ObjImporter : : doObject3DName ( UnsignedInt id ) {
const size_t numMeshes = _state - > meshes . size ( ) ;
if ( id > = numMeshes ) {
return _state - > meshlessObjects [ id - numMeshes ] ;
const size_t lastMesh = _state - > meshes . size ( ) - 1 ;
if ( id > lastMesh ) {
return _state - > meshlessObjects [ id - lastMesh ] ;
}
return _state - > meshes [ id ] - > name ( ) ; /* Intentional, objects are just meshes + material */
return _state - > meshes [ id ] - > name ( ) ;
}
std : : unique_ptr < ObjectData3D > ObjImporter : : doObject3D ( UnsignedInt id ) {
const size_t numMeshes = _state - > meshes . size ( ) ;
if ( id > numMeshes ) {
return std : : unique_ptr < ObjectData3D > { new ObjectData3D { { } , { } , & _state - > meshlessObjects [ id - numMeshes ] } } ;
const size_t lastMesh = _state - > meshes . size ( ) - 1 ;
if ( id > lastMesh ) {
return std : : unique_ptr < ObjectData3D > { new ObjectData3D { { } , { } , & _state - > meshlessObjects [ id - lastMesh ] } } ;
}
const ObjMesh & mesh = * _state - > meshes [ id ] ;
return std : : unique_ptr < ObjectData3D > {
new MeshObjectData3D { { } , { } , id , mesh . data . materialId , _state - > meshes [ id ] . get ( ) } } ;
}
UnsignedInt ObjImporter : : doMesh3DCount ( ) const { return _state - > meshes . size ( ) ; }
Int ObjImporter : : doMesh3DForName ( const std : : string & name ) {
return _state - > meshIds [ name ] ;
}
@ -782,7 +778,7 @@ std::string ObjImporter::doMesh3DName(UnsignedInt id) {
std : : optional < MeshData3D > ObjImporter : : doMesh3D ( UnsignedInt id ) {
const ObjMesh & mesh = * _state - > meshes [ id ] ;
const i nt primitiveSize = ( mesh . primitive = = MeshPrimitive : : Triangles )
const I nt primitiveSize = ( mesh . primitive = = MeshPrimitive : : Triangles )
? 3 : ( ( mesh . primitive = = MeshPrimitive : : Lines ) ? 2 : 1 ) ;
std : : vector < UnsignedInt > positionIndices ;
@ -812,8 +808,8 @@ std::optional<MeshData3D> ObjImporter::doMesh3D(UnsignedInt id) {
CORRADE_ASSERT ( pos [ 0 ] = = ' f ' & & pos [ 1 ] = = ' ' , " Unexpected primitive keyword for Triangles " , { } ) ;
pos = pos . suffix ( 2 ) ;
for ( i nt i = 0 ; i < 3 ; + + i ) {
std : : array < i nt, 3 > vertex ;
for ( I nt i = 0 ; i < 3 ; + + i ) {
std : : array < I nt, 3 > vertex ;
std : : tie ( vertex , pos ) = parseVertex ( pos ) ;
positionIndices . push_back ( vertex [ 0 ] ) ;
textureCoordinateIndices . push_back ( vertex [ 1 ] ) ;
@ -833,7 +829,7 @@ std::optional<MeshData3D> ObjImporter::doMesh3D(UnsignedInt id) {
pos = pos . suffix ( 2 ) ;
while ( ! atEndOfLine ( pos ) ) {
std : : array < i nt, 2 > line ;
std : : array < I nt, 2 > line ;
std : : tie ( line , pos ) = parseLine ( pos ) ;
positionIndices . push_back ( line [ 0 ] ) ;
textureCoordinateIndices . push_back ( line [ 1 ] ) ;
@ -850,7 +846,7 @@ std::optional<MeshData3D> ObjImporter::doMesh3D(UnsignedInt id) {
CORRADE_ASSERT ( pos [ 0 ] = = ' p ' & & pos [ 1 ] = = ' ' , " Unexpected primitive keyword for Points " , { } ) ;
pos = pos . suffix ( 2 ) ;
ArrayView < char > word ;
ArrayView < const char > word ;
while ( ! atEndOfLine ( pos ) ) {
std : : tie ( word , pos ) = nextWord ( pos ) ;
positionIndices . push_back ( strToInt ( word ) ) ;
@ -879,19 +875,16 @@ std::optional<MeshData3D> ObjImporter::doMesh3D(UnsignedInt id) {
indices = MeshTools : : combineIndexArrays ( arrays ) ;
/* Reindex data arrays */
try {
positionLayers . push_back ( reindex ( positionIndices , _state - > positions ) ) ;
if ( hasNormals ) normalLayers . push_back ( reindex ( normalIndices , _state - > normals ) ) ;
if ( hasTexCoords ) texCoordLayers . push_back ( reindex ( textureCoordinateIndices , _state - > texCoords ) ) ;
} catch ( . . . ) {
/* Error message already printed */
return std : : nullopt ;
}
return MeshData3D ( mesh . primitive , std : : move ( indices ) , std : : move ( positionLayers ) ,
std : : move ( normalLayers ) , std : : move ( texCoordLayers ) , { } , & mesh ) ;
}
UnsignedInt ObjImporter : : doMaterialCount ( ) const { return _state - > materials . size ( ) ; }
std : : unique_ptr < AbstractMaterialData > ObjImporter : : doMaterial ( const UnsignedInt id ) {
ObjMaterial & objMat = _state - > materials [ id ] ;
PhongMaterialData : : Flags flags ;
@ -931,11 +924,13 @@ std::unique_ptr<AbstractMaterialData> ObjImporter::doMaterial(const UnsignedInt
return std : : unique_ptr < AbstractMaterialData > ( mat ) ;
}
UnsignedInt ObjImporter : : doImage2DCount ( ) const { return _state - > textures . size ( ) ; }
std : : optional < ImageData2D > ObjImporter : : doImage2D ( UnsignedInt id ) {
CORRADE_ASSERT ( manager ( ) , " Trade::ObjImporter::image2D(): the plugin must be instantiated with access to plugin manager in order to open image files " , { } ) ;
std : : unique_ptr < AbstractImporter > imageImporter = manager ( ) - > loadAndInstantiate ( " TgaImporter " ) ; // probably AnyImageImporter would be the way to go here...
if ( ! imageImporter - > openFile ( _fileRoot + _state - > textures [ id ] ) ) {
if ( ! imageImporter - > openFile ( _state - > fileRoot + _state - > textures [ id ] ) ) {
return std : : nullopt ;
}