First pass of Collada ZAE support

Reads the manifest and loads the DAE
Does not yet load embedded textures
pull/2545/head
RichardTea 2019-07-12 11:29:35 +01:00
parent 2c7f607e7c
commit d64e1bde13
6 changed files with 1852 additions and 1721 deletions

View File

@ -60,6 +60,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/ParsingUtils.h>
#include <assimp/SkeletonMeshBuilder.h>
#include <assimp/CreateAnimMesh.h>
#include <assimp/ZipArchiveIOSystem.h>
#include "time.h"
#include "math.h"
@ -75,12 +76,12 @@ static const aiImporterDesc desc = {
"",
"",
"http://collada.org",
aiImporterFlags_SupportTextFlavour,
aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportCompressedFlavour,
1,
3,
1,
5,
"dae"
"dae zae"
};
// ------------------------------------------------------------------------------------------------
@ -114,9 +115,20 @@ bool ColladaLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, boo
// check file extension
std::string extension = GetExtension(pFile);
if (extension == "dae") {
bool readSig = checkSig && (pIOHandler != nullptr);
if (!readSig) {
if (extension == "dae" || extension == "zae") {
return true;
}
}
if (readSig) {
// Look for a DAE file inside, but don't extract it
ZipArchiveIOSystem zip_archive(pIOHandler, pFile);
if (zip_archive.isOpen())
return !ColladaParser::ReadZaeManifest(zip_archive).empty();
}
// XML - too generic, we need to open the file and search for typical keywords
if (extension == "xml" || !extension.length() || checkSig) {
@ -357,7 +369,8 @@ void ColladaLoader::BuildLightsForNode( const ColladaParser& pParser, const Coll
if (out->mType == aiLightSource_AMBIENT) {
out->mColorDiffuse = out->mColorSpecular = aiColor3D(0, 0, 0);
out->mColorAmbient = srcLight->mColor*srcLight->mIntensity;
} else {
}
else {
// collada doesn't differentiate between these color types
out->mColorDiffuse = out->mColorSpecular = srcLight->mColor*srcLight->mIntensity;
out->mColorAmbient = aiColor3D(0, 0, 0);
@ -375,12 +388,14 @@ void ColladaLoader::BuildLightsForNode( const ColladaParser& pParser, const Coll
// epsilon chosen to be 0.1
out->mAngleOuterCone = std::acos(std::pow(0.1f, 1.f / srcLight->mFalloffExponent)) +
out->mAngleInnerCone;
} else {
}
else {
out->mAngleOuterCone = out->mAngleInnerCone + AI_DEG_TO_RAD(srcLight->mPenumbraAngle);
if (out->mAngleOuterCone < out->mAngleInnerCone)
std::swap(out->mAngleInnerCone, out->mAngleOuterCone);
}
} else {
}
else {
out->mAngleOuterCone = AI_DEG_TO_RAD(srcLight->mOuterAngle);
}
}
@ -474,7 +489,8 @@ void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Coll
ASSIMP_LOG_WARN_F("Collada: Unable to find geometry for ID \"", mid.mMeshOrController, "\". Skipping.");
continue;
}
} else {
}
else {
// ID found in the mesh library -> direct reference to an unskinned mesh
srcMesh = srcMeshIt->second;
}
@ -495,7 +511,8 @@ void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Coll
if (meshMatIt != mid.mMaterials.end()) {
table = &meshMatIt->second;
meshMaterial = table->mMatName;
} else {
}
else {
ASSIMP_LOG_WARN_F("Collada: No material specified for subgroup <", submesh.mMaterial, "> in geometry <",
mid.mMeshOrController, ">.");
if (!mid.mMaterials.empty()) {
@ -531,7 +548,8 @@ void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Coll
std::map<ColladaMeshIndex, size_t>::const_iterator dstMeshIt = mMeshIndexByID.find(index);
if (dstMeshIt != mMeshIndexByID.end()) {
newMeshRefs.push_back(dstMeshIt->second);
} else {
}
else {
// else we have to add the mesh to the collection and store its newly assigned index at the node
aiMesh* dstMesh = CreateMesh(pParser, srcMesh, submesh, srcController, vertexStart, faceStart);
@ -1056,7 +1074,8 @@ void insertMorphTimeValue(std::vector<MorphTimeValues> &values, float time, floa
{
values[i].mKeys.push_back(k);
return;
} else if (time > values[i].mTime && time < values[i+1].mTime)
}
else if (time > values[i].mTime && time < values[i + 1].mTime)
{
MorphTimeValues val;
val.mTime = time;
@ -1158,7 +1177,8 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
entry.mSubElement = 2;
else
ASSIMP_LOG_WARN_F("Unknown anim subelement <", subElement, ">. Ignoring");
} else {
}
else {
// no subelement following, transformId is remaining string
entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1);
}
@ -1216,7 +1236,8 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
{
entry.mTargetId = entry.mTransformId;
entry.mTransformId = "";
} else
}
else
continue;
}
@ -1385,7 +1406,8 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
}
anims.push_back(dstAnim);
} else
}
else
{
ASSIMP_LOG_WARN("Collada loader: found empty animation channel, ignored. Please check your exporter.");
}
@ -1623,7 +1645,8 @@ void ColladaLoader::FillMaterials( const ColladaParser& pParser, aiScene* /*pSce
effect.mTransparent.a = 1.f;
mat.AddProperty(&effect.mTransparent, 1, AI_MATKEY_COLOR_TRANSPARENT);
} else {
}
else {
effect.mTransparency *= effect.mTransparent.a;
}
@ -1821,7 +1844,8 @@ void ColladaLoader::ConvertPath (aiString& ss)
size_t nbr = strtoul16(mychar);
it += 3;
*out++ = (char)(nbr & 0xFF);
} else
}
else
{
*out++ = *it++;
}
@ -1905,7 +1929,8 @@ std::string ColladaLoader::FindNameForNode( const Collada::Node* pNode)
{
if (!pNode->mName.empty()) {
return pNode->mName;
} else {
}
else {
return format() << "$ColladaAutoName$_" << mNodeNameCounter++;
}
}

View File

@ -94,7 +94,7 @@ public:
public:
/** Returns whether the class can handle the format of the given file.
* See BaseImporter::CanRead() for details. */
bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const;
bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const override;
protected:
/** Return importer meta information.

View File

@ -57,6 +57,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/IOSystem.hpp>
#include <assimp/light.h>
#include <assimp/TinyFormatter.h>
#include <assimp/ZipArchiveIOSystem.h>
#include <memory>
@ -90,21 +91,49 @@ ColladaParser::ColladaParser( IOSystem* pIOHandler, const std::string& pFile)
throw DeadlyImportError("IOSystem is NULL.");
}
// open the file
std::unique_ptr<IOStream> file( pIOHandler->Open(pFile ) );
if (file.get() == nullptr) {
throw DeadlyImportError( "Failed to open file " + pFile + "." );
std::unique_ptr<IOStream> daefile;
std::unique_ptr<ZipArchiveIOSystem> zip_archive;
// Determine type
std::string extension = BaseImporter::GetExtension(pFile);
if (extension != "dae") {
zip_archive.reset(new ZipArchiveIOSystem(pIOHandler, pFile));
}
if (zip_archive && zip_archive->isOpen()) {
std::string dae_filename = ReadZaeManifest(*zip_archive);
if (dae_filename.empty()) {
ThrowException(std::string("Invalid ZAE"));
}
daefile.reset(zip_archive->Open(dae_filename.c_str()));
if (daefile == nullptr) {
ThrowException(std::string("Invalid ZAE manifest: '") + std::string(dae_filename) + std::string("' is missing"));
}
}
else {
// attempt to open the file directly
daefile.reset(pIOHandler->Open(pFile));
if (daefile.get() == nullptr) {
throw DeadlyImportError("Failed to open file '" + pFile + "'.");
}
}
// generate a XML reader for it
std::unique_ptr<CIrrXML_IOStreamReader> mIOWrapper(new CIrrXML_IOStreamReader(file.get()));
std::unique_ptr<CIrrXML_IOStreamReader> mIOWrapper(new CIrrXML_IOStreamReader(daefile.get()));
mReader = irr::io::createIrrXMLReader(mIOWrapper.get());
if (!mReader) {
ThrowException("Collada: Unable to open file.");
ThrowException("Unable to read file, malformed XML");
}
// start reading
ReadContents();
// read embedded textures
if (zip_archive && zip_archive->isOpen()) {
// TODO
}
}
// ------------------------------------------------------------------------------------------------
@ -118,6 +147,49 @@ ColladaParser::~ColladaParser()
delete it->second;
}
// ------------------------------------------------------------------------------------------------
// Read a ZAE manifest and return the filename to attempt to open
std::string ColladaParser::ReadZaeManifest(ZipArchiveIOSystem &zip_archive) {
// Open the manifest
std::unique_ptr<IOStream> manifestfile(zip_archive.Open("manifest.xml"));
if (manifestfile == nullptr)
{
// No manifest, hope there is only one .DAE inside
std::vector<std::string> file_list;
zip_archive.getFileListExtension(file_list, "dae");
if (file_list.empty())
return std::string();
return file_list.front();
}
std::unique_ptr<CIrrXML_IOStreamReader> mIOWrapper(new CIrrXML_IOStreamReader(manifestfile.get()));
irr::io::IrrXMLReader* manifest_reader = irr::io::createIrrXMLReader(mIOWrapper.get());
while (manifest_reader->read())
{
// find the manifest "dae_root" element
if (manifest_reader->getNodeType() == irr::io::EXN_ELEMENT)
{
if (::strcmp(manifest_reader->getNodeName(), "dae_root") == 0)
{
if (!manifest_reader->read())
return std::string();
if (manifest_reader->getNodeType() != irr::io::EXN_TEXT && manifest_reader->getNodeType() != irr::io::EXN_CDATA)
return std::string();
const char* filepath = manifest_reader->getNodeData();
if (filepath == nullptr)
return std::string();
return std::string(filepath);
}
}
}
return std::string();
}
// ------------------------------------------------------------------------------------------------
// Read bool from text contents of current element
bool ColladaParser::ReadBoolFromTextContent()
@ -165,12 +237,14 @@ void ColladaParser::ReadContents()
}
ReadStructure();
} else
}
else
{
ASSIMP_LOG_DEBUG_F("Ignoring global element <", mReader->getNodeName(), ">.");
SkipElement();
}
} else
}
else
{
// skip everything else silently
}
@ -506,7 +580,8 @@ void ColladaParser::ReadAnimationLibrary()
{
// delegate the reading. Depending on the inner elements it will be a container or a anim channel
ReadAnimation(&mAnims);
} else
}
else
{
// ignore the rest
SkipElement();
@ -722,7 +797,8 @@ void ColladaParser::ReadControllerLibrary()
// read on from there
ReadController(mControllerLibrary[id]);
} else
}
else
{
// ignore the rest
SkipElement();
@ -816,7 +892,8 @@ void ColladaParser::ReadController( Collada::Controller& pController)
pController.mMorphWeight = source + 1;
}
}
} else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
}
else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
if (strcmp(mReader->getNodeName(), "targets") == 0)
break;
else
@ -1008,7 +1085,8 @@ void ColladaParser::ReadImageLibrary()
// read on from there
ReadImage(mImageLibrary[id]);
} else
}
else
{
// ignore the rest
SkipElement();
@ -1158,7 +1236,8 @@ void ColladaParser::ReadMaterialLibrary()
}
ReadMaterial(mMaterialLibrary[id]);
} else
}
else
{
// ignore the rest
SkipElement();
@ -1193,7 +1272,8 @@ void ColladaParser::ReadLightLibrary()
// create an entry and store it in the library under its ID
ReadLight(mLightLibrary[id] = Light());
} else
}
else
{
// ignore the rest
SkipElement();
@ -1232,7 +1312,8 @@ void ColladaParser::ReadCameraLibrary()
ReadCamera(cam);
} else
}
else
{
// ignore the rest
SkipElement();
@ -1268,7 +1349,8 @@ void ColladaParser::ReadMaterial( Collada::Material& pMaterial)
pMaterial.mEffect = url + 1;
SkipElement();
} else
}
else
{
// ignore the rest
SkipElement();
@ -1439,7 +1521,8 @@ void ColladaParser::ReadEffectLibrary()
mEffectLibrary[id] = Effect();
// read on from there
ReadEffect(mEffectLibrary[id]);
} else
}
else
{
// ignore the rest
SkipElement();
@ -1779,7 +1862,8 @@ void ColladaParser::ReadEffectFloat( ai_real& pFloat)
SkipSpacesAndLineEnd(&content);
TestClosing("float");
} else
}
else
{
// ignore the rest
SkipElement();
@ -1834,7 +1918,8 @@ void ColladaParser::ReadEffectParam( Collada::EffectParam& pParam)
pParam.mType = Param_Sampler;
pParam.mReference = url;
SkipElement("sampler2D");
} else
}
else
{
// ignore unknown element
SkipElement();
@ -1879,7 +1964,8 @@ void ColladaParser::ReadGeometryLibrary()
// read on from there
ReadGeometry(mesh);
} else
}
else
{
// ignore the rest
SkipElement();
@ -1910,7 +1996,8 @@ void ColladaParser::ReadGeometry( Collada::Mesh* pMesh)
{
// read on from there
ReadMesh(pMesh);
} else
}
else
{
// ignore the rest
SkipElement();
@ -1952,7 +2039,8 @@ void ColladaParser::ReadMesh( Mesh* pMesh)
{
// read per-index mesh data and faces setup
ReadIndexData(pMesh);
} else
}
else
{
// ignore the restf
SkipElement();
@ -1968,7 +2056,8 @@ void ColladaParser::ReadMesh( Mesh* pMesh)
{
// end of <mesh> element - we're done here
break;
} else
}
else
{
// everything else should be punished
ThrowException("Expected end of <mesh> element.");
@ -1999,7 +2088,8 @@ void ColladaParser::ReadSource()
else if (IsElement("accessor"))
{
ReadAccessor(sourceID);
} else
}
else
{
// ignore the rest
SkipElement();
@ -2015,7 +2105,8 @@ void ColladaParser::ReadSource()
else if (strcmp(mReader->getNodeName(), "technique_common") == 0)
{
// end of another meaningless element - read over it
} else
}
else
{
// everything else should be punished
ThrowException("Expected end of <source> element.");
@ -2064,7 +2155,8 @@ void ColladaParser::ReadDataArray()
SkipSpacesAndLineEnd(&content);
}
} else
}
else
{
data.mValues.reserve(count);
@ -2176,7 +2268,8 @@ void ColladaParser::ReadAccessor( const std::string& pID)
// skip remaining stuff of this element, if any
SkipElement();
} else
}
else
{
ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag <accessor>");
}
@ -2206,7 +2299,8 @@ void ColladaParser::ReadVertexData( Mesh* pMesh)
if (IsElement("input"))
{
ReadInputChannel(pMesh->mPerVertexData);
} else
}
else
{
ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag <vertices>");
}
@ -2304,9 +2398,11 @@ void ColladaParser::ReadIndexData( Mesh* pMesh)
else if (IsElement("extra"))
{
SkipElement("extra");
} else if ( IsElement("ph")) {
}
else if (IsElement("ph")) {
SkipElement("ph");
} else {
}
else {
ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag <" << elementName << ">");
}
}
@ -2436,10 +2532,12 @@ size_t ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector<InputChannel>& pP
// HACK: We just fix this number since SketchUp 15.3.331 writes the wrong 'count' for 'lines'
ReportWarning("Expected different index count in <p> element, %zu instead of %zu.", indices.size(), expectedPointCount * numOffsets);
pNumPrimitives = (indices.size() / numOffsets) / 2;
} else
}
else
ThrowException("Expected different index count in <p> element.");
} else if( expectedPointCount == 0 && (indices.size() % numOffsets) != 0)
}
else if (expectedPointCount == 0 && (indices.size() % numOffsets) != 0)
ThrowException("Expected different index count in <p> element.");
// find the data for all sources
@ -2660,7 +2758,8 @@ void ColladaParser::ExtractDataObjectFromChannel( const InputChannel& pInput, si
pMesh->mTexCoords[pInput.mIndex].push_back(aiVector3D(obj[0], obj[1], obj[2]));
if (0 != acc.mSubOffset[2] || 0 != acc.mSubOffset[3]) /* hack ... consider cleaner solution */
pMesh->mNumUVComponents[pInput.mIndex] = 3;
} else
}
else
{
ASSIMP_LOG_ERROR("Collada: too many texture coordinate sets. Skipping.");
}
@ -2680,7 +2779,8 @@ void ColladaParser::ExtractDataObjectFromChannel( const InputChannel& pInput, si
result[static_cast<unsigned int>(i)] = obj[pInput.mResolved->mSubOffset[i]];
}
pMesh->mColors[pInput.mIndex].push_back(result);
} else
}
else
{
ASSIMP_LOG_ERROR("Collada: too many vertex color sets. Skipping.");
}
@ -2723,7 +2823,8 @@ void ColladaParser::ReadSceneLibrary()
mNodeLibrary[node->mID] = node;
ReadSceneNode(node);
} else
}
else
{
// ignore the rest
SkipElement();
@ -3036,7 +3137,8 @@ void ColladaParser::ReadScene()
if (sit == mNodeLibrary.end())
ThrowException("Unable to resolve visual_scene reference \"" + std::string(url) + "\" in <instance_visual_scene> element.");
mRootNode = sit->second;
} else {
}
else {
SkipElement();
}
}

View File

@ -54,6 +54,7 @@
namespace Assimp
{
class ZipArchiveIOSystem;
// ------------------------------------------------------------------------------------------
/** Parser helper class for the Collada loader.
@ -75,6 +76,9 @@ namespace Assimp
/** Destructor */
~ColladaParser();
/** Attempts to read the ZAE manifest and returns the DAE to open */
static std::string ReadZaeManifest(ZipArchiveIOSystem &zip_archive);
/** Reads the contents of the file */
void ReadContents();

Binary file not shown.

Binary file not shown.