Skip to content

Commit 664ed34

Browse files
committed
Merge pull request #189 from goddardl/NativeDeepReader
IECoreNuke::DeepImageReader
2 parents f909d9a + 46e3724 commit 664ed34

File tree

7 files changed

+465
-1
lines changed

7 files changed

+465
-1
lines changed

config/ie/options

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ DOXYGEN = os.path.join( "/software/apps/doxygen", os.environ["DOXYGEN_VERSION"],
360360
ENV_VARS_TO_IMPORT="PATH COMPILER COMPILER_VERSION PYTHONPATH IEENV_ROOT IEENV_WORKING_PATH IEENV_LIBRARY_PREFIX_PATH DOXYGEN_VERSION IEENV_DEBUG IEENV_DEBUG_PYTHON IEENV_DEBUGGER IEENV_DEBUGGER_ARGS DELIGHT_CONF SCONS_VERSION DL_VERSION DL_SHADERS_PATH DL_DISPLAYS_PATH"
361361

362362
# make sure the tests can run
363-
TEST_LIBPATH = ":".join( [ pythonReg["location"] + "/" + compiler + "/" + compilerVersion + "/lib", compilerReg["location"] + "/lib" ] )
363+
TEST_LIBPATH = ":".join( [ pythonReg["location"] + "/" + compiler + "/" + compilerVersion + "/lib", compilerReg["location"] + "/lib", dlReg["location"] + "/lib" ] )
364364
TEST_LIBRARY_PATH_ENV_VAR = "IEENV_LIBRARY_PREFIX_PATH"
365365

366366
# install the op stubs and procedural stubs
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
//////////////////////////////////////////////////////////////////////////
2+
//
3+
// Copyright (c) 2013, Image Engine Design Inc. All rights reserved.
4+
//
5+
// Redistribution and use in source and binary forms, with or without
6+
// modification, are permitted provided that the following conditions are
7+
// met:
8+
//
9+
// * Redistributions of source code must retain the above copyright
10+
// notice, this list of conditions and the following disclaimer.
11+
//
12+
// * Redistributions in binary form must reproduce the above copyright
13+
// notice, this list of conditions and the following disclaimer in the
14+
// documentation and/or other materials provided with the distribution.
15+
//
16+
// * Neither the name of Image Engine Design nor the names of any
17+
// other contributors to this software may be used to endorse or
18+
// promote products derived from this software without specific prior
19+
// written permission.
20+
//
21+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
22+
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23+
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24+
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
25+
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26+
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27+
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28+
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29+
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30+
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31+
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32+
//
33+
//////////////////////////////////////////////////////////////////////////
34+
35+
#ifndef IECORENUKE_DEEPIMAGEREADER_H
36+
#define IECORENUKE_DEEPIMAGEREADER_H
37+
38+
#include "DDImage/Knobs.h"
39+
#include "DDImage/Thread.h"
40+
#include "DDImage/DeepReader.h"
41+
#include "DDImage/DeepPlane.h"
42+
43+
namespace IECoreNuke
44+
{
45+
46+
/// This class can be extended to expose reader options that will be
47+
/// displayed on Nuke's DeepRead node.
48+
class DeepImageReaderFormats : public DD::Image::DeepReaderFormat
49+
{
50+
void append( DD::Image::Hash &h)
51+
{
52+
}
53+
54+
void knobs( DD::Image::Knob_Callback f )
55+
{
56+
}
57+
};
58+
59+
/// Reads DeepImage files that are supported by cortex.
60+
/// The DeepImageReader enables support for the deep image types
61+
/// registered to cortex from Nuke's DeepReader node.
62+
class DeepImageReader : public DD::Image::DeepReader
63+
{
64+
65+
public:
66+
67+
DeepImageReader( DD::Image::DeepReaderOwner *op, const std::string &fileName );
68+
69+
virtual bool doDeepEngine( DD::Image::Box box, const DD::Image::ChannelSet &channels, DD::Image::DeepOutputPlane &plane );
70+
virtual const DD::Image::MetaData::Bundle &fetchMetaData( const char *key );
71+
72+
static const char *supportedExtensions();
73+
static DD::Image::DeepReader *build( DD::Image::DeepReaderOwner *op, const std::string &fn );
74+
static DD::Image::DeepReaderFormat *buildformat( DD::Image::DeepReaderOwner *op );
75+
static const DD::Image::DeepReader::Description g_description;
76+
77+
private:
78+
79+
/// Loads an image and sets m_reader to the reader for the file. If an Exception is
80+
/// raised then the reason is saved and returned in errorMsg.
81+
/// Returns true if the file was successfully loaded.
82+
bool loadFileFromPath( const std::string &filePath, std::string &errorMsg );
83+
84+
/// Holds the path of the file that is currently being read.
85+
std::string m_currentPath;
86+
87+
/// A mutex which ensures that only one thread reads from the file at once.
88+
DD::Image::Lock m_lock;
89+
90+
/// The data window of the file. This is set within loadFileFromPath().
91+
DD::Image::Box m_dataWindow;
92+
93+
/// The channels within the file. This is set within loadFileFromPath().
94+
DD::Image::ChannelSet m_channels;
95+
96+
/// The cortex reader that we use to read the file.
97+
IECore::DeepImageReaderPtr m_reader;
98+
99+
/// A map of Channels to indexes within the IECore::DeepPixel class's channelData().
100+
std::map< DD::Image::Channel, int > m_channelMap;
101+
102+
/// The metadata of the deep image.
103+
DD::Image::MetaData::Bundle m_meta;
104+
};
105+
106+
}; // namespace IECoreNuke
107+
108+
#endif

src/IECoreNuke/DeepImageReader.cpp

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
//////////////////////////////////////////////////////////////////////////
2+
//
3+
// Copyright (c) 2013, Image Engine Design Inc. All rights reserved.
4+
//
5+
// Redistribution and use in source and binary forms, with or without
6+
// modification, are permitted provided that the following conditions are
7+
// met:
8+
//
9+
// * Redistributions of source code must retain the above copyright
10+
// notice, this list of conditions and the following disclaimer.
11+
//
12+
// * Redistributions in binary form must reproduce the above copyright
13+
// notice, this list of conditions and the following disclaimer in the
14+
// documentation and/or other materials provided with the distribution.
15+
//
16+
// * Neither the name of Image Engine Design nor the names of any
17+
// other contributors to this software may be used to endorse or
18+
// promote products derived from this software without specific prior
19+
// written permission.
20+
//
21+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
22+
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23+
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24+
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
25+
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26+
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27+
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28+
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29+
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30+
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31+
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32+
//
33+
//////////////////////////////////////////////////////////////////////////
34+
35+
#include "IECore/DeepImageReader.h"
36+
#include "IECore/DeepPixel.h"
37+
38+
#include "IECoreNuke/DeepImageReader.h"
39+
40+
namespace IECoreNuke
41+
{
42+
43+
DeepImageReader::DeepImageReader( DD::Image::DeepReaderOwner *op, const std::string &fileName ) :
44+
DD::Image::DeepReader( op )
45+
{
46+
std::string errorMsg;
47+
if( !loadFileFromPath( fileName, errorMsg ) )
48+
{
49+
_op->error( errorMsg.c_str() );
50+
return;
51+
}
52+
53+
// Set the output size, channels and context.
54+
int width = m_reader->displayWindow().size().x + 1;
55+
int height = m_reader->displayWindow().size().y + 1;
56+
setInfo( width, height, _owner->readerOutputContext(), m_channels );
57+
58+
// Set the metadata.
59+
Imath::M44f cam = m_reader->worldToCameraMatrix();
60+
m_meta.setData( "cortex/worldToCamera", &cam[0][0], 16 );
61+
62+
Imath::M44f ndc = m_reader->worldToNDCMatrix();
63+
m_meta.setData( "cortex/worldToNDC", &ndc[0][0], 16 );
64+
}
65+
66+
bool DeepImageReader::doDeepEngine( DD::Image::Box box, const DD::Image::ChannelSet &channels, DD::Image::DeepOutputPlane &plane )
67+
{
68+
plane = DD::Image::DeepOutputPlane( channels, box );
69+
70+
if( !m_reader || m_channels.empty() )
71+
{
72+
for( int y = box.y(); y < box.t(); ++y )
73+
{
74+
for( int ox = box.x(); ox != box.r(); ++ox )
75+
{
76+
plane.addHole();
77+
}
78+
}
79+
80+
return true;
81+
}
82+
83+
DD::Image::Guard g( m_lock );
84+
Imath::Box2i displayWindow( m_reader->displayWindow() );
85+
86+
for( int y = box.y(); y < box.t(); ++y )
87+
{
88+
if( y < m_dataWindow.y() || y >= m_dataWindow.t() )
89+
{
90+
for( int ox = box.x(); ox != box.r(); ++ox )
91+
{
92+
plane.addHole();
93+
}
94+
continue;
95+
}
96+
97+
int minX = std::min( m_dataWindow.x(), box.x() );
98+
int maxX = std::max( m_dataWindow.r(), box.r() );
99+
100+
// The Y coordinate in the cortex deep image coordinate space.
101+
int cy = displayWindow.size().y - ( y - displayWindow.min[1] );
102+
103+
for( int x = minX; x < maxX; ++x )
104+
{
105+
if( x < m_dataWindow.x() || x >= m_dataWindow.r() )
106+
{
107+
plane.addHole();
108+
continue;
109+
}
110+
111+
unsigned int nSamples( 0 );
112+
113+
IECore::DeepPixelPtr pixel;
114+
try
115+
{
116+
pixel = m_reader->readPixel( x, cy );
117+
if( pixel )
118+
{
119+
nSamples = pixel->numSamples();
120+
}
121+
}
122+
catch( const IECore::Exception &e )
123+
{
124+
}
125+
126+
if( nSamples == 0 )
127+
{
128+
if( x >= box.x() || x < box.r() )
129+
{
130+
plane.addHole();
131+
}
132+
continue;
133+
}
134+
135+
if( x < box.x() || x >= box.r() )
136+
{
137+
continue;
138+
}
139+
140+
DD::Image::DeepOutPixel dop;
141+
float previousBack = pixel->getDepth( 0 );
142+
for( unsigned int i = 0; i < nSamples; ++i )
143+
{
144+
float *data( pixel->channelData( i ) );
145+
float depth = pixel->getDepth( i );
146+
DD::Image::ChannelSet allChans = m_channels + channels;
147+
foreach( z, allChans )
148+
{
149+
if( z == DD::Image::Chan_DeepFront )
150+
{
151+
dop.push_back( previousBack );
152+
previousBack = depth;
153+
}
154+
else if( z == DD::Image::Chan_DeepBack )
155+
{
156+
dop.push_back( depth );
157+
}
158+
else
159+
{
160+
if( m_channels.contains(z) )
161+
{
162+
dop.push_back( data[ m_channelMap[z] ] );
163+
}
164+
else
165+
{
166+
dop.push_back(0);
167+
}
168+
}
169+
}
170+
}
171+
plane.addPixel( dop );
172+
}
173+
}
174+
return true;
175+
}
176+
177+
bool DeepImageReader::loadFileFromPath( const std::string &filePath, std::string &errorMsg )
178+
{
179+
try
180+
{
181+
// Perform an early-out if we have already loaded the desired file.
182+
if( m_currentPath == filePath && m_reader && m_currentPath != "" )
183+
{
184+
return true;
185+
}
186+
187+
IECore::ReaderPtr object( IECore::Reader::create( filePath ) );
188+
m_reader = IECore::runTimeCast<IECore::DeepImageReader>( object );
189+
190+
if( m_reader )
191+
{
192+
m_currentPath = filePath;
193+
std::vector< std::string > channelNames;
194+
195+
m_reader->channelNames( channelNames );
196+
197+
m_channels = DD::Image::ChannelSet( DD::Image::Mask_DeepFront | DD::Image::Mask_DeepBack );
198+
m_channelMap.clear();
199+
for( std::vector< std::string >::const_iterator it( channelNames.begin() ); it != channelNames.end(); ++it )
200+
{
201+
int idx( it - channelNames.begin() );
202+
if( *it == "A" )
203+
{
204+
m_channels += DD::Image::Chan_Alpha;
205+
m_channelMap[DD::Image::Chan_Alpha] = idx;
206+
}
207+
else if( *it == "R" )
208+
{
209+
m_channels += DD::Image::Chan_Red;
210+
m_channelMap[DD::Image::Chan_Red] = idx;
211+
}
212+
else if( *it == "G" )
213+
{
214+
m_channels += DD::Image::Chan_Green;
215+
m_channelMap[DD::Image::Chan_Green] = idx;
216+
}
217+
else if( *it == "B" )
218+
{
219+
m_channels += DD::Image::Chan_Blue;
220+
m_channelMap[DD::Image::Chan_Blue] = idx;
221+
}
222+
}
223+
224+
Imath::Box2i dataWindow( m_reader->dataWindow() );
225+
m_dataWindow = DD::Image::Box( dataWindow.min[0], dataWindow.min[1], dataWindow.max[0]+1, dataWindow.max[1]+1 );
226+
errorMsg = "";
227+
return true;
228+
}
229+
else
230+
{
231+
errorMsg = "Object is not an IECore::DeepImageReader.";
232+
}
233+
}
234+
catch( const IECore::Exception &e )
235+
{
236+
errorMsg = ( boost::format( "DeepImageReader : %s" ) % e.what() ).str();
237+
}
238+
return false;
239+
}
240+
241+
DD::Image::DeepReader *DeepImageReader::build( DD::Image::DeepReaderOwner *op, const std::string &fn )
242+
{
243+
return new DeepImageReader( op, fn );
244+
}
245+
246+
DD::Image::DeepReaderFormat *DeepImageReader::buildformat( DD::Image::DeepReaderOwner *op )
247+
{
248+
return new DeepImageReaderFormats();
249+
}
250+
251+
const DD::Image::MetaData::Bundle &DeepImageReader::fetchMetaData( const char *key )
252+
{
253+
return m_meta;
254+
}
255+
256+
const char *DeepImageReader::supportedExtensions()
257+
{
258+
// We have to hard code the supported deep image types here
259+
// because we cannot call IECore::Reader::supportedExtensions
260+
// as we are inside a static initializer.
261+
// We have also omitted the IECoreDL dtex reader here as nuke
262+
// already supports it out of the box.
263+
return "shw\0dsm\0rat\0";
264+
}
265+
266+
const DD::Image::DeepReader::Description DeepImageReader::g_description( supportedExtensions(), "cortex", build, buildformat );
267+
268+
} // namespace IECoreNuke

test/IECoreNuke/All.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040

4141
from KnobAccessorsTest import *
4242
from FnAxisTest import *
43+
from DeepImageReaderTest import *
4344
from LensDistortTest import *
4445
from StringUtilTest import *
4546
from KnobConvertersTest import *

0 commit comments

Comments
 (0)