Collada loader now handles texture-names with escape characters.

Names like "my%20texture.png" will now load "my texture.png". Collada filenames are in xs:anyURI format.
xs:anyURI is used in more places, but we don't support any other file-loading inside Collada so far, so that was the most important place to fix.
Also added/fixed a few comments.


git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@5793 dfc29bdd-3216-0410-991c-e03cc46cb475
master
cutealien 2019-03-25 22:32:32 +00:00
parent a450a0e391
commit 917379f453
6 changed files with 91 additions and 15 deletions

View File

@ -1,5 +1,6 @@
--------------------------
Changes in 1.9 (not yet released)
- .dae/Collada reader/writer now handle whitespace in texture-filenames with escape characters (handle them as xs:anyURI).
- Add function string::insert.
- EditBox now still allows overwriting characters when the text-length is at max.
- Bugfix: CMatrix4::transformPlane was calculating the wrong plane-normal before.
@ -9,7 +10,7 @@ Changes in 1.9 (not yet released)
- Bugfix: CCameraSceneNode resets the IsOrthogonal flag to false now when it recalculates a projection matrix.
- SViewFrustum::setFrom and SViewFrustum constructor now use a parameter to allow to set the correct near clipping plane when the projection matrix doesn't use a target depth range of 0 to z, but for example -z to z. So OGL projections matrices can now also use it.
- Remove code to read boundingbox element in Collada reader as it's not in Collada specification.
- .dae/Collade reader now converts from Collada's right-handed to Irrlicht's left handed coordinate system (switching z to -z)
- .dae/Collada reader now converts from Collada's right-handed to Irrlicht's left handed coordinate system (switching z to -z)
- Add irr::string::eraseTrailingFloatZeros to kick out trailing 0's for strings generated from floats.
- .dae/Collada writer now converts from Irrlicht's left-handed to Collada's right-handed coordinate system (switching z to -z)
- Switch Collada writer to utf8 xml's.

View File

@ -154,6 +154,7 @@ namespace scene
//! Callback interface to use custom names on collada writing.
/** You can either modify names and id's written to collada or you can use
this interface to just find out which names are used on writing.
Names are often used later as xs:anyURI, so avoid whitespace, '#' and '%' in the names.
*/
class IColladaMeshWriterNames : public virtual IReferenceCounted
{
@ -165,7 +166,7 @@ namespace scene
/** Note that names really must be unique here per mesh-pointer, so
mostly it's a good idea to return the nameForMesh from
IColladaMeshWriter::getDefaultNameGenerator(). Also names must follow
the xs::NCName standard to be valid, you can run them through
the xs:NCName standard to be valid, you can run them through
IColladaMeshWriter::toNCName to ensure that.
\param mesh Pointer to the mesh which needs a name
\param instance When E_COLLADA_GEOMETRY_WRITING is not ECGI_PER_MESH then
@ -177,7 +178,7 @@ namespace scene
/** Note that names really must be unique here per node-pointer, so
mostly it's a good idea to return the nameForNode from
IColladaMeshWriter::getDefaultNameGenerator(). Also names must follow
the xs::NCName standard to be valid, you can run them through
the xs:NCName standard to be valid, you can run them through
IColladaMeshWriter::toNCName to ensure that.
*/
virtual irr::core::stringc nameForNode(const scene::ISceneNode* node) = 0;
@ -190,7 +191,7 @@ namespace scene
instances per node are identical between different nodes you can reduce
the number of exported materials using that knowledge by using identical
names for such shared materials.
Names must follow the xs::NCName standard to be valid, you can run them
Names must follow the xs:NCName standard to be valid, you can run them
through IColladaMeshWriter::toNCName to ensure that.
*/
virtual irr::core::stringc nameForMaterial(const video::SMaterial & material, int materialId, const scene::IMesh* mesh, const scene::ISceneNode* node) = 0;
@ -382,7 +383,7 @@ namespace scene
return DefaultNameGenerator;
}
//! Restrict the characters of oldString a set of allowed characters in xs::NCName and add the prefix.
//! Restrict the characters of oldString a set of allowed characters in xs:NCName and add the prefix.
/** A tool function to help when using a custom name generator to generative valid names for collada names and id's. */
virtual irr::core::stringc toNCName(const irr::core::stringc& oldString, const irr::core::stringc& prefix=irr::core::stringc("_NC_")) const = 0;

