2016-10-04 09:45:08 +00:00
/*
Open Asset Import Library ( assimp )
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2020-01-20 13:53:12 +00:00
Copyright ( c ) 2006 - 2020 , assimp team
2018-01-28 18:42:05 +00:00
2016-10-04 09:45:08 +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 .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
2016-10-02 00:08:34 +00:00
/// \file X3DImporter_Group.cpp
/// \brief Parsing data from nodes of "Grouping" set of X3D.
/// \date 2015-2016
/// \author smal.root@gmail.com
2016-09-29 15:50:24 +00:00
# ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
# include "X3DImporter.hpp"
# include "X3DImporter_Macro.hpp"
2020-08-10 20:13:45 +00:00
# include <assimp/ParsingUtils.h>
2016-09-29 15:50:24 +00:00
namespace Assimp
{
// <Group
// DEF="" ID
// USE="" IDREF
// bboxCenter="0 0 0" SFVec3f [initializeOnly]
// bboxSize="-1 -1 -1" SFVec3f [initializeOnly]
// >
// <!-- ChildContentModel -->
// ChildContentModel is the child-node content model corresponding to X3DChildNode, combining all profiles. ChildContentModel can contain most nodes,
// other Grouping nodes, Prototype declarations and ProtoInstances in any order and any combination. When the assigned profile is less than Full, the
// precise palette of legal nodes that are available depends on assigned profile and components.
// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model.
// </Group>
// A Group node contains children nodes without introducing a new transformation. It is equivalent to a Transform node containing an identity transform.
2020-08-10 20:13:45 +00:00
void X3DImporter : : ParseNode_Grouping_Group ( XmlNode & node ) {
//std::string def, use;
2016-09-29 15:50:24 +00:00
2020-08-10 20:13:45 +00:00
std : : string def = node . attribute ( " DEF " ) . as_string ( ) ;
std : : string use = node . attribute ( " USE " ) . as_string ( ) ;
/*MACRO_ATTRREAD_LOOPBEG;
2016-09-29 15:50:24 +00:00
MACRO_ATTRREAD_CHECKUSEDEF_RET ( def , use ) ;
2020-08-10 20:13:45 +00:00
MACRO_ATTRREAD_LOOPEND ; */
2016-09-29 15:50:24 +00:00
// if "USE" defined then find already defined element.
if ( ! use . empty ( ) )
{
2020-08-10 20:13:45 +00:00
X3DNodeElementBase * ne = nullptr ;
if ( def . empty ( ) ) {
Throw_DEF_And_USE ( node . name ( ) ) ;
}
if ( ! FindNodeElement ( use , X3DNodeElementBase : : ENET_Group , & ne ) ) {
Throw_USE_NotFound ( node . name ( ) , use ) ;
}
mNodeElementCur - > Child . push_back ( ne ) ;
//MACRO_USE_CHECKANDAPPLY(def, use, X3DNodeElementBase::ENET_Group, ne);
} else {
2016-09-29 15:50:24 +00:00
ParseHelper_Group_Begin ( ) ; // create new grouping element and go deeper if node has children.
2020-08-10 20:13:45 +00:00
// at this place new group mode created and made current, so we can name it.
if ( ! def . empty ( ) ) {
mNodeElementCur - > ID = def ;
}
2016-09-29 15:50:24 +00:00
// in grouping set of nodes check X3DMetadataObject is not needed, because it is done in <Scene> parser function.
// for empty element exit from node in that place
2020-08-10 20:13:45 +00:00
//if(mReader->isEmptyElement())
if ( node . empty ( ) ) {
ParseHelper_Node_Exit ( ) ;
}
2016-09-29 15:50:24 +00:00
} // if(!use.empty()) else
}
void X3DImporter : : ParseNode_Grouping_GroupEnd ( )
{
ParseHelper_Node_Exit ( ) ; // go up in scene graph
}
// <StaticGroup
// DEF="" ID
// USE="" IDREF
// bboxCenter="0 0 0" SFVec3f [initializeOnly]
// bboxSize="-1 -1 -1" SFVec3f [initializeOnly]
// >
// <!-- ChildContentModel -->
// ChildContentModel is the child-node content model corresponding to X3DChildNode, combining all profiles. ChildContentModel can contain most nodes,
// other Grouping nodes, Prototype declarations and ProtoInstances in any order and any combination. When the assigned profile is less than Full, the
// precise palette of legal nodes that are available depends on assigned profile and components.
// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model.
// </StaticGroup>
// The StaticGroup node contains children nodes which cannot be modified. StaticGroup children are guaranteed to not change, send events, receive events or
// contain any USE references outside the StaticGroup.
2020-08-10 20:13:45 +00:00
void X3DImporter : : ParseNode_Grouping_StaticGroup ( XmlNode & node ) {
// std::string def, use;
std : : string def = node . attribute ( " DEF " ) . as_string ( ) ;
std : : string use = node . attribute ( " USE " ) . as_string ( ) ;
2016-09-29 15:50:24 +00:00
2020-08-10 20:13:45 +00:00
/* MACRO_ATTRREAD_LOOPBEG;
2016-09-29 15:50:24 +00:00
MACRO_ATTRREAD_CHECKUSEDEF_RET ( def , use ) ;
2020-08-10 20:13:45 +00:00
MACRO_ATTRREAD_LOOPEND ; */
2016-09-29 15:50:24 +00:00
// if "USE" defined then find already defined element.
if ( ! use . empty ( ) )
{
2020-08-10 20:13:45 +00:00
X3DNodeElementBase * ne = nullptr ;
if ( ! FindNodeElement ( use , X3DNodeElementBase : : ENET_Group , & ne ) ) {
Throw_USE_NotFound ( node . name ( ) , use ) ;
}
mNodeElementCur - > Child . push_back ( ne ) ;
2016-09-29 15:50:24 +00:00
2020-08-10 20:13:45 +00:00
// MACRO_USE_CHECKANDAPPLY(def, use, ENET_Group, ne);
2016-09-29 15:50:24 +00:00
}
else
{
ParseHelper_Group_Begin ( true ) ; // create new grouping element and go deeper if node has children.
// at this place new group mode created and made current, so we can name it.
2020-07-26 08:17:21 +00:00
if ( ! def . empty ( ) ) mNodeElementCur - > ID = def ;
2016-09-29 15:50:24 +00:00
// in grouping set of nodes check X3DMetadataObject is not needed, because it is done in <Scene> parser function.
// for empty element exit from node in that place
2020-08-10 20:13:45 +00:00
if ( node . empty ( ) ) {
ParseHelper_Node_Exit ( ) ;
}
// if(mReader->isEmptyElement()) ParseHelper_Node_Exit();
2016-09-29 15:50:24 +00:00
} // if(!use.empty()) else
}
void X3DImporter : : ParseNode_Grouping_StaticGroupEnd ( )
{
ParseHelper_Node_Exit ( ) ; // go up in scene graph
}
// <Switch
// DEF="" ID
// USE="" IDREF
// bboxCenter="0 0 0" SFVec3f [initializeOnly]
// bboxSize="-1 -1 -1" SFVec3f [initializeOnly]
// whichChoice="-1" SFInt32 [inputOutput]
// >
// <!-- ChildContentModel -->
// ChildContentModel is the child-node content model corresponding to X3DChildNode, combining all profiles. ChildContentModel can contain most nodes,
// other Grouping nodes, Prototype declarations and ProtoInstances in any order and any combination. When the assigned profile is less than Full, the
// precise palette of legal nodes that are available depends on assigned profile and components.
// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model.
// </Switch>
// The Switch grouping node traverses zero or one of the nodes specified in the children field. The whichChoice field specifies the index of the child
// to traverse, with the first child having index 0. If whichChoice is less than zero or greater than the number of nodes in the children field, nothing
// is chosen.
2020-08-10 20:13:45 +00:00
void X3DImporter : : ParseNode_Grouping_Switch ( XmlNode & node ) {
// std::string def, use;
2016-10-04 16:40:58 +00:00
int32_t whichChoice = - 1 ;
2020-08-10 20:13:45 +00:00
std : : string def = node . attribute ( " DEF " ) . as_string ( ) ;
std : : string use = node . attribute ( " USE " ) . as_string ( ) ;
pugi : : xml_attribute attr = node . attribute ( " whichChoise " ) ;
whichChoice = attr . as_int ( ) ;
/*MACRO_ATTRREAD_LOOPBEG;
2016-09-29 15:50:24 +00:00
MACRO_ATTRREAD_CHECKUSEDEF_RET ( def , use ) ;
MACRO_ATTRREAD_CHECK_RET ( " whichChoice " , whichChoice , XML_ReadNode_GetAttrVal_AsI32 ) ;
2020-08-10 20:13:45 +00:00
MACRO_ATTRREAD_LOOPEND ; */
2016-09-29 15:50:24 +00:00
// if "USE" defined then find already defined element.
if ( ! use . empty ( ) )
{
2020-08-10 20:13:45 +00:00
X3DNodeElementBase * ne = nullptr ;
if ( ! FindNodeElement ( use , X3DNodeElementBase : : ENET_Group , & ne ) ) {
Throw_USE_NotFound ( node . name ( ) , use ) ;
}
mNodeElementCur - > Child . push_back ( ne ) ;
2016-09-29 15:50:24 +00:00
2020-08-10 20:13:45 +00:00
// MACRO_USE_CHECKANDAPPLY(def, use, ENET_Group, ne);
2016-09-29 15:50:24 +00:00
}
else
{
ParseHelper_Group_Begin ( ) ; // create new grouping element and go deeper if node has children.
// at this place new group mode created and made current, so we can name it.
2020-07-26 08:17:21 +00:00
if ( ! def . empty ( ) ) mNodeElementCur - > ID = def ;
2016-09-29 15:50:24 +00:00
// also set values specific to this type of group
2020-07-26 08:17:21 +00:00
( ( X3DGroup * ) mNodeElementCur ) - > UseChoice = true ;
( ( X3DGroup * ) mNodeElementCur ) - > Choice = whichChoice ;
2016-09-29 15:50:24 +00:00
// in grouping set of nodes check X3DMetadataObject is not needed, because it is done in <Scene> parser function.
// for empty element exit from node in that place
2020-08-10 20:13:45 +00:00
// if(mReader->isEmptyElement()) ParseHelper_Node_Exit();
if ( node . empty ( ) ) {
ParseHelper_Node_Exit ( ) ;
}
2016-09-29 15:50:24 +00:00
} // if(!use.empty()) else
}
void X3DImporter : : ParseNode_Grouping_SwitchEnd ( )
{
2020-08-10 20:13:45 +00:00
// just exit from node. Defined choice will be accepted at post-processing stage.
2016-09-29 15:50:24 +00:00
ParseHelper_Node_Exit ( ) ; // go up in scene graph
}
2020-08-10 20:13:45 +00:00
void ReadAttrAsVec3f ( pugi : : xml_node & node , const std : : string & attrName , aiVector3D & vec ) {
const pugi : : xml_attribute & attr = node . attribute ( attrName . c_str ( ) ) ;
if ( attr . empty ( ) ) {
return ;
}
std : : string data = attr . as_string ( ) ;
std : : vector < std : : string > token ;
tokenize < std : : string > ( data , token , " " ) ;
vec . x = ( ai_real ) std : : atof ( token [ 0 ] . c_str ( ) ) ;
vec . y = ( ai_real ) std : : atof ( token [ 1 ] . c_str ( ) ) ;
vec . z = ( ai_real ) std : : atof ( token [ 2 ] . c_str ( ) ) ;
}
void ReadAttrAsFloatArray ( pugi : : xml_node & node , const std : : string & attrName , size_t numComponents , std : : vector < float > & tvec ) {
pugi : : xml_attribute attr = node . attribute ( attrName . c_str ( ) ) ;
std : : string data = attr . as_string ( ) ;
std : : vector < std : : string > token ;
tokenize < std : : string > ( data , token , " " ) ;
if ( token . size ( ) ! = numComponents ) throw DeadlyImportError ( " <Transform>: rotation vector must have 4 elements. " ) ;
for ( size_t i = 0 ; i < numComponents ; + + i ) {
tvec . push_back ( ( ai_real ) std : : atof ( token [ i ] . c_str ( ) ) ) ;
}
}
2016-09-29 15:50:24 +00:00
// <Transform
// DEF="" ID
// USE="" IDREF
// bboxCenter="0 0 0" SFVec3f [initializeOnly]
// bboxSize="-1 -1 -1" SFVec3f [initializeOnly]
// center="0 0 0" SFVec3f [inputOutput]
// rotation="0 0 1 0" SFRotation [inputOutput]
// scale="1 1 1" SFVec3f [inputOutput]
// scaleOrientation="0 0 1 0" SFRotation [inputOutput]
// translation="0 0 0" SFVec3f [inputOutput]
// >
// <!-- ChildContentModel -->
// ChildContentModel is the child-node content model corresponding to X3DChildNode, combining all profiles. ChildContentModel can contain most nodes,
// other Grouping nodes, Prototype declarations and ProtoInstances in any order and any combination. When the assigned profile is less than Full, the
// precise palette of legal nodes that are available depends on assigned profile and components.
// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model.
// </Transform>
// The Transform node is a grouping node that defines a coordinate system for its children that is relative to the coordinate systems of its ancestors.
// Given a 3-dimensional point P and Transform node, P is transformed into point P' in its parent's coordinate system by a series of intermediate
// transformations. In matrix transformation notation, where C (center), SR (scaleOrientation), T (translation), R (rotation), and S (scale) are the
// equivalent transformation matrices,
// P' = T * C * R * SR * S * -SR * -C * P
2020-08-10 20:13:45 +00:00
void X3DImporter : : ParseNode_Grouping_Transform ( XmlNode & node ) {
2016-10-04 16:40:58 +00:00
aiVector3D center ( 0 , 0 , 0 ) ;
2020-08-10 20:13:45 +00:00
float rotation [ 4 ] = { 0 , 0 , 1 , 0 } ;
aiVector3D scale ( 1 , 1 , 1 ) ; // A value of zero indicates that any child geometry shall not be displayed
float scale_orientation [ 4 ] = { 0 , 0 , 1 , 0 } ;
2016-10-04 16:40:58 +00:00
aiVector3D translation ( 0 , 0 , 0 ) ;
aiMatrix4x4 matr , tmatr ;
2020-08-10 20:13:45 +00:00
//std::string use, def;
2016-09-29 15:50:24 +00:00
2020-08-10 20:13:45 +00:00
//MACRO_ATTRREAD_LOOPBEG;
std : : string def = node . attribute ( " DEF " ) . as_string ( ) ;
std : : string use = node . attribute ( " USE " ) . as_string ( ) ;
//MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
ReadAttrAsVec3f ( node , " center " , center ) ;
ReadAttrAsVec3f ( node , " scale " , scale ) ;
ReadAttrAsVec3f ( node , " translation " , translation ) ;
/*MACRO_ATTRREAD_CHECK_REF("center", center, XML_ReadNode_GetAttrVal_AsVec3f);
2016-09-29 15:50:24 +00:00
MACRO_ATTRREAD_CHECK_REF ( " scale " , scale , XML_ReadNode_GetAttrVal_AsVec3f ) ;
2020-08-10 20:13:45 +00:00
MACRO_ATTRREAD_CHECK_REF ( " translation " , translation , XML_ReadNode_GetAttrVal_AsVec3f ) ; */
if ( hasAttribute ( node , " rotation " ) ) {
std : : vector < float > tvec ;
ReadAttrAsFloatArray ( node , " rotation " , 4 , tvec ) ;
memcpy ( rotation , tvec . data ( ) , sizeof ( rotation ) ) ;
}
if ( hasAttribute ( node , " scaleOrientation " ) ) {
std : : vector < float > tvec ;
ReadAttrAsFloatArray ( node , " rotation " , 4 , tvec ) ;
: : memcpy ( scale_orientation , tvec . data ( ) , sizeof ( scale_orientation ) ) ;
}
/*if(an == "rotation")
2016-09-29 15:50:24 +00:00
{
std : : vector < float > tvec ;
XML_ReadNode_GetAttrVal_AsArrF ( idx , tvec ) ;
if ( tvec . size ( ) ! = 4 ) throw DeadlyImportError ( " <Transform>: rotation vector must have 4 elements. " ) ;
memcpy ( rotation , tvec . data ( ) , sizeof ( rotation ) ) ;
continue ;
}
2020-08-10 20:13:45 +00:00
if ( an = = " scaleOrientation " ) {
2016-09-29 15:50:24 +00:00
std : : vector < float > tvec ;
XML_ReadNode_GetAttrVal_AsArrF ( idx , tvec ) ;
2016-10-04 16:40:58 +00:00
if ( tvec . size ( ) ! = 4 )
{
throw DeadlyImportError ( " <Transform>: scaleOrientation vector must have 4 elements. " ) ;
}
2016-09-29 15:50:24 +00:00
2016-10-04 16:40:58 +00:00
: : memcpy ( scale_orientation , tvec . data ( ) , sizeof ( scale_orientation ) ) ;
2016-09-29 15:50:24 +00:00
continue ;
}
2020-08-10 20:13:45 +00:00
MACRO_ATTRREAD_LOOPEND ; */
2016-09-29 15:50:24 +00:00
// if "USE" defined then find already defined element.
2020-08-10 20:13:45 +00:00
if ( ! use . empty ( ) ) {
X3DNodeElementBase * ne = nullptr ;
if ( ! FindNodeElement ( use , X3DNodeElementBase : : ENET_Group , & ne ) ) {
Throw_USE_NotFound ( node . name ( ) , use ) ;
}
mNodeElementCur - > Child . push_back ( ne ) ;
2016-09-29 15:50:24 +00:00
2020-08-10 20:13:45 +00:00
//MACRO_USE_CHECKANDAPPLY(def, use, ENET_Group, ne);
2016-09-29 15:50:24 +00:00
}
else
{
ParseHelper_Group_Begin ( ) ; // create new grouping element and go deeper if node has children.
// at this place new group mode created and made current, so we can name it.
2016-10-04 16:40:58 +00:00
if ( ! def . empty ( ) )
{
2020-07-26 08:17:21 +00:00
mNodeElementCur - > ID = def ;
2016-10-04 16:40:58 +00:00
}
2016-09-29 15:50:24 +00:00
//
// also set values specific to this type of group
//
2016-10-04 16:40:58 +00:00
// calculate transformation matrix
2016-09-29 15:50:24 +00:00
aiMatrix4x4 : : Translation ( translation , matr ) ; // T
aiMatrix4x4 : : Translation ( center , tmatr ) ; // C
matr * = tmatr ;
aiMatrix4x4 : : Rotation ( rotation [ 3 ] , aiVector3D ( rotation [ 0 ] , rotation [ 1 ] , rotation [ 2 ] ) , tmatr ) ; // R
matr * = tmatr ;
aiMatrix4x4 : : Rotation ( scale_orientation [ 3 ] , aiVector3D ( scale_orientation [ 0 ] , scale_orientation [ 1 ] , scale_orientation [ 2 ] ) , tmatr ) ; // SR
matr * = tmatr ;
aiMatrix4x4 : : Scaling ( scale , tmatr ) ; // S
matr * = tmatr ;
aiMatrix4x4 : : Rotation ( - scale_orientation [ 3 ] , aiVector3D ( scale_orientation [ 0 ] , scale_orientation [ 1 ] , scale_orientation [ 2 ] ) , tmatr ) ; // -SR
matr * = tmatr ;
aiMatrix4x4 : : Translation ( - center , tmatr ) ; // -C
matr * = tmatr ;
// and assign it
2020-07-26 08:17:21 +00:00
( ( X3DGroup * ) mNodeElementCur ) - > Transformation = matr ;
2016-09-29 15:50:24 +00:00
// in grouping set of nodes check X3DMetadataObject is not needed, because it is done in <Scene> parser function.
// for empty element exit from node in that place
2020-08-10 20:13:45 +00:00
if ( node . empty ( ) ) {
2016-10-04 16:40:58 +00:00
ParseHelper_Node_Exit ( ) ;
}
2016-09-29 15:50:24 +00:00
} // if(!use.empty()) else
}
void X3DImporter : : ParseNode_Grouping_TransformEnd ( )
{
ParseHelper_Node_Exit ( ) ; // go up in scene graph
}
} // namespace Assimp
# endif // !ASSIMP_BUILD_NO_X3D_IMPORTER