// Copyright (c) 2011 The Foundry Visionmongers Ltd. All Rights Reserved. #include "DDImage/DeepOp.h" #include "DDImage/Knobs.h" #include "DDImage/Thread.h" #include "DDImage/Iop.h" #include "DDImage/Row.h" static const char* CLASS = "DeepMerge"; using namespace DD::Image; class DeepMerge : public DeepOnlyOp { bool _dropHidden; public: DeepMerge(Node* node) : DeepOnlyOp(node) { _dropHidden = false; } virtual int minimum_inputs() const { return 1; } virtual Op* op() { return this; } virtual int maximum_inputs() const { return 999; } virtual bool test_input(int idx, Op*op) const { return dynamic_cast(op); } DeepOp* dinput(int n) { return dynamic_cast(Op::input(n)); } const char* node_help() const { return "Merges two or more deep data inputs to produce a composite deep data stream."; } const char* Class() const { return CLASS; } void knobs(Knob_Callback f) { Bool_knob(f, &_dropHidden, "drop_hidden", "drop hidden samples"); Tooltip(f, "Drop samples that are behind other samples with alpha 1 (ie those that are entirely obscured)"); } //! get the extra channels needed apart from those being passed through. DD::Image::ChannelSet extraChans() const { //! If _dropHidden is on we need depth and alpha if (_dropHidden) return Mask_DeepFront | Mask_Alpha; return Mask_None; } void _validate(bool real) { bool any = false; for (int i = 0; i < inputs(); i++) { if (DeepOp* dop = dinput(i)) { dop->validate(real); if (!any) { _deepInfo = dop->deepInfo(); any = true; } else { _deepInfo.merge(dop->deepInfo()); } } } } void getDeepRequests(DD::Image::Box box, const DD::Image::ChannelSet& channels, int count, std::vector& requests) { DD::Image::ChannelSet reqChans = channels + extraChans(); for (int i = 0; i < inputs(); i++) { if (dinput(i)) { requests.push_back(RequestData(dinput(i), box, reqChans, count)); } } } bool doDeepEngine(DD::Image::Box box, const ChannelSet& channels, DeepOutputPlane& plane) { plane = DeepOutputPlane(channels, box); const int numChans = channels.size(); bool done = true; std::vector inPlanes(inputs()); DD::Image::ChannelSet getChans = channels + extraChans(); for (int i = 0; i < inputs(); i++) { if (dinput(i)) { if (!dinput(i)->deepEngine(box, getChans, inPlanes[i])) return false; } } for (DD::Image::Box::iterator it = box.begin(); it != box.end(); it++) { if (aborted()) { return false; } DeepOutPixel pixelData; pixelData.clear(); float firstSolid = FLT_MAX; if (_dropHidden) { for (int i = 0; i < inputs(); i++) if (dinput(i)) { DeepPixel deepPixel = inPlanes[i].getPixel(it); for (size_t j = 0; j < deepPixel.getSampleCount(); j++) if (deepPixel.getUnorderedSample(j, Chan_Alpha) >= 1) firstSolid = std::min(firstSolid, deepPixel.getUnorderedSample(j, Chan_DeepFront)); } } for (int i = 0; i < inputs(); i++) { if (dinput(i)) { DeepPixel deepPixel = inPlanes[i].getPixel(it); pixelData.reserveMore(deepPixel.getSampleCount() * numChans); for (size_t j = 0; j < deepPixel.getSampleCount(); j++) { if (_dropHidden) { float front = deepPixel.getUnorderedSample(j, Chan_DeepFront); if (front > firstSolid) continue; } foreach (z, channels) { pixelData.push_back(deepPixel.getUnorderedSample(j, z)); } } } } plane.addPixel(pixelData); } return done; } static const Description d; static const Description d2; }; static Op* build(Node* node) { return new DeepMerge(node); } const Op::Description DeepMerge::d(::CLASS, "Image/DeepMerge", build); const Op::Description DeepMerge::d2("ToDeep", "Image/DeepMerge", build);