Skip to content

Commit

Permalink
IECoreUSD : Use / for resolved paths.
Browse files Browse the repository at this point in the history
On Windows, the result of USD's `GetResolvedPath()` method returns the
resolved path using `\` between directories. This can cause problems
when doing string substition on a resolved path since the `\` will be
interpreted as the start of an escape character. Using `/` also
conforms to Cortex's standard of always using `/` for paths because they
work on all operating systems.
  • Loading branch information
ericmehl authored and johnhaddon committed Sep 18, 2024
1 parent cdc0cc1 commit 00721c4
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 5 deletions.
1 change: 1 addition & 0 deletions Changes
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Fixes
- Fixed loading of skinned facevarying normals.
- `lightLink` and `shadowLink` collections on UsdLuxLightAPI are no longer treated as sets.
- Version.h : Fixed `*Version()` functions to return the runtime version of the library, not the version that client code was compiled with. Use the `CORTEX_*_VERSION` macros for compile time checks.
- IECoreUSD : Asset and volume paths now use `/` in the resolved path on all operating systems. This behavior can be disabled by setting the `IECOREUSD_FORCE_ASSET_PATH_FORWARD_SLASH` environment variable to a value of `0`.

10.5.9.2 (relative to 10.5.9.1)
========
Expand Down
35 changes: 33 additions & 2 deletions contrib/IECoreUSD/src/IECoreUSD/DataAlgo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ IECORE_POP_DEFAULT_VISIBILITY

#include "boost/unordered_map.hpp"

#ifdef _MSC_VER
#include <filesystem>
#endif

using namespace std;
using namespace pxr;
using namespace IECore;
Expand Down Expand Up @@ -92,6 +96,19 @@ GeometricData::Interpretation interpretation( TfToken role )
return GeometricData::None;
}

#ifdef _MSC_VER

static const bool g_forceAssetPathForwardSlash = []() -> bool {
const char *c = getenv( "IECOREUSD_FORCE_ASSET_PATH_FORWARD_SLASH" );
if( !c )
{
return true;
}
return strcmp( c, "0" );
}();

#endif

} // namespace


Expand Down Expand Up @@ -142,9 +159,16 @@ IECore::DataPtr dataFromArray( const pxr::VtValue &value, GeometricData::Interpr

IECore::DataPtr dataFromSdfAssetPath( const SdfAssetPath &assetPath, const pxr::UsdAttribute *attribute = nullptr )
{
if( assetPath.GetResolvedPath().size() || !assetPath.GetAssetPath().size() || !attribute )

#ifdef _MSC_VER
const std::string p = g_forceAssetPathForwardSlash ? std::filesystem::path( assetPath.GetResolvedPath() ).generic_string() : assetPath.GetResolvedPath();
#else
const std::string p = assetPath.GetResolvedPath();
#endif

if( p.size() || !assetPath.GetAssetPath().size() || !attribute )
{
return new StringData( assetPath.GetResolvedPath() );
return new StringData( p );
}

// Path resolution failed, for a couple of possible reasons :
Expand All @@ -168,9 +192,16 @@ IECore::DataPtr dataFromSdfAssetPath( const SdfAssetPath &assetPath, const pxr::
spec->GetLayer()->GetNumTimeSamplesForPath( spec->GetPath() )
)
{
#ifdef _MSC_VER
const std::string result = SdfComputeAssetPathRelativeToLayer( spec->GetLayer(), assetPath.GetAssetPath() );
return new StringData(
g_forceAssetPathForwardSlash ? std::filesystem::path( result ).generic_string() : result
);
#else
return new StringData(
SdfComputeAssetPathRelativeToLayer( spec->GetLayer(), assetPath.GetAssetPath() )
);
#endif
}
}

Expand Down
7 changes: 4 additions & 3 deletions contrib/IECoreUSD/src/IECoreUSD/VolumeAlgo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,13 @@
//
//////////////////////////////////////////////////////////////////////////

#include "IECoreUSD/DataAlgo.h"
#include "IECoreUSD/ObjectAlgo.h"

#include "IECoreVDB/VDBObject.h"

#include "IECore/MessageHandler.h"
#include "IECore/SimpleTypedData.h"

IECORE_PUSH_DEFAULT_VISIBILITY
#include "pxr/usd/usdVol/volume.h"
Expand Down Expand Up @@ -96,9 +98,8 @@ IECore::ObjectPtr readVolume( pxr::UsdVolVolume &volume, pxr::UsdTimeCode time,
continue;
}

SdfAssetPath fieldAssetPath;
fieldAsset.GetFilePathAttr().Get( &fieldAssetPath, time );
const std::string fieldFileName = fieldAssetPath.GetResolvedPath();
ConstDataPtr fieldFileNameData = DataAlgo::fromUSD( fieldAsset.GetFilePathAttr(), time );
const std::string fieldFileName = static_cast<const StringData *>( fieldFileNameData.get() )->readable();

if( fileName.empty() )
{
Expand Down
27 changes: 27 additions & 0 deletions contrib/IECoreUSD/test/IECoreUSD/USDSceneTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
#
##########################################################################

import IECore

import importlib
import os
import math
Expand Down Expand Up @@ -4371,5 +4373,30 @@ def testWriteToOpenScene( self ) :
with self.assertRaisesRegex( RuntimeError, f"USDScene : Failed to open USD stage : '{fileName}'" ) :
IECoreScene.SceneInterface.create( fileName, IECore.IndexedIO.OpenMode.Write )

def testAssetPathSlashes ( self ) :

root = IECoreScene.SceneInterface.create(
os.path.join( os.path.dirname( __file__ ), "data", "assetPathAttribute.usda" ),
IECore.IndexedIO.OpenMode.Read
)
xform = root.child( "xform" )

self.assertEqual( xform.attributeNames(), [ "render:testAsset" ] )
self.assertNotIn( "\\", xform.readAttribute( "render:testAsset", 0 ).value )
self.assertTrue( pathlib.Path( xform.readAttribute( "render:testAsset", 0 ).value ).is_file() )

@unittest.skipIf( not haveVDB, "No IECoreVDB" )
def testUsdVolVolumeSlashes( self ) :

import IECoreVDB

fileName = os.path.dirname( __file__ ) + "/data/volume.usda"
root = IECoreScene.SceneInterface.create( fileName, IECore.IndexedIO.OpenMode.Read )
child = root.child( "volume" )

vdbObject = child.readObject( 0 )
self.assertNotIn( "\\", vdbObject.fileName() )
self.assertTrue( pathlib.Path( vdbObject.fileName() ).is_file() )

if __name__ == "__main__":
unittest.main()

0 comments on commit 00721c4

Please sign in to comment.