// 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" 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; } class dtexDeepReaderFormat : public DeepReaderFormat { friend class dtexDeepReader; bool _raw; bool _premult; public: dtexDeepReaderFormat() { _raw = false; _premult = false; } bool getRaw() const { return _raw; } bool getPremult() const { return _premult; } void knobs(Knob_Callback f) { Bool_knob(f, &_raw, "raw", "raw values"); Bool_knob(f, &_premult, "premult", "premultiply"); Tooltip(f, "Premultiply values from file (if off, then it assumes they are already premultiplied)"); } void append(Hash& hash) { hash.append(_raw); hash.append(_premult); } }; /** * This is a plugin to read the Pixar Renderman 'dtex' files. */ class dtexDeepReader : public DeepReader { 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 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); } ~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) { Guard g(_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); dtexDeepReaderFormat* format = dynamic_cast(_owner->handler()); bool raw = format ? format->getRaw() : false; bool premult = format ? format->getPremult() : false; std::map chanMap; if (_numChans == 4) { chanMap[Chan_Red] = 0; chanMap[Chan_Green] = 1; chanMap[Chan_Blue] = 2; chanMap[Chan_Alpha] = 3; raw = true; } 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); int numpts = DtexPixelGetNumPoints(pixel); DeepOutPixel pels(numpts * channels.size()); for (int j = 0; j < numpts; j ++ ) { float z; DtexPixelGetPoint(pixel, j, &z, &pts[0]); if (!raw) { float z2; DtexPixelGetPoint(pixel, j+1, &z2, &pts2[0]); if (pts[chanMap[Chan_Alpha]] == pts2[chanMap[Chan_Alpha]]) continue; } float alpha = 1; if (chanMap.count(Chan_Alpha)) { const int alphaChan = chanMap[Chan_Alpha]; alpha = raw ? 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 || chan == Chan_DeepBack) pels.push_back(z); 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); } }