View File

@ -332,6 +332,22 @@ CColladaFileLoader::CColladaFileLoader(scene::ISceneManager* smgr,
setDebugName("CColladaFileLoader");
#endif
// Escape characters, see https://www.w3schools.com/tags/ref_urlencode.asp
// TODO: There should be more, but usually people just escape the space character anyway.
// And I'm not sure if our xml files are utf-8 or windows-1252, so let's avoid the ambiguous ones.
EscapeCharsAnyURI.push_back(EscapeCharacterURL(' ', "%20"));
EscapeCharsAnyURI.push_back(EscapeCharacterURL('"', "%22"));
EscapeCharsAnyURI.push_back(EscapeCharacterURL('#', "%23"));
EscapeCharsAnyURI.push_back(EscapeCharacterURL('$', "%24"));
EscapeCharsAnyURI.push_back(EscapeCharacterURL('%', "%25"));
EscapeCharsAnyURI.push_back(EscapeCharacterURL('&', "%26"));
EscapeCharsAnyURI.push_back(EscapeCharacterURL('\'', "%27"));
EscapeCharsAnyURI.push_back(EscapeCharacterURL('(', "%28"));
EscapeCharsAnyURI.push_back(EscapeCharacterURL(')', "%29"));
EscapeCharsAnyURI.push_back(EscapeCharacterURL('/', "%2F"));
EscapeCharsAnyURI.push_back(EscapeCharacterURL('\\', "%5C"));
TextureLoader = new CMeshTextureLoader( FileSystem, SceneManager->getVideoDriver() );
}
@ -1209,6 +1225,7 @@ void CColladaFileLoader::readImage(io::IXMLReaderUTF8* reader)
reader->read();
image.Source = reader->getNodeData();
image.Source.trim();
unescape(image.Source);
image.SourceIsFilename=true;
}
else
@ -2742,8 +2759,8 @@ void CColladaFileLoader::clearData()
//! changes the XML URI into an internal id
void CColladaFileLoader::uriToId(core::stringc& str)
{
// currently, we only remove the # from the begin if there
// because we simply don't support referencing other files.
// Currently, we only remove the # from the beginning
// as we don't support referencing other files.
if (!str.size())
return;
@ -2942,6 +2959,47 @@ core::matrix4 CColladaFileLoader::flipZAxis(const core::matrix4& m)
return matrix;
}
void CColladaFileLoader::unescape(irr::core::stringc& uri)
{
u32 len = uri.size();
for (u32 i=0; i<len-1; ++i)
{
if (uri[i] == '%' )
{
if (uri[i+1] == '%')
{
++i;
continue;
}
for (u32 e = 0; e < EscapeCharsAnyURI.size(); ++e)
{
const irr::core::stringc& escapeString = EscapeCharsAnyURI[e].Escape;
const u32 escapeLen = escapeString.size();
bool equals = true;
for ( u32 c = 1; c<escapeLen; ++c) // string compare (and we already know first on fits as always '%')
{
if ( uri[i+c] != escapeString[c] )
{
equals = false;
break;
}
}
if ( equals )
{
uri[i] = EscapeCharsAnyURI[e].Character;
// TODO: core::string has no erase function which erases more than one char at a time currently
for ( u32 a=0;a<escapeLen-1; ++a)
uri.erase(i+1);
len -= escapeLen-1;
break;
}
}
}
}
}
} // end namespace scene
} // end namespace irr

View File

