272 lines
7.7 KiB
C++
272 lines
7.7 KiB
C++
//
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
// Copyright (c) Contributors to the OpenEXR Project.
|
|
//
|
|
|
|
#ifndef _PxDeepBaseHelper_h_
|
|
#define _PxDeepBaseHelper_h_
|
|
|
|
#include "PxDeepOutPixel.h"
|
|
#include "PxDeepOutRow.h"
|
|
#include "PxDeepUtils.h"
|
|
|
|
#include <dtex.h>
|
|
|
|
#include <ImfChannelList.h>
|
|
#include <ImfDeepScanLineOutputFile.h>
|
|
#include <ImfPartType.h>
|
|
|
|
#include <ImathBox.h>
|
|
#include <ImathVec.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
|