Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/IECoreNuke/ToNukeGeometryConverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ void writeAttribute( DD::Image::GeometryList &geoList, int objIndex, const char
attr->flt() = static_cast<const IECore::FloatData *>( value )->readable();
break;
}
case IECore::DoubleDataTypeId :
{
// Nuke only supports float attributes, so we narrow double to float.
auto attr = geoList.writable_attribute( objIndex, GroupType::Group_Object, name, AttribType::FLOAT_ATTRIB );
attr->flt() = static_cast<float>( static_cast<const IECore::DoubleData *>( value )->readable() );
break;
}
case IECore::IntDataTypeId :
{
auto attr = geoList.writable_attribute( objIndex, GroupType::Group_Object, name, AttribType::INT_ATTRIB );
Expand Down Expand Up @@ -94,6 +101,13 @@ void writeAttribute( DD::Image::GeometryList &geoList, int objIndex, const char
attr->vector3() = IECore::convert<DD::Image::Vector3>( static_cast<const IECore::V3fData *>( value )->readable() );
break;
}
case IECore::Color3fDataTypeId :
{
auto attr = geoList.writable_attribute( objIndex, GroupType::Group_Object, name, AttribType::VECTOR3_ATTRIB );
const auto &c = static_cast<const IECore::Color3fData *>( value )->readable();
attr->vector3() = DD::Image::Vector3( c[0], c[1], c[2] );
break;
}
case IECore::Color4fDataTypeId :
{
auto attr = geoList.writable_attribute( objIndex, GroupType::Group_Object, name, AttribType::VECTOR4_ATTRIB );
Expand Down Expand Up @@ -143,6 +157,13 @@ void writeAttribute( DD::Image::GeometryList &geoList, int objIndex, const char
attr->matrix3() = result;
break;
}
// Nuke has no equivalent for InternedString types, so we silently skip them.
// We could convert InternedStringVectorData to a delimited string, but
// round-tripping wouldn't be transparent — LiveScene would need special
// handling to split the string back into a vector.
case IECore::InternedStringDataTypeId :
case IECore::InternedStringVectorDataTypeId :
break;
default :
IECore::msg( IECore::Msg::Warning, "ToNukeGeometryConverter", boost::format( "Unsupported attribute type \"%s\" for \"%s\"" ) % value->typeName() % name );
break;
Expand Down
82 changes: 82 additions & 0 deletions test/IECoreNuke/LiveSceneKnobTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,88 @@ def testAttributes( self ) :
self.assertEqual( attr.value, imath.M44f( expectedAttr.value ) )


def testAttributeTypeRoundTrip( self ) :
import imath
import IECoreScene
import tempfile
import os

# Create a temporary SCC with various attribute types on a leaf location.
tmpDir = tempfile.mkdtemp()
sceneFile = os.path.join( tmpDir, "attrTypes.scc" )

scene = IECoreScene.SceneCache( sceneFile, IECore.IndexedIO.OpenMode.Write )
child = scene.createChild( "obj" )
child.writeObject( IECoreScene.MeshPrimitive.createBox( imath.Box3f( imath.V3f( -1 ), imath.V3f( 1 ) ) ), 0.0 )
child.writeTransform( IECore.M44dData( imath.M44d() ), 0.0 )

child.writeAttribute( "user:testFloat", IECore.FloatData( 1.5 ), 0.0 )
child.writeAttribute( "user:testDouble", IECore.DoubleData( 2.5 ), 0.0 )
child.writeAttribute( "user:testInt", IECore.IntData( 42 ), 0.0 )
child.writeAttribute( "user:testBool", IECore.BoolData( True ), 0.0 )
child.writeAttribute( "user:testString", IECore.StringData( "hello" ), 0.0 )
child.writeAttribute( "user:testInternedString", IECore.InternedStringData( "skipped" ), 0.0 )
child.writeAttribute( "user:testV2f", IECore.V2fData( imath.V2f( 1, 2 ) ), 0.0 )
child.writeAttribute( "user:testV3f", IECore.V3fData( imath.V3f( 1, 2, 3 ) ), 0.0 )
child.writeAttribute( "user:testColor3f", IECore.Color3fData( imath.Color3f( 0.1, 0.2, 0.3 ) ), 0.0 )
child.writeAttribute( "user:testColor4f", IECore.Color4fData( imath.Color4f( 0.1, 0.2, 0.3, 0.4 ) ), 0.0 )
child.writeAttribute( "user:testM33f", IECore.M33fData( imath.M33f() ), 0.0 )
child.writeAttribute( "user:testM44f", IECore.M44fData( imath.M44f() ), 0.0 )
child.writeAttribute( "user:testM44d", IECore.M44dData( imath.M44d() ), 0.0 )

del child, scene

mh = IECore.CapturingMessageHandler()
with mh :
sceneReader = nuke.createNode( "ieSceneCacheReader" )
sceneReader.knob( "file" ).setValue( sceneFile )
sceneReader.forceValidate()
widget = sceneReader.knob( "sceneView" )
widget.setSelectedItems( ["/root/obj"] )

n = nuke.createNode( "ieLiveScene" )
n.setInput( 0, sceneReader )

liveScene = n.knob( "scene" ).getValue()
leaf = liveScene.scene( ["obj"] )

# Each attribute type round-trips through Nuke. Some types change
# (e.g. DoubleData -> FloatData, Color3fData -> V3fData) because
# Nuke only has float-precision attribute types.
cases = [
( "user:testFloat", IECore.FloatData, 1.5 ),
( "user:testDouble", IECore.FloatData, 2.5 ),
( "user:testInt", IECore.IntData, 42 ),
( "user:testBool", IECore.IntData, 1 ),
( "user:testString", IECore.StringData, "hello" ),
( "user:testV2f", IECore.V2fData, imath.V2f( 1, 2 ) ),
( "user:testV3f", IECore.V3fData, imath.V3f( 1, 2, 3 ) ),
( "user:testColor3f", IECore.V3fData, imath.V3f( 0.1, 0.2, 0.3 ) ),
( "user:testColor4f", IECore.Color4fData, imath.Color4f( 0.1, 0.2, 0.3, 0.4 ) ),
( "user:testM33f", IECore.M33fData, imath.M33f() ),
( "user:testM44f", IECore.M44fData, imath.M44f() ),
( "user:testM44d", IECore.M44fData, imath.M44f() ),
]

for name, expectedType, expectedValue in cases :
self.assertIn( name, leaf.attributeNames() )
self.assertTrue( leaf.hasAttribute( name ) )
attr = leaf.readAttribute( name, 0 )
self.assertIsInstance( attr, expectedType, f"Wrong type for {name}: {type( attr )}" )
self.assertEqual( attr.value, expectedValue, f"Wrong value for {name}" )

# InternedStringData has no Nuke equivalent and should be silently skipped.
self.assertNotIn( "user:testInternedString", leaf.attributeNames() )
self.assertFalse( leaf.hasAttribute( "user:testInternedString" ) )

# No warnings should have been emitted for the skipped type.
warnings = [m for m in mh.messages if m.level == IECore.Msg.Level.Warning]
self.assertEqual( warnings, [] )

os.remove( sceneFile )
os.rmdir( tmpDir )


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

Loading