@ -344,6 +344,9 @@ private:
//! Note that function is symmetric (no difference if called before or after a transpose).
core::matrix4 flipZAxis(const core::matrix4& m);
//! replace escape characters with the unescaped ones
void unescape(irr::core::stringc& uri);
scene::ISceneManager* SceneManager;
io::IFileSystem* FileSystem;
@ -369,6 +372,19 @@ private:
core::array< core::array<irr::scene::IMeshBuffer*> > MeshesToBind;
bool CreateInstances;
struct EscapeCharacterURL
{
EscapeCharacterURL(irr::c8 c, const irr::c8* e)
: Character(c)
{
Escape = e;
}
irr::c8 Character; // unescaped (like ' ')
irr::core::stringc Escape; // escaped (like '%20')
};
irr::core::array<EscapeCharacterURL> EscapeCharsAnyURI;
};

View File

@ -178,7 +178,7 @@ irr::core::stringc CColladaMeshWriterNames::nameForMesh(const scene::IMesh* mesh
irr::core::stringc CColladaMeshWriterNames::nameForNode(const scene::ISceneNode* node)
{
irr::core::stringc name;
// Prefix, because xs::ID can't start with a number, also nicer name
// Prefix, because xs:ID can't start with a number, also nicer name
if ( node && node->getType() == ESNT_LIGHT )
name = "light";
else
@ -1225,7 +1225,7 @@ bool CColladaMeshWriter::isXmlNameChar(c8 c) const
*/
}
// Restrict the characters to a set of allowed characters in xs::NCName.
// Restrict the characters to a set of allowed characters in xs:NCName.
irr::core::stringc CColladaMeshWriter::toNCName(const irr::core::stringc& oldString, const irr::core::stringc& prefix) const
{
irr::core::stringc result(prefix); // help to ensure id starts with a valid char and reduce chance of name-conflicts
@ -1260,7 +1260,7 @@ const irr::core::stringc* CColladaMeshWriter::findGeometryNameForNode(ISceneNode
return &colladaMesh.findGeometryNameForNode(node);
}
// Restrict the characters to a set of allowed characters in xs::anyURI
// Restrict the characters to a set of allowed characters in xs:anyURI
irr::core::stringc CColladaMeshWriter::pathToURI(const irr::io::path& path) const
{
irr::core::stringc result;
@ -1280,7 +1280,7 @@ irr::core::stringc CColladaMeshWriter::pathToURI(const irr::io::path& path) cons
}
result.append(path);
// Make correct URI (without whitespaces)
// Make correct URI (without whitespace)
u32 len = result.size();
for (u32 i=0; i<len; ++i)
{
@ -1404,7 +1404,7 @@ void CColladaMeshWriter::writeMaterialEffect(const irr::core::stringc& materialf
// <init_from>internal_texturename</init_from>
Writer->writeElement("init_from", false);
irr::io::path p(FileSystem->getRelativeFilename(layer.Texture->getName().getPath(), Directory));
Writer->writeText(toNCName(irr::core::stringc(p)).c_str());
Writer->writeText(toNCName(irr::core::stringc(p)).c_str()); // same ID for internal name as in writeLibraryImages
Writer->writeClosingTag("init_from");
Writer->writeLineBreak();

View File

@ -93,7 +93,7 @@ public:
//! writes a mesh
virtual bool writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 flags=EMWF_NONE) _IRR_OVERRIDE_;
// Restrict the characters of oldString a set of allowed characters in xs::NCName and add the prefix.
// Restrict the characters of oldString a set of allowed characters in xs:NCName and add the prefix.
virtual irr::core::stringc toNCName(const irr::core::stringc& oldString, const irr::core::stringc& prefix=irr::core::stringc("_NC_")) const _IRR_OVERRIDE_;
//! After export you can find out which name had been used for writing the geometry for this node.
@ -269,8 +269,8 @@ protected:
Escape = e;
}
irr::c8 Character;
irr::core::stringc Escape;
irr::c8 Character; // unescaped (like ' ')
irr::core::stringc Escape; // escaped (like '%20')
};
irr::core::array<EscapeCharacterURL> EscapeCharsAnyURI;
};