|
@@ -72,6 +72,8 @@ ColladaParser::~ColladaParser()
|
|
delete mReader;
|
|
delete mReader;
|
|
for( NodeLibrary::iterator it = mNodeLibrary.begin(); it != mNodeLibrary.end(); ++it)
|
|
for( NodeLibrary::iterator it = mNodeLibrary.begin(); it != mNodeLibrary.end(); ++it)
|
|
delete it->second;
|
|
delete it->second;
|
|
|
|
+ for( MeshLibrary::iterator it = mMeshLibrary.begin(); it != mMeshLibrary.end(); ++it)
|
|
|
|
+ delete it->second;
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// ------------------------------------------------------------------------------------------------
|
|
@@ -163,6 +165,9 @@ void ColladaParser::ReadAssetInfo()
|
|
}
|
|
}
|
|
else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
|
else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
|
{
|
|
{
|
|
|
|
+ if( strcmp( mReader->getNodeName(), "asset") != 0)
|
|
|
|
+ ThrowException( "Expected end of \"asset\" element.");
|
|
|
|
+
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -172,9 +177,493 @@ void ColladaParser::ReadAssetInfo()
|
|
// Reads the geometry library contents
|
|
// Reads the geometry library contents
|
|
void ColladaParser::ReadGeometryLibrary()
|
|
void ColladaParser::ReadGeometryLibrary()
|
|
{
|
|
{
|
|
|
|
+ while( mReader->read())
|
|
|
|
+ {
|
|
|
|
+ if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
|
|
|
+ {
|
|
|
|
+ if( IsElement( "geometry"))
|
|
|
|
+ {
|
|
|
|
+ // read ID. Another entry which is "optional" by design but obligatory in reality
|
|
|
|
+ int indexID = GetAttribute( "id");
|
|
|
|
+ std::string id = mReader->getAttributeValue( indexID);
|
|
|
|
+
|
|
|
|
+ // TODO: (thom) support SIDs
|
|
|
|
+ assert( TestAttribute( "sid") == -1);
|
|
|
|
+
|
|
|
|
+ // a <geometry> always contains a single <mesh> element inside, so we just skip that element in advance
|
|
|
|
+ TestOpening( "mesh");
|
|
|
|
+
|
|
|
|
+ // create a mesh and store it in the library under its ID
|
|
|
|
+ Mesh* mesh = new Mesh;
|
|
|
|
+ mMeshLibrary[id] = mesh;
|
|
|
|
+ // read on from there
|
|
|
|
+ ReadMesh( mesh);
|
|
|
|
+
|
|
|
|
+ // check for the closing tag of the outer <geometry" element, the inner closing of <mesh> has been consumed by ReadMesh()
|
|
|
|
+ TestClosing( "geometry");
|
|
|
|
+ } else
|
|
|
|
+ {
|
|
|
|
+ // ignore the rest
|
|
|
|
+ SkipElement();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
|
|
|
+ {
|
|
|
|
+ if( strcmp( mReader->getNodeName(), "library_geometries") != 0)
|
|
|
|
+ ThrowException( "Expected end of \"library_geometries\" element.");
|
|
|
|
+
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+// Reads a mesh from the geometry library
|
|
|
|
+void ColladaParser::ReadMesh( Mesh* pMesh)
|
|
|
|
+{
|
|
|
|
+ // I'm doing a dirty state parsing here because I don't want to open another submethod for it.
|
|
|
|
+ // There's a <source> tag defining the name for the accessor inside, and possible a <float_array>
|
|
|
|
+ // with it's own ID. This string contains the current source's ID if parsing is inside a <source> element.
|
|
|
|
+ std::string presentSourceID;
|
|
|
|
+
|
|
|
|
+ while( mReader->read())
|
|
|
|
+ {
|
|
|
|
+ if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
|
|
|
+ {
|
|
|
|
+ if( IsElement( "source"))
|
|
|
|
+ {
|
|
|
|
+ // beginning of a source element - store ID for the inner elements
|
|
|
|
+ int attrID = GetAttribute( "id");
|
|
|
|
+ presentSourceID = mReader->getAttributeValue( attrID);
|
|
|
|
+ }
|
|
|
|
+ else if( IsElement( "float_array"))
|
|
|
|
+ {
|
|
|
|
+ ReadFloatArray();
|
|
|
|
+ }
|
|
|
|
+ else if( IsElement( "technique_common"))
|
|
|
|
+ {
|
|
|
|
+ // I don't fucking care for your profiles bullshit
|
|
|
|
+ }
|
|
|
|
+ else if( IsElement( "accessor"))
|
|
|
|
+ {
|
|
|
|
+ ReadAccessor( presentSourceID);
|
|
|
|
+ }
|
|
|
|
+ else if( IsElement( "vertices"))
|
|
|
|
+ {
|
|
|
|
+ // read per-vertex mesh data
|
|
|
|
+ ReadVertexData( pMesh);
|
|
|
|
+ }
|
|
|
|
+ else if( IsElement( "polylist") || IsElement( "triangles"))
|
|
|
|
+ {
|
|
|
|
+ // read per-index mesh data and faces setup
|
|
|
|
+ ReadIndexData( pMesh);
|
|
|
|
+ } else
|
|
|
|
+ {
|
|
|
|
+ // ignore the rest
|
|
|
|
+ SkipElement();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
|
|
|
+ {
|
|
|
|
+ if( strcmp( mReader->getNodeName(), "source") == 0)
|
|
|
|
+ {
|
|
|
|
+ // end of <source> - reset present source ID
|
|
|
|
+ presentSourceID.clear();
|
|
|
|
+ }
|
|
|
|
+ else if( strcmp( mReader->getNodeName(), "technique_common") == 0)
|
|
|
|
+ {
|
|
|
|
+ // end of another meaningless element - read over it
|
|
|
|
+ }
|
|
|
|
+ else if( strcmp( mReader->getNodeName(), "mesh") == 0)
|
|
|
|
+ {
|
|
|
|
+ // end of <mesh> element - we're done here
|
|
|
|
+ break;
|
|
|
|
+ } else
|
|
|
|
+ {
|
|
|
|
+ // everything else should be punished
|
|
|
|
+ ThrowException( "Expected end of \"mesh\" element.");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+// Reads a data array holding a number of floats, and stores it in the global library
|
|
|
|
+void ColladaParser::ReadFloatArray()
|
|
|
|
+{
|
|
|
|
+ // read attributes
|
|
|
|
+ int indexID = GetAttribute( "id");
|
|
|
|
+ std::string id = mReader->getAttributeValue( indexID);
|
|
|
|
+ int indexCount = GetAttribute( "count");
|
|
|
|
+ unsigned int count = (unsigned int) mReader->getAttributeValueAsInt( indexCount);
|
|
|
|
+ const char* content = GetTextContent();
|
|
|
|
+
|
|
|
|
+ // read values and store inside an array in the data library
|
|
|
|
+ mDataLibrary[id] = Data();
|
|
|
|
+ Data& data = mDataLibrary[id];
|
|
|
|
+ data.mValues.reserve( count);
|
|
|
|
+ for( unsigned int a = 0; a < count; a++)
|
|
|
|
+ {
|
|
|
|
+ if( *content == 0)
|
|
|
|
+ ThrowException( "Expected more values while reading float_array contents.");
|
|
|
|
+
|
|
|
|
+ float value;
|
|
|
|
+ // read a number
|
|
|
|
+ content = fast_atof_move( content, value);
|
|
|
|
+ data.mValues.push_back( value);
|
|
|
|
+ // skip whitespace after it
|
|
|
|
+ SkipSpacesAndLineEnd( &content);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // test for closing tag
|
|
|
|
+ TestClosing( "float_array");
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+// Reads an accessor and stores it in the global library
|
|
|
|
+void ColladaParser::ReadAccessor( const std::string& pID)
|
|
|
|
+{
|
|
|
|
+ // read accessor attributes
|
|
|
|
+ int attrSource = GetAttribute( "source");
|
|
|
|
+ const char* source = mReader->getAttributeValue( attrSource);
|
|
|
|
+ if( source[0] != '#')
|
|
|
|
+ ThrowException( boost::str( boost::format( "Unknown reference format in url \"%s\".") % source));
|
|
|
|
+ int attrCount = GetAttribute( "count");
|
|
|
|
+ unsigned int count = (unsigned int) mReader->getAttributeValueAsInt( attrCount);
|
|
|
|
+ int attrOffset = TestAttribute( "offset");
|
|
|
|
+ unsigned int offset = 0;
|
|
|
|
+ if( attrOffset > -1)
|
|
|
|
+ offset = (unsigned int) mReader->getAttributeValueAsInt( attrOffset);
|
|
|
|
+ int attrStride = TestAttribute( "stride");
|
|
|
|
+ unsigned int stride = 1;
|
|
|
|
+ if( attrStride > -1)
|
|
|
|
+ stride = (unsigned int) mReader->getAttributeValueAsInt( attrStride);
|
|
|
|
+
|
|
|
|
+ // store in the library under the given ID
|
|
|
|
+ mAccessorLibrary[pID] = Accessor();
|
|
|
|
+ Accessor& acc = mAccessorLibrary[pID];
|
|
|
|
+ acc.mCount = count;
|
|
|
|
+ acc.mOffset = offset;
|
|
|
|
+ acc.mStride = stride;
|
|
|
|
+ acc.mSource = source+1; // ignore the leading '#'
|
|
|
|
+
|
|
|
|
+ // and read the components
|
|
|
|
+ while( mReader->read())
|
|
|
|
+ {
|
|
|
|
+ if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
|
|
|
+ {
|
|
|
|
+ if( IsElement( "param"))
|
|
|
|
+ {
|
|
|
|
+ // read data param
|
|
|
|
+ int attrName = TestAttribute( "name");
|
|
|
|
+ std::string name;
|
|
|
|
+ if( attrName > -1)
|
|
|
|
+ {
|
|
|
|
+ name = mReader->getAttributeValue( attrName);
|
|
|
|
+
|
|
|
|
+ // analyse for common type components and store it's sub-offset in the corresponding field
|
|
|
|
+ if( name == "X") acc.mSubOffset[0] = acc.mParams.size();
|
|
|
|
+ else if( name == "Y") acc.mSubOffset[1] = acc.mParams.size();
|
|
|
|
+ else if( name == "Z") acc.mSubOffset[2] = acc.mParams.size();
|
|
|
|
+ else if( name == "R") acc.mSubOffset[0] = acc.mParams.size();
|
|
|
|
+ else if( name == "G") acc.mSubOffset[1] = acc.mParams.size();
|
|
|
|
+ else if( name == "B") acc.mSubOffset[2] = acc.mParams.size();
|
|
|
|
+ else if( name == "A") acc.mSubOffset[3] = acc.mParams.size();
|
|
|
|
+ else if( name == "S") acc.mSubOffset[0] = acc.mParams.size();
|
|
|
|
+ else if( name == "T") acc.mSubOffset[1] = acc.mParams.size();
|
|
|
|
+ else
|
|
|
|
+ DefaultLogger::get()->warn( boost::str( boost::format( "Unknown accessor parameter \"%s\". Ignoring data channel.") % name));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ acc.mParams.push_back( name);
|
|
|
|
+
|
|
|
|
+ // skip remaining stuff of this element, if any
|
|
|
|
+ SkipElement();
|
|
|
|
+ } else
|
|
|
|
+ {
|
|
|
|
+ ThrowException( "Unexpected sub element in tag \"accessor\".");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
|
|
|
+ {
|
|
|
|
+ if( strcmp( mReader->getNodeName(), "accessor") != 0)
|
|
|
|
+ ThrowException( "Expected end of \"accessor\" element.");
|
|
|
|
+
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+// Reads input declarations of per-vertex mesh data into the given mesh
|
|
|
|
+void ColladaParser::ReadVertexData( Mesh* pMesh)
|
|
|
|
+{
|
|
|
|
+ // extract the ID of the <vertices> element. Not that we care, but to catch strange referencing schemes we should warn about
|
|
|
|
+ int attrID= GetAttribute( "id");
|
|
|
|
+ pMesh->mVertexID = mReader->getAttributeValue( attrID);
|
|
|
|
+
|
|
|
|
+ // a number of <input> elements
|
|
|
|
+ while( mReader->read())
|
|
|
|
+ {
|
|
|
|
+ if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
|
|
|
+ {
|
|
|
|
+ if( IsElement( "input"))
|
|
|
|
+ {
|
|
|
|
+ ReadInputChannel( pMesh->mPerVertexData);
|
|
|
|
+ } else
|
|
|
|
+ {
|
|
|
|
+ ThrowException( "Unexpected sub element in tag \"vertices\".");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
|
|
|
+ {
|
|
|
|
+ if( strcmp( mReader->getNodeName(), "vertices") != 0)
|
|
|
|
+ ThrowException( "Expected end of \"vertices\" element.");
|
|
|
|
+
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+// Reads input declarations of per-index mesh data into the given mesh
|
|
|
|
+void ColladaParser::ReadIndexData( Mesh* pMesh)
|
|
|
|
+{
|
|
|
|
+ std::vector<size_t> vcount;
|
|
|
|
+ std::vector<InputChannel> perIndexData;
|
|
|
|
+
|
|
|
|
+ // read primitive count from the attribute
|
|
|
|
+ int attrCount = GetAttribute( "count");
|
|
|
|
+ size_t numPrimitives = (size_t) mReader->getAttributeValueAsInt( attrCount);
|
|
|
|
+
|
|
|
|
+ // distinguish between polys and triangles
|
|
|
|
+ std::string elementName = mReader->getNodeName();
|
|
|
|
+ bool isPolylist = IsElement( "polylist");
|
|
|
|
+
|
|
|
|
+ // also a number of <input> elements, but in addition a <p> primitive collection and propably index counts for all primitives
|
|
|
|
+ while( mReader->read())
|
|
|
|
+ {
|
|
|
|
+ if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
|
|
|
|
+ {
|
|
|
|
+ if( IsElement( "input"))
|
|
|
|
+ {
|
|
|
|
+ ReadInputChannel( perIndexData);
|
|
|
|
+ }
|
|
|
|
+ else if( IsElement( "vcount"))
|
|
|
|
+ {
|
|
|
|
+ // case <polylist> - specifies the number of indices for each polygon
|
|
|
|
+ const char* content = GetTextContent();
|
|
|
|
+ vcount.reserve( numPrimitives);
|
|
|
|
+ for( unsigned int a = 0; a < numPrimitives; a++)
|
|
|
|
+ {
|
|
|
|
+ if( *content == 0)
|
|
|
|
+ ThrowException( "Expected more values while reading vcount contents.");
|
|
|
|
+ // read a number
|
|
|
|
+ vcount.push_back( (size_t) strtol10( content, &content));
|
|
|
|
+ // skip whitespace after it
|
|
|
|
+ SkipSpacesAndLineEnd( &content);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ TestClosing( "vcount");
|
|
|
|
+ }
|
|
|
|
+ else if( IsElement( "p"))
|
|
|
|
+ {
|
|
|
|
+ // now here the actual fun starts - these are the indices to construct the mesh data from
|
|
|
|
+ ReadPrimitives( pMesh, perIndexData, numPrimitives, vcount, isPolylist);
|
|
|
|
+ } else
|
|
|
|
+ {
|
|
|
|
+ ThrowException( "Unexpected sub element in tag \"vertices\".");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
|
|
|
+ {
|
|
|
|
+ if( mReader->getNodeName() != elementName)
|
|
|
|
+ ThrowException( boost::str( boost::format( "Expected end of \"%s\" element.") % elementName));
|
|
|
|
+
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+// Reads a single input channel element and stores it in the given array, if valid
|
|
|
|
+void ColladaParser::ReadInputChannel( std::vector<InputChannel>& poChannels)
|
|
|
|
+{
|
|
|
|
+ InputChannel channel;
|
|
|
|
+
|
|
|
|
+ // read semantic
|
|
|
|
+ int attrSemantic = GetAttribute( "semantic");
|
|
|
|
+ std::string semantic = mReader->getAttributeValue( attrSemantic);
|
|
|
|
+ channel.mType = GetTypeForSemantic( semantic);
|
|
|
|
+
|
|
|
|
+ // read source
|
|
|
|
+ int attrSource = GetAttribute( "source");
|
|
|
|
+ const char* source = mReader->getAttributeValue( attrSource);
|
|
|
|
+ if( source[0] != '#')
|
|
|
|
+ ThrowException( boost::str( boost::format( "Unknown reference format in url \"%s\".") % source));
|
|
|
|
+ channel.mAccessor = source+1; // skipping the leading #, hopefully the remaining text is the accessor ID only
|
|
|
|
+
|
|
|
|
+ // read index offset, if per-index <input>
|
|
|
|
+ int attrOffset = TestAttribute( "offset");
|
|
|
|
+ if( attrOffset > -1)
|
|
|
|
+ channel.mOffset = mReader->getAttributeValueAsInt( attrOffset);
|
|
|
|
+
|
|
|
|
+ // store, if valid type
|
|
|
|
+ if( channel.mType != IT_Invalid)
|
|
|
|
+ poChannels.push_back( channel);
|
|
|
|
+
|
|
|
|
+ // skip remaining stuff of this element, if any
|
|
SkipElement();
|
|
SkipElement();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+// Reads a <p> primitive index list and assembles the mesh data into the given mesh
|
|
|
|
+void ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector<InputChannel>& pPerIndexChannels,
|
|
|
|
+ size_t pNumPrimitives, const std::vector<size_t>& pVCount, bool pIsPolylist)
|
|
|
|
+{
|
|
|
|
+ // determine number of indices coming per vertex
|
|
|
|
+ // find the offset index for all per-vertex channels
|
|
|
|
+ size_t numOffsets = 1;
|
|
|
|
+ size_t perVertexOffset = -1; // invalid value
|
|
|
|
+ BOOST_FOREACH( const InputChannel& channel, pPerIndexChannels)
|
|
|
|
+ {
|
|
|
|
+ numOffsets = std::max( numOffsets, channel.mOffset+1);
|
|
|
|
+ if( channel.mType == IT_Vertex)
|
|
|
|
+ perVertexOffset = channel.mOffset;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // determine the expected number of indices
|
|
|
|
+ size_t expectedPointCount = 0;
|
|
|
|
+ if( pIsPolylist)
|
|
|
|
+ {
|
|
|
|
+ BOOST_FOREACH( size_t i, pVCount)
|
|
|
|
+ expectedPointCount += i;
|
|
|
|
+ } else
|
|
|
|
+ {
|
|
|
|
+ // everything triangles
|
|
|
|
+ expectedPointCount = 3 * pNumPrimitives;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // and read all indices into a temporary array
|
|
|
|
+ std::vector<size_t> indices( expectedPointCount * numOffsets);
|
|
|
|
+ const char* content = GetTextContent();
|
|
|
|
+ BOOST_FOREACH( size_t& value, indices)
|
|
|
|
+ {
|
|
|
|
+ if( *content == 0)
|
|
|
|
+ ThrowException( "Expected more values while reading primitive indices.");
|
|
|
|
+ // read a value in place
|
|
|
|
+ value = strtol10( content, &content);
|
|
|
|
+ // skip whitespace after it
|
|
|
|
+ SkipSpacesAndLineEnd( &content);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // find the data for all sources
|
|
|
|
+ BOOST_FOREACH( InputChannel& input, pMesh->mPerVertexData)
|
|
|
|
+ {
|
|
|
|
+ // find accessor
|
|
|
|
+ input.mResolved = &ResolveLibraryReference( mAccessorLibrary, input.mAccessor);
|
|
|
|
+ // resolve accessor's data pointer as well, if neccessary
|
|
|
|
+ const Accessor* acc = input.mResolved;
|
|
|
|
+ if( !acc->mData)
|
|
|
|
+ acc->mData = &ResolveLibraryReference( mDataLibrary, acc->mSource);
|
|
|
|
+ }
|
|
|
|
+ // and the same for the per-index channels
|
|
|
|
+ BOOST_FOREACH( InputChannel& input, pPerIndexChannels)
|
|
|
|
+ {
|
|
|
|
+ // ignore vertex pointer, it doesn't refer to an accessor
|
|
|
|
+ if( input.mType == IT_Vertex)
|
|
|
|
+ {
|
|
|
|
+ // warn if the vertex channel does not refer to the <vertices> element in the same mesh
|
|
|
|
+ if( input.mAccessor != pMesh->mVertexID)
|
|
|
|
+ ThrowException( "Unsupported vertex referencing scheme. I fucking hate Collada.");
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // find accessor
|
|
|
|
+ input.mResolved = &ResolveLibraryReference( mAccessorLibrary, input.mAccessor);
|
|
|
|
+ // resolve accessor's data pointer as well, if neccessary
|
|
|
|
+ const Accessor* acc = input.mResolved;
|
|
|
|
+ if( !acc->mData)
|
|
|
|
+ acc->mData = &ResolveLibraryReference( mDataLibrary, acc->mSource);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ // now assemble vertex data according to those indices
|
|
|
|
+ std::vector<size_t>::const_iterator idx = indices.begin();
|
|
|
|
+ for( size_t a = 0; a < pNumPrimitives; a++)
|
|
|
|
+ {
|
|
|
|
+ // determine number of points for this primitive
|
|
|
|
+ size_t numPoints = 3;
|
|
|
|
+ if( pIsPolylist)
|
|
|
|
+ numPoints = pVCount[a];
|
|
|
|
+
|
|
|
|
+ // store the face size to later reconstruct the face from
|
|
|
|
+ pMesh->mFaceSize.push_back( numPoints);
|
|
|
|
+
|
|
|
|
+ // gather that number of vertices
|
|
|
|
+ for( size_t b = 0; b < numPoints; b++)
|
|
|
|
+ {
|
|
|
|
+ // read all indices for this vertex. Yes, in a hacky static array
|
|
|
|
+ assert( numOffsets < 20);
|
|
|
|
+ static size_t vindex[20];
|
|
|
|
+ for( size_t offsets = 0; offsets < numOffsets; ++offsets)
|
|
|
|
+ vindex[offsets] = *idx++;
|
|
|
|
+
|
|
|
|
+ // extract per-vertex channels using the global per-vertex offset
|
|
|
|
+ BOOST_FOREACH( const InputChannel& input, pMesh->mPerVertexData)
|
|
|
|
+ ExtractDataObjectFromChannel( input, vindex[perVertexOffset], pMesh);
|
|
|
|
+ // and extract per-index channels using there specified offset
|
|
|
|
+ BOOST_FOREACH( const InputChannel& input, pPerIndexChannels)
|
|
|
|
+ ExtractDataObjectFromChannel( input, vindex[input.mOffset], pMesh);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // if I ever get my hands on that guy how invented this steaming pile of indirection...
|
|
|
|
+ TestClosing( "p");
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+// Extracts a single object from an input channel and stores it in the appropriate mesh data array
|
|
|
|
+void ColladaParser::ExtractDataObjectFromChannel( const InputChannel& pInput, size_t pLocalIndex, Mesh* pMesh)
|
|
|
|
+{
|
|
|
|
+ // ignore vertex referrer - we handle them that separate
|
|
|
|
+ if( pInput.mType == IT_Vertex)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ const Accessor& acc = *pInput.mResolved;
|
|
|
|
+ if( pLocalIndex >= acc.mCount)
|
|
|
|
+ ThrowException( boost::str( boost::format( "Invalid data index (%d/%d) in primitive specification") % pLocalIndex % acc.mCount));
|
|
|
|
+
|
|
|
|
+ // get a pointer to the start of the data object referred to by the accessor and the local index
|
|
|
|
+ const float* dataObject = &(acc.mData->mValues[0]) + acc.mOffset + pLocalIndex* acc.mStride;
|
|
|
|
+
|
|
|
|
+ // assemble according to the accessors component sub-offset list. We don't care, yet, what kind of object exactly we're extracting here
|
|
|
|
+ float obj[4];
|
|
|
|
+ for( size_t c = 0; c < 4; ++c)
|
|
|
|
+ obj[c] = dataObject[acc.mSubOffset[c]];
|
|
|
|
+
|
|
|
|
+ // now we reinterpret it according to the type we're reading here
|
|
|
|
+ switch( pInput.mType)
|
|
|
|
+ {
|
|
|
|
+ case IT_Position: // ignore all position streams except 0 - there can be only one position
|
|
|
|
+ if( pInput.mIndex == 0)
|
|
|
|
+ pMesh->mPositions.push_back( aiVector3D( obj[0], obj[1], obj[2]));
|
|
|
|
+ break;
|
|
|
|
+ case IT_Normal: // ignore all normal streams except 0 - there can be only one normal
|
|
|
|
+ if( pInput.mIndex == 0)
|
|
|
|
+ pMesh->mNormals.push_back( aiVector3D( obj[0], obj[1], obj[2]));
|
|
|
|
+ break;
|
|
|
|
+ case IT_Texcoord: // up to 4 texture coord sets are fine, ignore the others
|
|
|
|
+ if( pInput.mIndex < AI_MAX_NUMBER_OF_TEXTURECOORDS)
|
|
|
|
+ pMesh->mTexCoords[pInput.mIndex].push_back( aiVector2D( obj[0], obj[1]));
|
|
|
|
+ break;
|
|
|
|
+ case IT_Color: // up to 4 color sets are fine, ignore the others
|
|
|
|
+ if( pInput.mIndex < AI_MAX_NUMBER_OF_COLOR_SETS)
|
|
|
|
+ pMesh->mColors[pInput.mIndex].push_back( aiColor4D( obj[0], obj[1], obj[2], obj[3]));
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
// ------------------------------------------------------------------------------------------------
|
|
// ------------------------------------------------------------------------------------------------
|
|
// Reads the library of node hierarchies and scene parts
|
|
// Reads the library of node hierarchies and scene parts
|
|
void ColladaParser::ReadSceneLibrary()
|
|
void ColladaParser::ReadSceneLibrary()
|
|
@@ -214,6 +703,9 @@ void ColladaParser::ReadSceneLibrary()
|
|
}
|
|
}
|
|
else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
|
else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
|
|
{
|
|
{
|
|
|
|
+ if( strcmp( mReader->getNodeName(), "library_visual_scenes") != 0)
|
|
|
|
+ ThrowException( "Expected end of \"library_visual_scenes\" element.");
|
|
|
|
+
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -371,6 +863,22 @@ void ColladaParser::SkipElement()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+// Tests for an opening element of the given name, throws an exception if not found
|
|
|
|
+void ColladaParser::TestOpening( const char* pName)
|
|
|
|
+{
|
|
|
|
+ // read element start
|
|
|
|
+ if( !mReader->read())
|
|
|
|
+ ThrowException( boost::str( boost::format( "Unexpected end of file while beginning of \"%s\" element.") % pName));
|
|
|
|
+ // whitespace in front is ok, just read again if found
|
|
|
|
+ if( mReader->getNodeType() == irr::io::EXN_TEXT)
|
|
|
|
+ if( !mReader->read())
|
|
|
|
+ ThrowException( boost::str( boost::format( "Unexpected end of file while reading beginning of \"%s\" element.") % pName));
|
|
|
|
+
|
|
|
|
+ if( mReader->getNodeType() != irr::io::EXN_ELEMENT || strcmp( mReader->getNodeName(), pName) != 0)
|
|
|
|
+ ThrowException( boost::str( boost::format( "Expected start of \"%s\" element.") % pName));
|
|
|
|
+}
|
|
|
|
+
|
|
// ------------------------------------------------------------------------------------------------
|
|
// ------------------------------------------------------------------------------------------------
|
|
// Tests for the closing tag of the given element, throws an exception if not found
|
|
// Tests for the closing tag of the given element, throws an exception if not found
|
|
void ColladaParser::TestClosing( const char* pName)
|
|
void ColladaParser::TestClosing( const char* pName)
|
|
@@ -378,6 +886,11 @@ void ColladaParser::TestClosing( const char* pName)
|
|
// read closing tag
|
|
// read closing tag
|
|
if( !mReader->read())
|
|
if( !mReader->read())
|
|
ThrowException( boost::str( boost::format( "Unexpected end of file while reading end of \"%s\" element.") % pName));
|
|
ThrowException( boost::str( boost::format( "Unexpected end of file while reading end of \"%s\" element.") % pName));
|
|
|
|
+ // whitespace in front is ok, just read again if found
|
|
|
|
+ if( mReader->getNodeType() == irr::io::EXN_TEXT)
|
|
|
|
+ if( !mReader->read())
|
|
|
|
+ ThrowException( boost::str( boost::format( "Unexpected end of file while reading end of \"%s\" element.") % pName));
|
|
|
|
+
|
|
if( mReader->getNodeType() != irr::io::EXN_ELEMENT_END || strcmp( mReader->getNodeName(), pName) != 0)
|
|
if( mReader->getNodeType() != irr::io::EXN_ELEMENT_END || strcmp( mReader->getNodeName(), pName) != 0)
|
|
ThrowException( boost::str( boost::format( "Expected end of \"%s\" element.") % pName));
|
|
ThrowException( boost::str( boost::format( "Expected end of \"%s\" element.") % pName));
|
|
}
|
|
}
|
|
@@ -482,3 +995,22 @@ aiMatrix4x4 ColladaParser::CalculateResultTransform( const std::vector<Transform
|
|
|
|
|
|
return res;
|
|
return res;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+// Determines the input data type for the given semantic string
|
|
|
|
+ColladaParser::InputType ColladaParser::GetTypeForSemantic( const std::string& pSemantic)
|
|
|
|
+{
|
|
|
|
+ if( pSemantic == "POSITION")
|
|
|
|
+ return IT_Position;
|
|
|
|
+ else if( pSemantic == "TEXCOORD")
|
|
|
|
+ return IT_Texcoord;
|
|
|
|
+ else if( pSemantic == "NORMAL")
|
|
|
|
+ return IT_Normal;
|
|
|
|
+ else if( pSemantic == "COLOR")
|
|
|
|
+ return IT_Color;
|
|
|
|
+ else if( pSemantic == "VERTEX")
|
|
|
|
+ return IT_Vertex;
|
|
|
|
+
|
|
|
|
+ DefaultLogger::get()->warn( boost::str( boost::format( "Unknown vertex input type \"%s\". Ignoring.") % pSemantic));
|
|
|
|
+ return IT_Invalid;
|
|
|
|
+}
|