2022-04-07 18:46:57 +02:00

331 lines
12 KiB
C++

//-*****************************************************************************
// Copyright (c) 2012, Pixar. All rights reserved. *
// *
// This license governs use of the accompanying software. If you *
// use the software, you accept this license. If you do not accept *
// the license, do not use the software. *
// *
// 1. Definitions *
// The terms "reproduce," "reproduction," "derivative works," and *
// "distribution" have the same meaning here as under U.S. *
// copyright law. A "contribution" is the original software, or *
// any additions or changes to the software. *
// A "contributor" is any person or entity that distributes its *
// contribution under this license. *
// "Licensed patents" are a contributor's patent claims that read *
// directly on its contribution. *
// *
// 2. Grant of Rights *
// (A) Copyright Grant- Subject to the terms of this license, *
// including the license conditions and limitations in section 3, *
// each contributor grants you a non-exclusive, worldwide, *
// royalty-free copyright license to reproduce its contribution, *
// prepare derivative works of its contribution, and distribute *
// its contribution or any derivative works that you create. *
// (B) Patent Grant- Subject to the terms of this license, *
// including the license conditions and limitations in section 3, *
// each contributor grants you a non-exclusive, worldwide, *
// royalty-free license under its licensed patents to make, have *
// made, use, sell, offer for sale, import, and/or otherwise *
// dispose of its contribution in the software or derivative works *
// of the contribution in the software. *
// *
// 3. Conditions and Limitations *
// (A) No Trademark License- This license does not grant you *
// rights to use any contributor's name, logo, or trademarks. *
// (B) If you bring a patent claim against any contributor over *
// patents that you claim are infringed by the software, your *
// patent license from such contributor to the software ends *
// automatically. *
// (C) If you distribute any portion of the software, you must *
// retain all copyright, patent, trademark, and attribution *
// notices that are present in the software. *
// (D) If you distribute any portion of the software in source *
// code form, you may do so only under this license by including a *
// complete copy of this license with your distribution. If you *
// distribute any portion of the software in compiled or object *
// code form, you may only do so under a license that complies *
// with this license. *
// (E) The software is licensed "as-is." You bear the risk of *
// using it. The contributors give no express warranties, *
// guarantees or conditions. You may have additional consumer *
// rights under your local laws which this license cannot change. *
// To the extent permitted under your local laws, the contributors *
// exclude the implied warranties of merchantability, fitness for *
// a particular purpose and non-infringement. *
//-*****************************************************************************
//-*****************************************************************************
// Written by Pixar Animation Studios, 2011-2012.
//-*****************************************************************************
#ifndef _PxDeepBaseHelper_h_
#define _PxDeepBaseHelper_h_
#include "PxDeepUtils.h"
#include "PxDeepOutPixel.h"
#include "PxDeepOutRow.h"
#include <dtex.h>
#include <ImfDeepScanLineOutputFile.h>
#include <ImfPartType.h>
#include <ImfChannelList.h>
#include <ImathVec.h>
#include <ImathBox.h>
namespace PxDeep {
//-*****************************************************************************
// PARAMETERS STRUCT
//-*****************************************************************************
// This allows us to keep function signatures from changing around too much
// as the parameter set grows & changes, which it always does.
struct Parameters
{
Parameters()
: deepOpacity( true )
, discrete( true )
, multiplyColorByAlpha( false )
, sideways( false )
, discardZeroAlphaSamples( true )
, doDeepBack( true )
, doRGB( true )
, compressionError( 0.0f ) {}
bool deepOpacity;
bool discrete;
bool multiplyColorByAlpha;
bool sideways;
bool discardZeroAlphaSamples;
bool doDeepBack;
bool doRGB;
float compressionError;
};
//-*****************************************************************************
// BASE DEEP HELPER CLASS
//-*****************************************************************************
// The intention of this templated base class is to provide consistent
// storage vectors for spans and deep pixels across multiple pixel reads,
// so we don't slow down constantly creating and destroying std::vectors.
// This class has a "processDeepBox" function which does the work.
template <typename RGBA_T, typename DERIVED, typename SPAN>
class BaseDeepHelper
{
public:
typedef DERIVED sub_type;
typedef SPAN span_type;
BaseDeepHelper( DtexFile* i_dtexFile,
int i_numDtexChans,
const Parameters& i_params )
: m_dtexFile( i_dtexFile )
, m_numDtexChans( i_numDtexChans )
, m_params( i_params )
{
m_image = NULL;
DtexGetImageByIndex( m_dtexFile, 0, &m_image );
m_fileWidth = DtexWidth( m_image );
m_fileHeight = DtexHeight( m_image );
m_pixel = DtexMakePixel( m_numDtexChans );
m_rawPixel = DtexMakePixel( m_numDtexChans );
}
~BaseDeepHelper()
{
DtexDestroyPixel( m_pixel );
DtexDestroyPixel( m_rawPixel );
}
void processDeepBox( Imf::DeepScanLineOutputFile& o_file,
const Imath::Box2i& i_box );
protected:
DtexFile* m_dtexFile;
int m_numDtexChans;
Parameters m_params;
DtexImage* m_image;
int m_fileWidth;
int m_fileHeight;
DtexPixel* m_pixel;
DtexPixel* m_rawPixel;
std::vector<span_type> m_spans;
DeepOutPixel<RGBA_T> m_deepOutPixel;
};
//-*****************************************************************************
//-*****************************************************************************
// SPAN CLASSES
//-*****************************************************************************
//-*****************************************************************************
//-*****************************************************************************
// These span objects are used by the helper classes below to keep track
// of the information read out of the DTEX file, so it can be processed.
// They have an ordering operator which sorts them by depth and then index.
// We use double precision for 'viz', for reasons described in the 'VIZ'
// section of the explanatory comments in the PxDeepUtils library.
struct Span
{
Span() : in( 0.0f ), out( 0.0f ), viz( 0.0 ), index( 0 ) {}
float in;
float out;
double viz;
int index;
void clear()
{
in = 0.0f;
out = 0.0f;
viz = 0.0;
index = 0;
}
bool operator<( const Span& i_other ) const
{
if ( in < i_other.in )
{
return true;
}
else if ( in == i_other.in )
{
return index < i_other.index;
}
else
{
return false;
}
}
};
//-*****************************************************************************
// Because the RGB values here are unpremultiplied, we use double precision
// to avoid precision loss when going (RGB/A)*A.
struct SpanRgba : public Span
{
SpanRgba() : Span() { rgb[0] = 0.0; rgb[1] = 0.0; rgb[2] = 0.0; }
double rgb[3];
void clear()
{
Span::clear();
rgb[0] = 0.0;
rgb[1] = 0.0;
rgb[2] = 0.0;
}
};
//-*****************************************************************************
// As above, we use double precision for viz.
struct SpanOpac : public Span
{
SpanOpac() : Span(), deepViz( 0.0 ) {}
double deepViz;
void clear()
{
Span::clear();
deepViz = 0.0;
}
};
//-*****************************************************************************
// The box processing simply loops over the rows, compresses each pixel, then
// converts from dtex representation to deep exr representation, and finally
// writes the rows to the file.
template <typename RGBA_T, typename DERIVED, typename SPAN>
void BaseDeepHelper<RGBA_T,DERIVED,SPAN>::processDeepBox
(
Imf::DeepScanLineOutputFile& o_file,
const Imath::Box2i& i_box )
{
int width = ( i_box.max.x - i_box.min.x ) + 1;
DeepOutRow<RGBA_T> outRow( width, m_params.doDeepBack, m_params.doRGB );
for ( int y = i_box.max.y; y >= i_box.min.y; --y )
{
outRow.clear();
for ( int x = i_box.min.x; x <= i_box.max.x; ++x )
{
if ( m_params.sideways )
{
DtexGetPixel( m_image, m_fileWidth - 1 - y,
m_fileHeight - 1 - x, m_rawPixel );
}
else
{
DtexGetPixel( m_image, x,
m_fileHeight - 1 - y, m_rawPixel );
}
// Get the number of input points.
int numPointsIn = DtexPixelGetNumPoints( m_rawPixel );
if ( numPointsIn < 0 )
{
PXDU_THROW( "Negative num points returned at dtex pixel: "
<< x << ", " << y );
}
// Compress the pixel.
if ( numPointsIn > 1 && m_params.compressionError > 0.0f )
{
DtexCompressPixel( m_rawPixel, m_pixel,
m_params.compressionError );
DtexFinishPixel( m_pixel );
}
else
{
DtexCopyPixel( m_pixel, m_rawPixel );
DtexFinishPixel( m_pixel );
}
// Get num points of compressed pixel.
int numPts = DtexPixelGetNumPoints( m_pixel );
// If no samples here, continue on.
if ( numPts < 1 )
{
outRow.addHole( x - i_box.min.x );
continue;
}
m_deepOutPixel.clear();
m_deepOutPixel.reserve( numPts * m_numDtexChans );
// Process the deep pixels.
DERIVED* derivedThis = static_cast<DERIVED*>( this );
derivedThis->processDeepPixel( numPts );
// Add the pixel to the row.
outRow.addPixel( x - i_box.min.x, m_deepOutPixel );
}
// Create the frame buffer.
// I'm not sure if this can be reused from row to row.
Imf::DeepFrameBuffer frameBuffer;
// Set the deep out row into the framebuffer.
outRow.setFrameBuffer( frameBuffer );
// Write row.
o_file.setFrameBuffer( frameBuffer );
o_file.writePixels( 1 );
}
}
} // End namespace PxDeep
#endif