43
43
#include " DDImage/Pixel.h"
44
44
#include " DDImage/Tile.h"
45
45
#include " IECore/CachedReader.h"
46
+ #include " IECore/FastFloat.h"
46
47
#include " IECore/Reader.h"
47
48
#include " IECore/NumericParameter.h"
48
49
#include " boost/algorithm/string.hpp"
@@ -223,9 +224,10 @@ void LensDistort::_validate(bool for_real)
223
224
}
224
225
225
226
// Set the output bounding box according to the lens model.
227
+ bool black = input0 ().black_outside ();
226
228
Imath::Box2i input ( Imath::V2i ( input0 ().info ().x (), input0 ().info ().y () ), Imath::V2i ( input0 ().info ().r ()-1 , input0 ().info ().t ()-1 ) );
227
229
Imath::Box2i box ( m_model[0 ]->bounds ( m_mode, input, format ().width (), format ().height () ) );
228
- info_.set ( box.min .x , box.min .y , box.max .x , box.max .y );
230
+ info_.set ( box.min .x -black , box.min .y -black , box.max .x +black , box.max .y +black );
229
231
230
232
set_out_channels ( Mask_All );
231
233
}
@@ -243,6 +245,14 @@ void LensDistort::_request( int x, int y, int r, int t, ChannelMask channels, in
243
245
244
246
void LensDistort::engine ( int y, int x, int r, ChannelMask channels, Row & outrow )
245
247
{
248
+ // Provide an early-out for any black rows.
249
+ bool blackOutside = info ().black_outside ();
250
+ if ( blackOutside && ( y == info ().t ()-1 || y == info ().y () ) )
251
+ {
252
+ outrow.erase ( channels );
253
+ return ;
254
+ }
255
+
246
256
const Info &info = input0 ().info ();
247
257
const double h ( format ().height () );
248
258
const double w ( format ().width () );
@@ -305,10 +315,20 @@ void LensDistort::engine( int y, int x, int r, ChannelMask channels, Row & outro
305
315
DD::Image::Pixel out (channels);
306
316
307
317
// Lock the tile into the cache
308
- DD::Image::Tile t ( input0 (), int (floor (x_min)), int (floor (y_min)), int (ceil (x_max)), int (ceil (y_max)), channels );
309
-
310
- // Loop over our array of precomputed points, and ask nuke to perform a filtered lookup for us
311
- for ( int i = x; i < r; i++ )
318
+ DD::Image::Tile t ( input0 (), IECore::fastFloatFloor ( x_min ), IECore::fastFloatFloor ( y_min ), IECore::fastFloatCeil ( x_max ), IECore::fastFloatCeil ( y_max ), channels );
319
+
320
+ // Write the black outside pixels.
321
+ if ( blackOutside )
322
+ {
323
+ foreach ( z, channels )
324
+ {
325
+ outrow.writable (z)[x] = 0 .f ;
326
+ outrow.writable (z)[r-1 ] = 0 .f ;
327
+ }
328
+ }
329
+
330
+ // Loop over our array of precomputed points, and ask nuke to perform a filtered lookup for us.
331
+ for ( int i = x+blackOutside; i < r-blackOutside; i++ )
312
332
{
313
333
if (aborted ()) break ;
314
334
input0 ().sample ( distort[i-x].x +0.5 , distort[i-x].y +0.5 , 1.0 , 1.0 , &m_filter, out );
@@ -317,7 +337,6 @@ void LensDistort::engine( int y, int x, int r, ChannelMask channels, Row & outro
317
337
outrow.writable (z)[i] = out[z];
318
338
}
319
339
}
320
-
321
340
}
322
341
323
342
void LensDistort::append ( DD::Image::Hash &hash )
@@ -486,32 +505,38 @@ void LensDistort::updatePluginAttributesFromKnobs()
486
505
487
506
int LensDistort::knob_changed (Knob* k)
488
507
{
489
- bool updateUI = false ;
490
-
491
508
// If the lensFileSequence knob just changed then we need to check if it is valid and load it.
492
- // Once loaded then we set the updateUI flag to trigger a UI update.
493
509
if ( k->is ( " lensFileSequence" ) )
494
510
{
511
+ bool updateRequired = false ;
512
+
495
513
std::string path;
496
514
bool oldValue = m_useFileSequence;
497
515
m_useFileSequence = getFileSequencePath ( path );
498
- updateUI |= oldValue != m_useFileSequence;
516
+ updateRequired |= oldValue != m_useFileSequence;
499
517
500
518
if ( m_useFileSequence )
501
519
{
502
520
bool oldValue = m_hasValidFileSequence;
503
521
std::string path;
504
522
m_hasValidFileSequence = setLensFromFile ( path );
505
- updateUI |= m_hasValidFileSequence != oldValue;
523
+ updateRequired |= m_hasValidFileSequence != oldValue;
524
+ }
525
+
526
+ if ( updateRequired )
527
+ {
528
+ updateUI ();
506
529
}
507
530
531
+ return true ;
508
532
}
509
533
510
534
// If the lens model was just changed then we need to set it internally and then update the UI.
511
535
if ( k->is ( " model" ) )
512
536
{
513
537
setLensModel ( modelNames ()[getLensModel ()] );
514
- updateUI = true ;
538
+ updateUI ();
539
+ return true ;
515
540
}
516
541
517
542
// Update our internal reference of the knob value that just changed...
@@ -531,27 +556,28 @@ int LensDistort::knob_changed(Knob* k)
531
556
}
532
557
}
533
558
534
- if ( k->is ( " lensFileSequence" ) ) return true ;
535
-
536
559
// Do we need to update the UI?
537
- if ( k == &Knob::showPanel || updateUI )
560
+ if ( k == &Knob::showPanel )
538
561
{
539
- m_numNewKnobs = replace_knobs ( m_lastStaticKnob, m_numNewKnobs, addDynamicKnobs, this ->firstOp () );
540
-
541
- // Handle the knobs state.
542
- if ( knob (" model" ) != NULL ) knob (" model" )->enable ( !m_useFileSequence );
543
- for ( PluginAttributeList::iterator it = m_pluginAttributes.begin (); it != m_pluginAttributes.end (); it++ )
544
- {
545
- if ( it->m_knob != NULL ) it->m_knob ->enable ( !m_useFileSequence );
546
- }
547
-
562
+ updateUI ();
548
563
return true ;
549
564
}
550
565
551
-
552
566
return Iop::knob_changed (k);
553
567
}
554
568
569
+ void LensDistort::updateUI ()
570
+ {
571
+ m_numNewKnobs = replace_knobs ( m_lastStaticKnob, m_numNewKnobs, addDynamicKnobs, this ->firstOp () );
572
+
573
+ // Handle the knobs state.
574
+ if ( knob (" model" ) != NULL ) knob (" model" )->enable ( !m_useFileSequence );
575
+ for ( PluginAttributeList::iterator it = m_pluginAttributes.begin (); it != m_pluginAttributes.end (); it++ )
576
+ {
577
+ if ( it->m_knob != NULL ) it->m_knob ->enable ( !m_useFileSequence );
578
+ }
579
+ }
580
+
555
581
void LensDistort::buildDynamicKnobs (void * p, DD::Image::Knob_Callback f)
556
582
{
557
583
PluginAttributeList& attributeList ( ((LensDistort*)p)->attributeList () );
0 commit comments