2016-10-03 17:24:14 +00:00
/*
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Open Asset Import Library ( assimp )
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2017-05-09 17:57:36 +00:00
Copyright ( c ) 2006 - 2017 , assimp team
2016-10-03 17:24:14 +00:00
All rights reserved .
Redistribution and use of this software in source and binary forms ,
with or without modification , are permitted provided that the following
conditions are met :
* Redistributions of source code must retain the above
copyright notice , this list of conditions and the
following disclaimer .
* Redistributions in binary form must reproduce the above
copyright notice , this list of conditions and the
following disclaimer in the documentation and / or other
materials provided with the distribution .
* Neither the name of the assimp team , nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
" AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL ,
SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT
LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
/// \file AMFImporter_Postprocess.cpp
2016-09-28 14:49:15 +00:00
/// \brief Convert built scenegraph and objects to Assimp scenegraph.
/// \date 2016
/// \author smal.root@gmail.com
# ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
# include "AMFImporter.hpp"
// Header files, Assimp.
# include "SceneCombiner.h"
# include "StandardShapes.h"
2016-10-15 19:45:58 +00:00
# include "StringUtils.h"
2016-09-28 14:49:15 +00:00
// Header files, stdlib.
# include <iterator>
namespace Assimp
{
aiColor4D AMFImporter : : SPP_Material : : GetColor ( const float pX , const float pY , const float pZ ) const
{
2017-02-22 16:20:26 +00:00
aiColor4D tcol ;
2016-09-28 14:49:15 +00:00
// Check if stored data are supported.
if ( Composition . size ( ) ! = 0 )
{
throw DeadlyImportError ( " IME. GetColor for composition " ) ;
}
else if ( Color - > Composed )
{
throw DeadlyImportError ( " IME. GetColor, composed color " ) ;
}
else
{
tcol = Color - > Color ;
}
// Check if default color must be used
if ( ( tcol . r = = 0 ) & & ( tcol . g = = 0 ) & & ( tcol . b = = 0 ) & & ( tcol . a = = 0 ) )
{
tcol . r = 0.5f ;
tcol . g = 0.5f ;
tcol . b = 0.5f ;
tcol . a = 1 ;
}
return tcol ;
}
void AMFImporter : : PostprocessHelper_CreateMeshDataArray ( const CAMFImporter_NodeElement_Mesh & pNodeElement , std : : vector < aiVector3D > & pVertexCoordinateArray ,
std : : vector < CAMFImporter_NodeElement_Color * > & pVertexColorArray ) const
{
2017-02-22 16:20:26 +00:00
CAMFImporter_NodeElement_Vertices * vn = nullptr ;
size_t col_idx ;
2016-09-28 14:49:15 +00:00
// All data stored in "vertices", search for it.
2016-09-29 15:04:31 +00:00
for ( CAMFImporter_NodeElement * ne_child : pNodeElement . Child )
2016-09-28 14:49:15 +00:00
{
2016-09-29 15:04:31 +00:00
if ( ne_child - > Type = = CAMFImporter_NodeElement : : ENET_Vertices ) vn = ( CAMFImporter_NodeElement_Vertices * ) ne_child ;
2016-09-28 14:49:15 +00:00
}
2016-09-29 15:04:31 +00:00
2016-09-28 14:49:15 +00:00
// If "vertices" not found then no work for us.
2016-09-29 15:04:31 +00:00
if ( vn = = nullptr ) return ;
2016-09-28 14:49:15 +00:00
pVertexCoordinateArray . reserve ( vn - > Child . size ( ) ) ; // all coordinates stored as child and we need to reserve space for future push_back's.
pVertexColorArray . resize ( vn - > Child . size ( ) ) ; // colors count equal vertices count.
col_idx = 0 ;
// Inside vertices collect all data and place to arrays
2016-09-29 15:04:31 +00:00
for ( CAMFImporter_NodeElement * vn_child : vn - > Child )
2016-09-28 14:49:15 +00:00
{
// vertices, colors
2016-09-29 15:04:31 +00:00
if ( vn_child - > Type = = CAMFImporter_NodeElement : : ENET_Vertex )
2016-09-28 14:49:15 +00:00
{
// by default clear color for current vertex
2016-09-29 15:04:31 +00:00
pVertexColorArray [ col_idx ] = nullptr ;
2016-09-28 14:49:15 +00:00
2016-09-29 15:04:31 +00:00
for ( CAMFImporter_NodeElement * vtx : vn_child - > Child )
2016-09-28 14:49:15 +00:00
{
2016-09-29 15:04:31 +00:00
if ( vtx - > Type = = CAMFImporter_NodeElement : : ENET_Coordinates )
2016-09-28 14:49:15 +00:00
{
2016-09-29 15:04:31 +00:00
pVertexCoordinateArray . push_back ( ( ( CAMFImporter_NodeElement_Coordinates * ) vtx ) - > Coordinate ) ;
2016-09-28 14:49:15 +00:00
continue ;
2016-09-29 15:04:31 +00:00
}
2016-09-28 14:49:15 +00:00
2016-09-29 15:04:31 +00:00
if ( vtx - > Type = = CAMFImporter_NodeElement : : ENET_Color )
2016-09-28 14:49:15 +00:00
{
2016-09-29 15:04:31 +00:00
pVertexColorArray [ col_idx ] = ( CAMFImporter_NodeElement_Color * ) vtx ;
2016-09-28 14:49:15 +00:00
continue ;
2016-09-29 15:04:31 +00:00
}
} // for(CAMFImporter_NodeElement* vtx: vn_child->Child)
2016-09-28 14:49:15 +00:00
col_idx + + ;
2016-09-29 15:04:31 +00:00
} // if(vn_child->Type == CAMFImporter_NodeElement::ENET_Vertex)
} // for(CAMFImporter_NodeElement* vn_child: vn->Child)
2016-09-28 14:49:15 +00:00
}
size_t AMFImporter : : PostprocessHelper_GetTextureID_Or_Create ( const std : : string & pID_R , const std : : string & pID_G , const std : : string & pID_B ,
const std : : string & pID_A )
{
2017-02-22 16:20:26 +00:00
size_t TextureConverted_Index ;
std : : string TextureConverted_ID ;
2016-09-28 14:49:15 +00:00
// check input data
if ( pID_R . empty ( ) & & pID_G . empty ( ) & & pID_B . empty ( ) & & pID_A . empty ( ) )
throw DeadlyImportError ( " PostprocessHelper_GetTextureID_Or_Create. At least one texture ID must be defined. " ) ;
// Create ID
TextureConverted_ID = pID_R + " _ " + pID_G + " _ " + pID_B + " _ " + pID_A ;
// Check if texture specified by set of IDs is converted already.
TextureConverted_Index = 0 ;
for ( const SPP_Texture & tex_convd : mTexture_Converted )
{
if ( tex_convd . ID = = TextureConverted_ID )
return TextureConverted_Index ;
else
TextureConverted_Index + + ;
}
//
// Converted texture not found, create it.
//
2016-09-29 21:03:34 +00:00
CAMFImporter_NodeElement_Texture * src_texture [ 4 ] { nullptr } ;
std : : vector < CAMFImporter_NodeElement_Texture * > src_texture_4check ;
2016-09-28 14:49:15 +00:00
SPP_Texture converted_texture ;
{ // find all specified source textures
2016-09-29 21:03:34 +00:00
CAMFImporter_NodeElement * t_tex ;
2016-09-28 14:49:15 +00:00
// R
if ( ! pID_R . empty ( ) )
{
2016-09-29 21:03:34 +00:00
if ( ! Find_NodeElement ( pID_R , CAMFImporter_NodeElement : : ENET_Texture , & t_tex ) ) Throw_ID_NotFound ( pID_R ) ;
2016-09-28 14:49:15 +00:00
2016-09-29 21:03:34 +00:00
src_texture [ 0 ] = ( CAMFImporter_NodeElement_Texture * ) t_tex ;
src_texture_4check . push_back ( ( CAMFImporter_NodeElement_Texture * ) t_tex ) ;
2016-09-28 14:49:15 +00:00
}
else
{
src_texture [ 0 ] = nullptr ;
}
// G
if ( ! pID_G . empty ( ) )
{
2016-09-29 21:03:34 +00:00
if ( ! Find_NodeElement ( pID_G , CAMFImporter_NodeElement : : ENET_Texture , & t_tex ) ) Throw_ID_NotFound ( pID_G ) ;
2016-09-28 14:49:15 +00:00
2016-09-29 21:03:34 +00:00
src_texture [ 1 ] = ( CAMFImporter_NodeElement_Texture * ) t_tex ;
src_texture_4check . push_back ( ( CAMFImporter_NodeElement_Texture * ) t_tex ) ;
2016-09-28 14:49:15 +00:00
}
else
{
src_texture [ 1 ] = nullptr ;
}
// B
if ( ! pID_B . empty ( ) )
{
2016-09-29 21:03:34 +00:00
if ( ! Find_NodeElement ( pID_B , CAMFImporter_NodeElement : : ENET_Texture , & t_tex ) ) Throw_ID_NotFound ( pID_B ) ;
2016-09-28 14:49:15 +00:00
2016-09-29 21:03:34 +00:00
src_texture [ 2 ] = ( CAMFImporter_NodeElement_Texture * ) t_tex ;
src_texture_4check . push_back ( ( CAMFImporter_NodeElement_Texture * ) t_tex ) ;
2016-09-28 14:49:15 +00:00
}
else
{
src_texture [ 2 ] = nullptr ;
}
// A
if ( ! pID_A . empty ( ) )
{
2016-09-29 21:03:34 +00:00
if ( ! Find_NodeElement ( pID_A , CAMFImporter_NodeElement : : ENET_Texture , & t_tex ) ) Throw_ID_NotFound ( pID_A ) ;
2016-09-28 14:49:15 +00:00
2016-09-29 21:03:34 +00:00
src_texture [ 3 ] = ( CAMFImporter_NodeElement_Texture * ) t_tex ;
src_texture_4check . push_back ( ( CAMFImporter_NodeElement_Texture * ) t_tex ) ;
2016-09-28 14:49:15 +00:00
}
else
{
src_texture [ 3 ] = nullptr ;
}
} // END: find all specified source textures
// check that all textures has same size
if ( src_texture_4check . size ( ) > 1 )
{
2016-11-03 17:37:02 +00:00
for ( size_t i = 0 , i_e = ( src_texture_4check . size ( ) - 1 ) ; i < i_e ; i + + )
2016-09-28 14:49:15 +00:00
{
if ( ( src_texture_4check [ i ] - > Width ! = src_texture_4check [ i + 1 ] - > Width ) | | ( src_texture_4check [ i ] - > Height ! = src_texture_4check [ i + 1 ] - > Height ) | |
( src_texture_4check [ i ] - > Depth ! = src_texture_4check [ i + 1 ] - > Depth ) )
{
throw DeadlyImportError ( " PostprocessHelper_GetTextureID_Or_Create. Source texture must has the same size. " ) ;
}
}
} // if(src_texture_4check.size() > 1)
// set texture attributes
converted_texture . Width = src_texture_4check [ 0 ] - > Width ;
converted_texture . Height = src_texture_4check [ 0 ] - > Height ;
converted_texture . Depth = src_texture_4check [ 0 ] - > Depth ;
// if one of source texture is tiled then converted texture is tiled too.
converted_texture . Tiled = false ;
for ( uint8_t i = 0 ; i < src_texture_4check . size ( ) ; i + + ) converted_texture . Tiled | = src_texture_4check [ i ] - > Tiled ;
// Create format hint.
strcpy ( converted_texture . FormatHint , " rgba0000 " ) ; // copy initial string.
if ( ! pID_R . empty ( ) ) converted_texture . FormatHint [ 4 ] = ' 8 ' ;
2016-09-29 14:11:53 +00:00
if ( ! pID_G . empty ( ) ) converted_texture . FormatHint [ 5 ] = ' 8 ' ;
if ( ! pID_B . empty ( ) ) converted_texture . FormatHint [ 6 ] = ' 8 ' ;
if ( ! pID_A . empty ( ) ) converted_texture . FormatHint [ 7 ] = ' 8 ' ;
2016-09-28 14:49:15 +00:00
//
// С opy data of textures.
//
size_t tex_size = 0 ;
size_t step = 0 ;
size_t off_g = 0 ;
size_t off_b = 0 ;
// Calculate size of the target array and rule how data will be copied.
2017-05-09 19:03:20 +00:00
if ( ! pID_R . empty ( ) & & nullptr ! = src_texture [ 0 ] ) {
tex_size + = src_texture [ 0 ] - > Data . size ( ) ; step + + , off_g + + , off_b + + ;
2017-02-04 17:15:50 +00:00
}
2017-05-09 19:03:20 +00:00
if ( ! pID_G . empty ( ) & & nullptr ! = src_texture [ 1 ] ) {
tex_size + = src_texture [ 1 ] - > Data . size ( ) ; step + + , off_b + + ;
}
if ( ! pID_B . empty ( ) & & nullptr ! = src_texture [ 2 ] ) {
tex_size + = src_texture [ 2 ] - > Data . size ( ) ; step + + ;
}
if ( ! pID_A . empty ( ) & & nullptr ! = src_texture [ 3 ] ) {
tex_size + = src_texture [ 3 ] - > Data . size ( ) ; step + + ;
}
// Create target array.
2016-09-28 14:49:15 +00:00
converted_texture . Data = new uint8_t [ tex_size ] ;
// And copy data
auto CopyTextureData = [ & ] ( const std : : string & pID , const size_t pOffset , const size_t pStep , const uint8_t pSrcTexNum ) - > void
{
if ( ! pID . empty ( ) )
{
for ( size_t idx_target = pOffset , idx_src = 0 ; idx_target < tex_size ; idx_target + = pStep , idx_src + + )
converted_texture . Data [ idx_target ] = src_texture [ pSrcTexNum ] - > Data . at ( idx_src ) ;
}
} ; // auto CopyTextureData = [&](const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void
CopyTextureData ( pID_R , 0 , step , 0 ) ;
CopyTextureData ( pID_G , off_g , step , 1 ) ;
CopyTextureData ( pID_B , off_b , step , 2 ) ;
CopyTextureData ( pID_A , step - 1 , step , 3 ) ;
// Store new converted texture ID
converted_texture . ID = TextureConverted_ID ;
// Store new converted texture
mTexture_Converted . push_back ( converted_texture ) ;
return TextureConverted_Index ;
}
void AMFImporter : : PostprocessHelper_SplitFacesByTextureID ( std : : list < SComplexFace > & pInputList , std : : list < std : : list < SComplexFace > > & pOutputList_Separated )
{
2017-02-22 16:20:26 +00:00
auto texmap_is_equal = [ ] ( const CAMFImporter_NodeElement_TexMap * pTexMap1 , const CAMFImporter_NodeElement_TexMap * pTexMap2 ) - > bool
{
if ( ( pTexMap1 = = nullptr ) & & ( pTexMap2 = = nullptr ) ) return true ;
if ( pTexMap1 = = nullptr ) return false ;
if ( pTexMap2 = = nullptr ) return false ;
if ( pTexMap1 - > TextureID_R ! = pTexMap2 - > TextureID_R ) return false ;
if ( pTexMap1 - > TextureID_G ! = pTexMap2 - > TextureID_G ) return false ;
if ( pTexMap1 - > TextureID_B ! = pTexMap2 - > TextureID_B ) return false ;
if ( pTexMap1 - > TextureID_A ! = pTexMap2 - > TextureID_A ) return false ;
return true ;
} ;
2016-09-28 14:49:15 +00:00
pOutputList_Separated . clear ( ) ;
if ( pInputList . size ( ) = = 0 ) return ;
do
{
SComplexFace face_start = pInputList . front ( ) ;
std : : list < SComplexFace > face_list_cur ;
2016-09-29 23:12:46 +00:00
for ( std : : list < SComplexFace > : : iterator it = pInputList . begin ( ) , it_end = pInputList . end ( ) ; it ! = it_end ; )
2016-09-28 14:49:15 +00:00
{
if ( texmap_is_equal ( face_start . TexMap , it - > TexMap ) )
{
auto it_old = it ;
it + + ;
face_list_cur . push_back ( * it_old ) ;
pInputList . erase ( it_old ) ;
}
else
{
it + + ;
}
}
if ( face_list_cur . size ( ) > 0 ) pOutputList_Separated . push_back ( face_list_cur ) ;
} while ( pInputList . size ( ) > 0 ) ;
}
2016-11-22 20:06:14 +00:00
void AMFImporter : : Postprocess_AddMetadata ( const std : : list < CAMFImporter_NodeElement_Metadata * > & metadataList , aiNode & sceneNode ) const
2016-09-28 14:49:15 +00:00
{
2016-11-22 20:06:14 +00:00
if ( ! metadataList . empty ( ) )
2016-09-28 14:49:15 +00:00
{
2016-11-22 20:06:14 +00:00
if ( sceneNode . mMetaData ! = nullptr ) throw DeadlyImportError ( " Postprocess. MetaData member in node are not nullptr. Something went wrong. " ) ;
2016-09-28 14:49:15 +00:00
// copy collected metadata to output node.
2016-11-23 11:24:04 +00:00
sceneNode . mMetaData = aiMetadata : : Alloc ( static_cast < unsigned int > ( metadataList . size ( ) ) ) ;
2016-11-22 20:06:14 +00:00
size_t meta_idx ( 0 ) ;
2016-09-28 14:49:15 +00:00
2016-11-22 20:06:14 +00:00
for ( const CAMFImporter_NodeElement_Metadata & metadata : metadataList )
2016-09-28 14:49:15 +00:00
{
2016-11-23 11:24:04 +00:00
sceneNode . mMetaData - > Set ( static_cast < unsigned int > ( meta_idx + + ) , metadata . Type , aiString ( metadata . Value ) ) ;
2016-09-28 14:49:15 +00:00
}
2016-11-22 20:06:14 +00:00
} // if(!metadataList.empty())
2016-09-28 14:49:15 +00:00
}
void AMFImporter : : Postprocess_BuildNodeAndObject ( const CAMFImporter_NodeElement_Object & pNodeElement , std : : list < aiMesh * > & pMeshList , aiNode * * pSceneNode )
{
2016-09-29 15:04:31 +00:00
CAMFImporter_NodeElement_Color * object_color = nullptr ;
2016-09-28 14:49:15 +00:00
// create new aiNode and set name as <object> has.
* pSceneNode = new aiNode ;
( * pSceneNode ) - > mName = pNodeElement . ID ;
// read mesh and color
2016-09-29 15:04:31 +00:00
for ( const CAMFImporter_NodeElement * ne_child : pNodeElement . Child )
2016-09-28 14:49:15 +00:00
{
std : : vector < aiVector3D > vertex_arr ;
std : : vector < CAMFImporter_NodeElement_Color * > color_arr ;
// color for object
2016-09-29 15:04:31 +00:00
if ( ne_child - > Type = = CAMFImporter_NodeElement : : ENET_Color ) object_color = ( CAMFImporter_NodeElement_Color * ) ne_child ;
2016-09-28 14:49:15 +00:00
2016-09-29 15:04:31 +00:00
if ( ne_child - > Type = = CAMFImporter_NodeElement : : ENET_Mesh )
2016-09-28 14:49:15 +00:00
{
// Create arrays from children of mesh: vertices.
2016-09-29 15:04:31 +00:00
PostprocessHelper_CreateMeshDataArray ( * ( ( CAMFImporter_NodeElement_Mesh * ) ne_child ) , vertex_arr , color_arr ) ;
2016-09-28 14:49:15 +00:00
// Use this arrays as a source when creating every aiMesh
2016-09-29 15:04:31 +00:00
Postprocess_BuildMeshSet ( * ( ( CAMFImporter_NodeElement_Mesh * ) ne_child ) , vertex_arr , color_arr , object_color , pMeshList , * * pSceneNode ) ;
}
} // for(const CAMFImporter_NodeElement* ne_child: pNodeElement)
2016-09-28 14:49:15 +00:00
}
void AMFImporter : : Postprocess_BuildMeshSet ( const CAMFImporter_NodeElement_Mesh & pNodeElement , const std : : vector < aiVector3D > & pVertexCoordinateArray ,
const std : : vector < CAMFImporter_NodeElement_Color * > & pVertexColorArray ,
const CAMFImporter_NodeElement_Color * pObjectColor , std : : list < aiMesh * > & pMeshList , aiNode & pSceneNode )
{
std : : list < unsigned int > mesh_idx ;
// all data stored in "volume", search for it.
2016-09-29 21:03:34 +00:00
for ( const CAMFImporter_NodeElement * ne_child : pNodeElement . Child )
2016-09-28 14:49:15 +00:00
{
2016-09-29 21:03:34 +00:00
const CAMFImporter_NodeElement_Color * ne_volume_color = nullptr ;
2016-09-28 14:49:15 +00:00
const SPP_Material * cur_mat = nullptr ;
2016-09-29 21:03:34 +00:00
if ( ne_child - > Type = = CAMFImporter_NodeElement : : ENET_Volume )
2016-09-28 14:49:15 +00:00
{
/******************* Get faces *******************/
const CAMFImporter_NodeElement_Volume * ne_volume = reinterpret_cast < const CAMFImporter_NodeElement_Volume * > ( ne_child ) ;
2016-09-29 21:03:34 +00:00
std : : list < SComplexFace > complex_faces_list ; // List of the faces of the volume.
std : : list < std : : list < SComplexFace > > complex_faces_toplist ; // List of the face list for every mesh.
2016-09-28 14:49:15 +00:00
// check if volume use material
if ( ! ne_volume - > MaterialID . empty ( ) )
{
if ( ! Find_ConvertedMaterial ( ne_volume - > MaterialID , & cur_mat ) ) Throw_ID_NotFound ( ne_volume - > MaterialID ) ;
}
// inside "volume" collect all data and place to arrays or create new objects
2016-09-29 21:03:34 +00:00
for ( const CAMFImporter_NodeElement * ne_volume_child : ne_volume - > Child )
2016-09-28 14:49:15 +00:00
{
// color for volume
2016-09-29 21:03:34 +00:00
if ( ne_volume_child - > Type = = CAMFImporter_NodeElement : : ENET_Color )
2016-09-28 14:49:15 +00:00
{
2016-09-29 21:03:34 +00:00
ne_volume_color = reinterpret_cast < const CAMFImporter_NodeElement_Color * > ( ne_volume_child ) ;
2016-09-28 14:49:15 +00:00
}
2016-09-29 21:03:34 +00:00
else if ( ne_volume_child - > Type = = CAMFImporter_NodeElement : : ENET_Triangle ) // triangles, triangles colors
2016-09-28 14:49:15 +00:00
{
const CAMFImporter_NodeElement_Triangle & tri_al = * reinterpret_cast < const CAMFImporter_NodeElement_Triangle * > ( ne_volume_child ) ;
SComplexFace complex_face ;
// initialize pointers
complex_face . Color = nullptr ;
complex_face . TexMap = nullptr ;
// get data from triangle children: color, texture coordinates.
if ( tri_al . Child . size ( ) )
{
2016-09-29 21:03:34 +00:00
for ( const CAMFImporter_NodeElement * ne_triangle_child : tri_al . Child )
2016-09-28 14:49:15 +00:00
{
2016-09-29 21:03:34 +00:00
if ( ne_triangle_child - > Type = = CAMFImporter_NodeElement : : ENET_Color )
complex_face . Color = reinterpret_cast < const CAMFImporter_NodeElement_Color * > ( ne_triangle_child ) ;
else if ( ne_triangle_child - > Type = = CAMFImporter_NodeElement : : ENET_TexMap )
complex_face . TexMap = reinterpret_cast < const CAMFImporter_NodeElement_TexMap * > ( ne_triangle_child ) ;
2016-09-28 14:49:15 +00:00
}
} // if(tri_al.Child.size())
// create new face and store it.
complex_face . Face . mNumIndices = 3 ;
complex_face . Face . mIndices = new unsigned int [ 3 ] ;
2016-11-18 13:31:32 +00:00
complex_face . Face . mIndices [ 0 ] = static_cast < unsigned int > ( tri_al . V [ 0 ] ) ;
complex_face . Face . mIndices [ 1 ] = static_cast < unsigned int > ( tri_al . V [ 1 ] ) ;
complex_face . Face . mIndices [ 2 ] = static_cast < unsigned int > ( tri_al . V [ 2 ] ) ;
2016-09-28 14:49:15 +00:00
complex_faces_list . push_back ( complex_face ) ;
}
2016-09-29 21:03:34 +00:00
} // for(const CAMFImporter_NodeElement* ne_volume_child: ne_volume->Child)
2016-09-28 14:49:15 +00:00
/**** Split faces list: one list per mesh ****/
PostprocessHelper_SplitFacesByTextureID ( complex_faces_list , complex_faces_toplist ) ;
/***** Create mesh for every faces list ******/
2016-09-29 21:03:34 +00:00
for ( std : : list < SComplexFace > & face_list_cur : complex_faces_toplist )
2016-09-28 14:49:15 +00:00
{
2016-09-29 21:03:34 +00:00
auto VertexIndex_GetMinimal = [ ] ( const std : : list < SComplexFace > & pFaceList , const size_t * pBiggerThan ) - > size_t
2016-09-28 14:49:15 +00:00
{
size_t rv ;
if ( pBiggerThan ! = nullptr )
{
bool found = false ;
for ( const SComplexFace & face : pFaceList )
{
for ( size_t idx_vert = 0 ; idx_vert < face . Face . mNumIndices ; idx_vert + + )
{
if ( face . Face . mIndices [ idx_vert ] > * pBiggerThan )
{
rv = face . Face . mIndices [ idx_vert ] ;
found = true ;
break ;
}
}
if ( found ) break ;
}
if ( ! found ) return * pBiggerThan ;
}
else
{
rv = pFaceList . front ( ) . Face . mIndices [ 0 ] ;
} // if(pBiggerThan != nullptr) else
for ( const SComplexFace & face : pFaceList )
{
for ( size_t vi = 0 ; vi < face . Face . mNumIndices ; vi + + )
{
if ( face . Face . mIndices [ vi ] < rv )
{
if ( pBiggerThan ! = nullptr )
{
if ( face . Face . mIndices [ vi ] > * pBiggerThan ) rv = face . Face . mIndices [ vi ] ;
}
else
{
rv = face . Face . mIndices [ vi ] ;
}
}
}
} // for(const SComplexFace& face: pFaceList)
return rv ;
2016-09-29 21:03:34 +00:00
} ; // auto VertexIndex_GetMinimal = [](const std::list<SComplexFace>& pFaceList, const size_t* pBiggerThan) -> size_t
2016-09-28 14:49:15 +00:00
2016-09-29 21:03:34 +00:00
auto VertexIndex_Replace = [ ] ( std : : list < SComplexFace > & pFaceList , const size_t pIdx_From , const size_t pIdx_To ) - > void
2016-09-28 14:49:15 +00:00
{
for ( const SComplexFace & face : pFaceList )
{
for ( size_t vi = 0 ; vi < face . Face . mNumIndices ; vi + + )
{
2016-11-18 13:31:32 +00:00
if ( face . Face . mIndices [ vi ] = = pIdx_From ) face . Face . mIndices [ vi ] = static_cast < unsigned int > ( pIdx_To ) ;
2016-09-28 14:49:15 +00:00
}
}
2016-09-29 21:03:34 +00:00
} ; // auto VertexIndex_Replace = [](std::list<SComplexFace>& pFaceList, const size_t pIdx_From, const size_t pIdx_To) -> void
2016-09-28 14:49:15 +00:00
auto Vertex_CalculateColor = [ & ] ( const size_t pIdx ) - > aiColor4D
{
// Color priorities(In descending order):
// 1. triangle color;
// 2. vertex color;
// 3. volume color;
// 4. object color;
// 5. material;
// 6. default - invisible coat.
//
// Fill vertices colors in color priority list above that's points from 1 to 6.
if ( ( pIdx < pVertexColorArray . size ( ) ) & & ( pVertexColorArray [ pIdx ] ! = nullptr ) ) // check for vertex color
{
if ( pVertexColorArray [ pIdx ] - > Composed )
throw DeadlyImportError ( " IME: vertex color composed " ) ;
else
return pVertexColorArray [ pIdx ] - > Color ;
}
else if ( ne_volume_color ! = nullptr ) // check for volume color
{
if ( ne_volume_color - > Composed )
throw DeadlyImportError ( " IME: volume color composed " ) ;
else
return ne_volume_color - > Color ;
}
else if ( pObjectColor ! = nullptr ) // check for object color
{
if ( pObjectColor - > Composed )
throw DeadlyImportError ( " IME: object color composed " ) ;
else
return pObjectColor - > Color ;
}
else if ( cur_mat ! = nullptr ) // check for material
{
return cur_mat - > GetColor ( pVertexCoordinateArray . at ( pIdx ) . x , pVertexCoordinateArray . at ( pIdx ) . y , pVertexCoordinateArray . at ( pIdx ) . z ) ;
}
else // set default color.
{
return { 0 , 0 , 0 , 0 } ;
2016-09-29 15:04:31 +00:00
} // if((vi < pVertexColorArray.size()) && (pVertexColorArray[vi] != nullptr)) else
2016-09-28 14:49:15 +00:00
} ; // auto Vertex_CalculateColor = [&](const size_t pIdx) -> aiColor4D
aiMesh * tmesh = new aiMesh ;
tmesh - > mPrimitiveTypes = aiPrimitiveType_TRIANGLE ; // Only triangles is supported by AMF.
//
// set geometry and colors (vertices)
//
// copy faces/triangles
2016-11-18 13:31:32 +00:00
tmesh - > mNumFaces = static_cast < unsigned int > ( face_list_cur . size ( ) ) ;
2016-09-28 14:49:15 +00:00
tmesh - > mFaces = new aiFace [ tmesh - > mNumFaces ] ;
// Create vertices list and optimize indices. Optimisation mean following.In AMF all volumes use one big list of vertices. And one volume
// can use only part of vertices list, for example: vertices list contain few thousands of vertices and volume use vertices 1, 3, 10.
// Do you need all this thousands of garbage? Of course no. So, optimisation step transformate sparse indices set to continuous.
2016-09-29 23:12:46 +00:00
size_t VertexCount_Max = tmesh - > mNumFaces * 3 ; // 3 - triangles.
2016-09-28 14:49:15 +00:00
std : : vector < aiVector3D > vert_arr , texcoord_arr ;
std : : vector < aiColor4D > col_arr ;
vert_arr . reserve ( VertexCount_Max * 2 ) ; // "* 2" - see below TODO.
col_arr . reserve ( VertexCount_Max * 2 ) ;
{ // fill arrays
size_t vert_idx_from , vert_idx_to ;
// first iteration.
vert_idx_to = 0 ;
vert_idx_from = VertexIndex_GetMinimal ( face_list_cur , nullptr ) ;
vert_arr . push_back ( pVertexCoordinateArray . at ( vert_idx_from ) ) ;
col_arr . push_back ( Vertex_CalculateColor ( vert_idx_from ) ) ;
if ( vert_idx_from ! = vert_idx_to ) VertexIndex_Replace ( face_list_cur , vert_idx_from , vert_idx_to ) ;
// rest iterations
do
{
vert_idx_from = VertexIndex_GetMinimal ( face_list_cur , & vert_idx_to ) ;
2016-12-08 02:31:51 +00:00
if ( vert_idx_from = = vert_idx_to ) break ; // all indices are transferred,
2016-09-28 14:49:15 +00:00
vert_arr . push_back ( pVertexCoordinateArray . at ( vert_idx_from ) ) ;
col_arr . push_back ( Vertex_CalculateColor ( vert_idx_from ) ) ;
vert_idx_to + + ;
if ( vert_idx_from ! = vert_idx_to ) VertexIndex_Replace ( face_list_cur , vert_idx_from , vert_idx_to ) ;
} while ( true ) ;
} // fill arrays. END.
//
// check if triangle colors are used and create additional faces if needed.
//
for ( const SComplexFace & face_cur : face_list_cur )
{
if ( face_cur . Color ! = nullptr )
{
aiColor4D face_color ;
size_t vert_idx_new = vert_arr . size ( ) ;
if ( face_cur . Color - > Composed )
throw DeadlyImportError ( " IME: face color composed " ) ;
else
face_color = face_cur . Color - > Color ;
for ( size_t idx_ind = 0 ; idx_ind < face_cur . Face . mNumIndices ; idx_ind + + )
{
vert_arr . push_back ( vert_arr . at ( face_cur . Face . mIndices [ idx_ind ] ) ) ;
col_arr . push_back ( face_color ) ;
2016-11-18 13:31:32 +00:00
face_cur . Face . mIndices [ idx_ind ] = static_cast < unsigned int > ( vert_idx_new + + ) ;
2016-09-28 14:49:15 +00:00
}
} // if(face_cur.Color != nullptr)
} // for(const SComplexFace& face_cur: face_list_cur)
//
// if texture is used then copy texture coordinates too.
//
if ( face_list_cur . front ( ) . TexMap ! = nullptr )
{
size_t idx_vert_new = vert_arr . size ( ) ;
///TODO: clean unused vertices. "* 2": in certain cases - mesh full of triangle colors - vert_arr will contain duplicated vertices for
/// colored triangles and initial vertices (for colored vertices) which in real became unused. This part need more thinking about
/// optimisation.
2016-09-29 23:24:24 +00:00
bool * idx_vert_used ;
2016-09-29 23:12:46 +00:00
2016-09-29 23:24:24 +00:00
idx_vert_used = new bool [ VertexCount_Max * 2 ] ;
2016-09-29 23:12:46 +00:00
for ( size_t i = 0 , i_e = VertexCount_Max * 2 ; i < i_e ; i + + ) idx_vert_used [ i ] = false ;
2016-09-28 14:49:15 +00:00
// This ID's will be used when set materials ID in scene.
2016-11-18 13:31:32 +00:00
tmesh - > mMaterialIndex = static_cast < unsigned int > ( PostprocessHelper_GetTextureID_Or_Create ( face_list_cur . front ( ) . TexMap - > TextureID_R ,
2016-09-28 14:49:15 +00:00
face_list_cur . front ( ) . TexMap - > TextureID_G ,
face_list_cur . front ( ) . TexMap - > TextureID_B ,
2016-11-18 13:31:32 +00:00
face_list_cur . front ( ) . TexMap - > TextureID_A ) ) ;
2016-09-28 14:49:15 +00:00
texcoord_arr . resize ( VertexCount_Max * 2 ) ;
for ( const SComplexFace & face_cur : face_list_cur )
{
for ( size_t idx_ind = 0 ; idx_ind < face_cur . Face . mNumIndices ; idx_ind + + )
{
const size_t idx_vert = face_cur . Face . mIndices [ idx_ind ] ;
if ( ! idx_vert_used [ idx_vert ] )
{
texcoord_arr . at ( idx_vert ) = face_cur . TexMap - > TextureCoordinate [ idx_ind ] ;
idx_vert_used [ idx_vert ] = true ;
}
else if ( texcoord_arr . at ( idx_vert ) ! = face_cur . TexMap - > TextureCoordinate [ idx_ind ] )
{
// in that case one vertex is shared with many texture coordinates. We need to duplicate vertex with another texture
// coordinates.
vert_arr . push_back ( vert_arr . at ( idx_vert ) ) ;
col_arr . push_back ( col_arr . at ( idx_vert ) ) ;
texcoord_arr . at ( idx_vert_new ) = face_cur . TexMap - > TextureCoordinate [ idx_ind ] ;
2016-11-18 13:31:32 +00:00
face_cur . Face . mIndices [ idx_ind ] = static_cast < unsigned int > ( idx_vert_new + + ) ;
2016-09-28 14:49:15 +00:00
}
} // for(size_t idx_ind = 0; idx_ind < face_cur.Face.mNumIndices; idx_ind++)
} // for(const SComplexFace& face_cur: face_list_cur)
2016-09-29 23:24:24 +00:00
delete [ ] idx_vert_used ;
2016-09-28 14:49:15 +00:00
// shrink array
texcoord_arr . resize ( idx_vert_new ) ;
} // if(face_list_cur.front().TexMap != nullptr)
//
// copy collected data to mesh
//
2016-11-18 13:31:32 +00:00
tmesh - > mNumVertices = static_cast < unsigned int > ( vert_arr . size ( ) ) ;
2016-09-28 14:49:15 +00:00
tmesh - > mVertices = new aiVector3D [ tmesh - > mNumVertices ] ;
tmesh - > mColors [ 0 ] = new aiColor4D [ tmesh - > mNumVertices ] ;
tmesh - > mFaces = new aiFace [ face_list_cur . size ( ) ] ;
memcpy ( tmesh - > mVertices , vert_arr . data ( ) , tmesh - > mNumVertices * sizeof ( aiVector3D ) ) ;
memcpy ( tmesh - > mColors [ 0 ] , col_arr . data ( ) , tmesh - > mNumVertices * sizeof ( aiColor4D ) ) ;
if ( texcoord_arr . size ( ) > 0 )
{
tmesh - > mTextureCoords [ 0 ] = new aiVector3D [ tmesh - > mNumVertices ] ;
memcpy ( tmesh - > mTextureCoords [ 0 ] , texcoord_arr . data ( ) , tmesh - > mNumVertices * sizeof ( aiVector3D ) ) ;
tmesh - > mNumUVComponents [ 0 ] = 2 ; // U and V stored in "x", "y" of aiVector3D.
}
size_t idx_face = 0 ;
for ( const SComplexFace & face_cur : face_list_cur ) tmesh - > mFaces [ idx_face + + ] = face_cur . Face ;
// store new aiMesh
2016-11-18 13:31:32 +00:00
mesh_idx . push_back ( static_cast < unsigned int > ( pMeshList . size ( ) ) ) ;
2016-09-28 14:49:15 +00:00
pMeshList . push_back ( tmesh ) ;
2016-09-29 21:03:34 +00:00
} // for(const std::list<SComplexFace>& face_list_cur: complex_faces_toplist)
2016-09-28 14:49:15 +00:00
} // if(ne_child->Type == CAMFImporter_NodeElement::ENET_Volume)
2016-09-29 21:03:34 +00:00
} // for(const CAMFImporter_NodeElement* ne_child: pNodeElement.Child)
2016-09-28 14:49:15 +00:00
// if meshes was created then assign new indices with current aiNode
if ( mesh_idx . size ( ) > 0 )
{
std : : list < unsigned int > : : const_iterator mit = mesh_idx . begin ( ) ;
2016-11-18 13:31:32 +00:00
pSceneNode . mNumMeshes = static_cast < unsigned int > ( mesh_idx . size ( ) ) ;
2016-09-28 14:49:15 +00:00
pSceneNode . mMeshes = new unsigned int [ pSceneNode . mNumMeshes ] ;
for ( size_t i = 0 ; i < pSceneNode . mNumMeshes ; i + + ) pSceneNode . mMeshes [ i ] = * mit + + ;
} // if(mesh_idx.size() > 0)
}
void AMFImporter : : Postprocess_BuildMaterial ( const CAMFImporter_NodeElement_Material & pMaterial )
{
SPP_Material new_mat ;
new_mat . ID = pMaterial . ID ;
2016-09-29 15:04:31 +00:00
for ( const CAMFImporter_NodeElement * mat_child : pMaterial . Child )
2016-09-28 14:49:15 +00:00
{
2016-09-29 15:04:31 +00:00
if ( mat_child - > Type = = CAMFImporter_NodeElement : : ENET_Color )
2016-09-28 14:49:15 +00:00
{
2016-09-29 15:04:31 +00:00
new_mat . Color = ( CAMFImporter_NodeElement_Color * ) mat_child ;
2016-09-28 14:49:15 +00:00
}
2016-09-29 15:04:31 +00:00
else if ( mat_child - > Type = = CAMFImporter_NodeElement : : ENET_Metadata )
2016-09-28 14:49:15 +00:00
{
2016-09-29 15:04:31 +00:00
new_mat . Metadata . push_back ( ( CAMFImporter_NodeElement_Metadata * ) mat_child ) ;
2016-09-28 14:49:15 +00:00
}
2016-09-29 15:04:31 +00:00
} // for(const CAMFImporter_NodeElement* mat_child; pMaterial.Child)
2016-09-28 14:49:15 +00:00
// place converted material to special list
mMaterial_Converted . push_back ( new_mat ) ;
}
void AMFImporter : : Postprocess_BuildConstellation ( CAMFImporter_NodeElement_Constellation & pConstellation , std : : list < aiNode * > & pNodeList ) const
{
aiNode * con_node ;
std : : list < aiNode * > ch_node ;
// We will build next hierarchy:
// aiNode as parent (<constellation>) for set of nodes as a children
// |- aiNode for transformation (<instance> -> <delta...>, <r...>) - aiNode for pointing to object ("objectid")
// ...
// \_ aiNode for transformation (<instance> -> <delta...>, <r...>) - aiNode for pointing to object ("objectid")
con_node = new aiNode ;
con_node - > mName = pConstellation . ID ;
2016-12-08 02:31:51 +00:00
// Walk through children and search for instances of another objects, constellations.
2016-09-29 15:04:31 +00:00
for ( const CAMFImporter_NodeElement * ne : pConstellation . Child )
2016-09-28 14:49:15 +00:00
{
aiMatrix4x4 tmat ;
aiNode * t_node ;
aiNode * found_node ;
2016-09-29 15:04:31 +00:00
if ( ne - > Type = = CAMFImporter_NodeElement : : ENET_Metadata ) continue ;
if ( ne - > Type ! = CAMFImporter_NodeElement : : ENET_Instance ) throw DeadlyImportError ( " Only <instance> nodes can be in <constellation>. " ) ;
2016-09-28 14:49:15 +00:00
// create alias for conveniance
2016-09-29 15:04:31 +00:00
CAMFImporter_NodeElement_Instance & als = * ( ( CAMFImporter_NodeElement_Instance * ) ne ) ;
2016-09-28 14:49:15 +00:00
// find referenced object
if ( ! Find_ConvertedNode ( als . ObjectID , pNodeList , & found_node ) ) Throw_ID_NotFound ( als . ObjectID ) ;
// create node for apllying transformation
t_node = new aiNode ;
t_node - > mParent = con_node ;
// apply transformation
aiMatrix4x4 : : Translation ( als . Delta , tmat ) , t_node - > mTransformation * = tmat ;
aiMatrix4x4 : : RotationX ( als . Rotation . x , tmat ) , t_node - > mTransformation * = tmat ;
aiMatrix4x4 : : RotationY ( als . Rotation . y , tmat ) , t_node - > mTransformation * = tmat ;
aiMatrix4x4 : : RotationZ ( als . Rotation . z , tmat ) , t_node - > mTransformation * = tmat ;
// create array for one child node
t_node - > mNumChildren = 1 ;
t_node - > mChildren = new aiNode * [ t_node - > mNumChildren ] ;
SceneCombiner : : Copy ( & t_node - > mChildren [ 0 ] , found_node ) ;
t_node - > mChildren [ 0 ] - > mParent = t_node ;
ch_node . push_back ( t_node ) ;
2016-09-29 15:04:31 +00:00
} // for(const CAMFImporter_NodeElement* ne: pConstellation.Child)
2016-09-28 14:49:15 +00:00
// copy found aiNode's as children
if ( ch_node . size ( ) = = 0 ) throw DeadlyImportError ( " <constellation> must have at least one <instance>. " ) ;
size_t ch_idx = 0 ;
2016-11-18 13:31:32 +00:00
con_node - > mNumChildren = static_cast < unsigned int > ( ch_node . size ( ) ) ;
2016-09-28 14:49:15 +00:00
con_node - > mChildren = new aiNode * [ con_node - > mNumChildren ] ;
2016-09-29 15:04:31 +00:00
for ( aiNode * node : ch_node ) con_node - > mChildren [ ch_idx + + ] = node ;
2016-09-28 14:49:15 +00:00
// and place "root" of <constellation> node to node list
pNodeList . push_back ( con_node ) ;
}
void AMFImporter : : Postprocess_BuildScene ( aiScene * pScene )
{
std : : list < aiNode * > node_list ;
std : : list < aiMesh * > mesh_list ;
std : : list < CAMFImporter_NodeElement_Metadata * > meta_list ;
//
// Because for AMF "material" is just complex colors mixing so aiMaterial will not be used.
// For building aiScene we are must to do few steps:
// at first creating root node for aiScene.
pScene - > mRootNode = new aiNode ;
2016-09-29 15:04:31 +00:00
pScene - > mRootNode - > mParent = nullptr ;
2016-09-28 14:49:15 +00:00
pScene - > mFlags | = AI_SCENE_FLAGS_ALLOW_SHARED ;
// search for root(<amf>) element
2016-09-29 15:04:31 +00:00
CAMFImporter_NodeElement * root_el = nullptr ;
for ( CAMFImporter_NodeElement * ne : mNodeElement_List )
2016-09-28 14:49:15 +00:00
{
2016-09-29 15:04:31 +00:00
if ( ne - > Type ! = CAMFImporter_NodeElement : : ENET_Root ) continue ;
2016-09-28 14:49:15 +00:00
2016-09-29 15:04:31 +00:00
root_el = ne ;
2016-09-28 14:49:15 +00:00
break ;
2016-09-29 15:04:31 +00:00
} // for(const CAMFImporter_NodeElement* ne: mNodeElement_List)
2016-09-28 14:49:15 +00:00
// Check if root element are found.
2016-09-29 15:04:31 +00:00
if ( root_el = = nullptr ) throw DeadlyImportError ( " Root(<amf>) element not found. " ) ;
2016-09-28 14:49:15 +00:00
2016-12-08 02:31:51 +00:00
// after that walk through children of root and collect data. Five types of nodes can be placed at top level - in <amf>: <object>, <material>, <texture>,
2016-09-28 14:49:15 +00:00
// <constellation> and <metadata>. But at first we must read <material> and <texture> because they will be used in <object>. <metadata> can be read
// at any moment.
//
// 1. <material>
// 2. <texture> will be converted later when processing triangles list. \sa Postprocess_BuildMeshSet
2016-09-29 15:04:31 +00:00
for ( const CAMFImporter_NodeElement * root_child : root_el - > Child )
2016-09-28 14:49:15 +00:00
{
2016-09-29 15:04:31 +00:00
if ( root_child - > Type = = CAMFImporter_NodeElement : : ENET_Material ) Postprocess_BuildMaterial ( * ( ( CAMFImporter_NodeElement_Material * ) root_child ) ) ;
2016-09-28 14:49:15 +00:00
}
// After "appearance" nodes we must read <object> because it will be used in <constellation> -> <instance>.
//
// 3. <object>
2016-09-29 15:04:31 +00:00
for ( const CAMFImporter_NodeElement * root_child : root_el - > Child )
2016-09-28 14:49:15 +00:00
{
2016-09-29 15:04:31 +00:00
if ( root_child - > Type = = CAMFImporter_NodeElement : : ENET_Object )
2016-09-28 14:49:15 +00:00
{
2016-09-29 15:04:31 +00:00
aiNode * tnode = nullptr ;
2016-09-28 14:49:15 +00:00
// for <object> mesh and node must be built: object ID assigned to aiNode name and will be used in future for <instance>
2016-09-29 15:04:31 +00:00
Postprocess_BuildNodeAndObject ( * ( ( CAMFImporter_NodeElement_Object * ) root_child ) , mesh_list , & tnode ) ;
if ( tnode ! = nullptr ) node_list . push_back ( tnode ) ;
2016-09-28 14:49:15 +00:00
2016-09-29 15:04:31 +00:00
}
} // for(const CAMFImporter_NodeElement* root_child: root_el->Child)
2016-09-28 14:49:15 +00:00
// And finally read rest of nodes.
//
2016-09-29 15:04:31 +00:00
for ( const CAMFImporter_NodeElement * root_child : root_el - > Child )
2016-09-28 14:49:15 +00:00
{
// 4. <constellation>
2016-09-29 15:04:31 +00:00
if ( root_child - > Type = = CAMFImporter_NodeElement : : ENET_Constellation )
2016-09-28 14:49:15 +00:00
{
// <object> and <constellation> at top of self abstraction use aiNode. So we can use only aiNode list for creating new aiNode's.
2016-09-29 15:04:31 +00:00
Postprocess_BuildConstellation ( * ( ( CAMFImporter_NodeElement_Constellation * ) root_child ) , node_list ) ;
2016-09-28 14:49:15 +00:00
}
// 5, <metadata>
2016-09-29 15:04:31 +00:00
if ( root_child - > Type = = CAMFImporter_NodeElement : : ENET_Metadata ) meta_list . push_back ( ( CAMFImporter_NodeElement_Metadata * ) root_child ) ;
} // for(const CAMFImporter_NodeElement* root_child: root_el->Child)
2016-09-28 14:49:15 +00:00
// at now we can add collected metadata to root node
Postprocess_AddMetadata ( meta_list , * pScene - > mRootNode ) ;
//
// Check constellation children
//
// As said in specification:
// "When multiple objects and constellations are defined in a single file, only the top level objects and constellations are available for printing."
// What that means? For example: if some object is used in constellation then you must show only constellation but not original object.
// And at this step we are checking that relations.
nl_clean_loop :
if ( node_list . size ( ) > 1 )
{
2016-12-08 02:31:51 +00:00
// walk through all nodes
2016-09-28 14:49:15 +00:00
for ( std : : list < aiNode * > : : iterator nl_it = node_list . begin ( ) ; nl_it ! = node_list . end ( ) ; nl_it + + )
{
// and try to find them in another top nodes.
std : : list < aiNode * > : : const_iterator next_it = nl_it ;
next_it + + ;
for ( ; next_it ! = node_list . end ( ) ; next_it + + )
{
2016-09-29 15:04:31 +00:00
if ( ( * next_it ) - > FindNode ( ( * nl_it ) - > mName ) ! = nullptr )
2016-09-28 14:49:15 +00:00
{
// if current top node(nl_it) found in another top node then erase it from node_list and restart search loop.
node_list . erase ( nl_it ) ;
goto nl_clean_loop ;
}
} // for(; next_it != node_list.end(); next_it++)
} // for(std::list<aiNode*>::const_iterator nl_it = node_list.begin(); nl_it != node_list.end(); nl_it++)
}
//
// move created objects to aiScene
//
//
// Nodes
if ( node_list . size ( ) > 0 )
{
std : : list < aiNode * > : : const_iterator nl_it = node_list . begin ( ) ;
2016-11-18 13:31:32 +00:00
pScene - > mRootNode - > mNumChildren = static_cast < unsigned int > ( node_list . size ( ) ) ;
2016-09-28 14:49:15 +00:00
pScene - > mRootNode - > mChildren = new aiNode * [ pScene - > mRootNode - > mNumChildren ] ;
for ( size_t i = 0 ; i < pScene - > mRootNode - > mNumChildren ; i + + )
{
// Objects and constellation that must be showed placed at top of hierarchy in <amf> node. So all aiNode's in node_list must have
// mRootNode only as parent.
( * nl_it ) - > mParent = pScene - > mRootNode ;
pScene - > mRootNode - > mChildren [ i ] = * nl_it + + ;
}
} // if(node_list.size() > 0)
//
// Meshes
if ( mesh_list . size ( ) > 0 )
{
std : : list < aiMesh * > : : const_iterator ml_it = mesh_list . begin ( ) ;
2016-11-18 13:31:32 +00:00
pScene - > mNumMeshes = static_cast < unsigned int > ( mesh_list . size ( ) ) ;
2016-09-28 14:49:15 +00:00
pScene - > mMeshes = new aiMesh * [ pScene - > mNumMeshes ] ;
for ( size_t i = 0 ; i < pScene - > mNumMeshes ; i + + ) pScene - > mMeshes [ i ] = * ml_it + + ;
} // if(mesh_list.size() > 0)
//
// Textures
2016-11-18 13:31:32 +00:00
pScene - > mNumTextures = static_cast < unsigned int > ( mTexture_Converted . size ( ) ) ;
2016-09-28 14:49:15 +00:00
if ( pScene - > mNumTextures > 0 )
{
size_t idx ;
idx = 0 ;
pScene - > mTextures = new aiTexture * [ pScene - > mNumTextures ] ;
for ( const SPP_Texture & tex_convd : mTexture_Converted )
{
pScene - > mTextures [ idx ] = new aiTexture ;
2016-11-18 13:31:32 +00:00
pScene - > mTextures [ idx ] - > mWidth = static_cast < unsigned int > ( tex_convd . Width ) ;
pScene - > mTextures [ idx ] - > mHeight = static_cast < unsigned int > ( tex_convd . Height ) ;
2016-09-28 14:49:15 +00:00
pScene - > mTextures [ idx ] - > pcData = ( aiTexel * ) tex_convd . Data ;
// texture format description.
strcpy ( pScene - > mTextures [ idx ] - > achFormatHint , tex_convd . FormatHint ) ;
idx + + ;
} // for(const SPP_Texture& tex_convd: mTexture_Converted)
// Create materials for embedded textures.
idx = 0 ;
2016-11-18 13:31:32 +00:00
pScene - > mNumMaterials = static_cast < unsigned int > ( mTexture_Converted . size ( ) ) ;
2016-09-28 14:49:15 +00:00
pScene - > mMaterials = new aiMaterial * [ pScene - > mNumMaterials ] ;
for ( const SPP_Texture & tex_convd : mTexture_Converted )
{
2016-10-15 19:45:58 +00:00
const aiString texture_id ( AI_EMBEDDED_TEXNAME_PREFIX + to_string ( idx ) ) ;
2016-09-28 14:49:15 +00:00
const int mode = aiTextureOp_Multiply ;
const int repeat = tex_convd . Tiled ? 1 : 0 ;
pScene - > mMaterials [ idx ] = new aiMaterial ;
pScene - > mMaterials [ idx ] - > AddProperty ( & texture_id , AI_MATKEY_TEXTURE_DIFFUSE ( 0 ) ) ;
pScene - > mMaterials [ idx ] - > AddProperty ( & mode , 1 , AI_MATKEY_TEXOP_DIFFUSE ( 0 ) ) ;
pScene - > mMaterials [ idx ] - > AddProperty ( & repeat , 1 , AI_MATKEY_MAPPINGMODE_U_DIFFUSE ( 0 ) ) ;
pScene - > mMaterials [ idx ] - > AddProperty ( & repeat , 1 , AI_MATKEY_MAPPINGMODE_V_DIFFUSE ( 0 ) ) ;
idx + + ;
}
} // if(pScene->mNumTextures > 0)
2016-12-08 02:31:51 +00:00
} // END: after that walk through children of root and collect data
2016-09-28 14:49:15 +00:00
} // namespace Assimp
# endif // !ASSIMP_BUILD_NO_AMF_IMPORTER