// Copyright (c) 2011 The Foundry Visionmongers Ltd. All Rights Reserved. #include "DDImage/DeepReader.h" #include "DDImage/DeepPlane.h" #include "DDImage/Knobs.h" #include "DDImage/Thread.h" #include "dtex.h" #include "rx.h" using namespace DD::Image; namespace Nuke { namespace Deep { static inline bool IsRGB(Channel channel) { return channel == Chan_Red || channel == Chan_Blue || channel == Chan_Green; } static inline bool IsRGBA(Channel channel) { return channel == Chan_Red || channel == Chan_Blue || channel == Chan_Green || channel == Chan_Alpha; } /** * Fetch the major version of renderman. Returns -1 if indeterminable. */ static int RenderManVersion() { int version[4]; RxInfoType_t type; int count; int status = RxRendererInfo("version", &version, 4 * sizeof(int), &type, &count); if (type == RxInfoInteger && count == 4 && status == 0) return version[1]; else return -1; } class dtexDeepReaderFormat : public DeepReaderFormat { friend class dtexDeepReader; bool _raw; bool _premult; bool _discrete; public: dtexDeepReaderFormat() { _raw = false; _premult = false; _discrete = true; // NOTE this is for backwards compatibility, it is knob defaulted to false ( which is probably more correct and matches weta's implementation ) } void knobs(Knob_Callback f) { Bool_knob(f, &_raw, "raw", "raw values"); Tooltip(f, "Read the samples exactly 'as is' without processing."); Bool_knob(f, &_premult, "premult", "premultiply"); Tooltip(f, "Premultiply values from file (if off, then it assumes they are already premultiplied)"); Bool_knob(f, &_discrete, "discrete", "discrete"); Tooltip(f, "Treat the file as discrete samples with the front and back being the same. This is only relevant for deep shadow files, color deep composting files are always discrete."); } void append(Hash& hash) { hash.append(_raw); hash.append(_premult); hash.append(_discrete); } }; /** * This is a plugin to read the Pixar Renderman 'dtex' files. */ class dtexDeepReader : public DeepReader { static Lock sLibraryLock; DtexFile* _dtexFile; DtexCache* _dtexCache; Lock _engineLock; int _numChans; DD::Image::OutputContext _outputContext; int _dtexOpenError; // defined in thirdparty/sony/renderman/version/bin/platform/include/dtex.h dtexDeepReaderFormat *_dtexReaderFormat; public: dtexDeepReader(DeepReaderOwner* op, const std::string& filename) : DeepReader(op) { _dtexOpenError = DTEX_NOERR; _dtexFile = NULL; _dtexCache = NULL; if (filename.length()) open(filename); if (!_dtexFile) { if (filename.length() == 0) _op->error("no filename specified"); else if (_dtexOpenError != DTEX_NOERR) _op->error("error (%d) opening file: %s", _dtexOpenError, filename.c_str()); else _op->error("missing file: %s", filename.c_str()); _deepInfo = DeepInfo(); return; } _outputContext = _owner->readerOutputContext(); DtexImage* image; DtexGetImageByIndex(_dtexFile, 0, &image); float NP[16]; DtexNP(image, NP); float Nl[16]; DtexNl(image, Nl); _numChans = DtexNumChan(image); setInfo(DtexWidth(image), DtexHeight(image), _outputContext, Mask_RGB | Mask_Alpha | Mask_Deep); _metaData.setData("dtex/np", NP, 16); _metaData.setData("dtex/nl", Nl, 16); _dtexReaderFormat = dynamic_cast( op->handler() ); mFnAssert(_dtexReaderFormat); } ~dtexDeepReader() { if (_dtexFile) { DtexClose(_dtexFile); _dtexFile = NULL; } if (_dtexCache) { DtexDestroyCache(_dtexCache); _dtexCache = NULL; } } void open(const std::string& filename) { _dtexCache = DtexCreateCache(10000, NULL); _dtexOpenError = DtexOpenFile(filename.c_str(), "rb", _dtexCache, &_dtexFile); } void doDeepEngine(DD::Image::Box box, const ChannelSet& channels, DeepOutputPlane& plane) { static int sRenderManVersion = RenderManVersion(); // RenderMan 15 seems not to be thread-safe (bug 23831) Guard g(sRenderManVersion < 16 ? sLibraryLock : _engineLock); if (!_dtexFile) { if (_dtexOpenError != DTEX_NOERR) _op->error("error (%d) opening file", _dtexOpenError); else _op->error("missing file."); return; } DtexImage* image; DtexGetImageByIndex(_dtexFile, 0, &image); int height = DtexHeight(image); DtexPixel* pixel = DtexMakePixel(_numChans); plane = DeepOutputPlane(channels, box); bool raw = _dtexReaderFormat->_raw; bool discrete = _dtexReaderFormat->_premult; bool premult = _dtexReaderFormat->_discrete; std::map chanMap; if (_numChans == 4) { chanMap[Chan_Red] = 0; chanMap[Chan_Green] = 1; chanMap[Chan_Blue] = 2; chanMap[Chan_Alpha] = 3; } else { chanMap[Chan_Alpha] = 0; } std::vector pts(_numChans); std::vector pts2(_numChans); for (Box::iterator it = box.begin(); it != box.end(); it++) { float x = it.x; float y = it.y; _outputContext.from_proxy_xy(x, y); DtexGetPixel(image, int(x), height - 1 - int(y), pixel); bool isMonochrome = DtexIsPixelMonochrome( pixel ); int numpts = DtexPixelGetNumPoints(pixel); DeepOutPixel pels(numpts * channels.size()); for (int j = 0; j < numpts; j ++ ) { float z; DtexPixelGetPoint(pixel, j, &z, &pts[0]); float z2; if ( raw || ! isMonochrome ) { z2 = z; } else { if ( DtexPixelGetPoint(pixel, j+1, &z2, &pts2[0]) != DTEX_NOERR ) continue; if ( pts[chanMap[Chan_Alpha]] == pts2[chanMap[Chan_Alpha]] ) continue; if ( discrete ) z2 = z ; } float alpha = 1; if (chanMap.count(Chan_Alpha)) { const int alphaChan = chanMap[Chan_Alpha]; alpha = ( raw || ! isMonochrome ) ? pts[alphaChan] : ((pts[alphaChan] - pts2[alphaChan]) / pts[alphaChan]); } foreach(chan, channels) { if (chan == Chan_Z) pels.push_back(1/z); else if (chan == Chan_DeepFront ) pels.push_back(z); else if ( chan == Chan_DeepBack ) { pels.push_back(z2); } else if (chan == Chan_Alpha) pels.push_back(alpha); else if (chanMap.count(chan)) { if (premult && IsRGB(chan) && chanMap.count(Chan_Alpha)) { pels.push_back(pts[chanMap[chan]] * alpha); } else { pels.push_back( pts[ chanMap[chan] ] ); } } else if (IsRGBA(chan)) pels.push_back(alpha); else pels.push_back(0); } } plane.addPixel(pels); } DtexDestroyPixel(pixel); } }; static DeepReader* build(DeepReaderOwner* op, const std::string& fn) { return new dtexDeepReader(op, fn); } static DeepReaderFormat* buildFormat(DeepReaderOwner* op) { return new dtexDeepReaderFormat(); } static const DeepReader::Description d("dtex\0deepshad\0dshd\0tex\0", "dtex", build, buildFormat); Lock dtexDeepReader::sLibraryLock; } }