/src/freeimage-svn/FreeImage/trunk/Source/OpenEXR/IlmImf/ImfCompositeDeepScanLine.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /////////////////////////////////////////////////////////////////////////// |
2 | | // |
3 | | // Copyright (c) 2012, Weta Digital Ltd |
4 | | // |
5 | | // All rights reserved. |
6 | | // |
7 | | // Redistribution and use in source and binary forms, with or without |
8 | | // modification, are permitted provided that the following conditions are |
9 | | // met: |
10 | | // * Redistributions of source code must retain the above copyright |
11 | | // notice, this list of conditions and the following disclaimer. |
12 | | // * Redistributions in binary form must reproduce the above |
13 | | // copyright notice, this list of conditions and the following disclaimer |
14 | | // in the documentation and/or other materials provided with the |
15 | | // distribution. |
16 | | // * Neither the name of Weta Digital nor the names of |
17 | | // its contributors may be used to endorse or promote products derived |
18 | | // from this software without specific prior written permission. |
19 | | // |
20 | | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
21 | | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
22 | | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
23 | | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
24 | | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
25 | | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
26 | | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
27 | | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
28 | | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
29 | | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
30 | | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
31 | | // |
32 | | /////////////////////////////////////////////////////////////////////////// |
33 | | |
34 | | |
35 | | #include "ImfCompositeDeepScanLine.h" |
36 | | #include "ImfDeepScanLineInputPart.h" |
37 | | #include "ImfDeepScanLineInputFile.h" |
38 | | #include "ImfChannelList.h" |
39 | | #include "ImfFrameBuffer.h" |
40 | | #include "ImfDeepFrameBuffer.h" |
41 | | #include "ImfDeepCompositing.h" |
42 | | #include "ImfPixelType.h" |
43 | | #include "IlmThreadPool.h" |
44 | | |
45 | | #include <Iex.h> |
46 | | #include <vector> |
47 | | OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER |
48 | | |
49 | | using std::vector; |
50 | | using std::string; |
51 | | using IMATH_NAMESPACE::Box2i; |
52 | | using ILMTHREAD_NAMESPACE::Task; |
53 | | using ILMTHREAD_NAMESPACE::TaskGroup; |
54 | | using ILMTHREAD_NAMESPACE::ThreadPool; |
55 | | |
56 | | |
57 | | |
58 | | struct CompositeDeepScanLine::Data{ |
59 | | public : |
60 | | vector<DeepScanLineInputFile *> _file; // array of files |
61 | | vector<DeepScanLineInputPart *> _part; // array of parts |
62 | | FrameBuffer _outputFrameBuffer; // output frame buffer provided |
63 | | bool _zback; // true if we are using zback (otherwise channel 1 = channel 0) |
64 | | vector< vector<float> > _channeldata; // pixel values, read from the input, one array per channel |
65 | | vector< int > _sampleCounts; // total per-pixel sample counts, |
66 | | Box2i _dataWindow; // data window of combined inputs |
67 | | DeepCompositing * _comp; // user-provided compositor |
68 | | vector<string> _channels; // names of channels that will be composited |
69 | | vector<int> _bufferMap; // entry _outputFrameBuffer[n].name() == _channels[ _bufferMap[n] ].name() |
70 | | |
71 | | void check_valid(const Header & header); // check newly added part/file is OK; on first good call, set _zback/_dataWindow |
72 | | |
73 | | // |
74 | | // set up the given deep frame buffer to contain the required channels |
75 | | // resize counts and pointers to the width of _dataWindow |
76 | | // zero-out all counts, since the datawindow may be smaller than/not include this part |
77 | | // |
78 | | |
79 | | void handleDeepFrameBuffer (DeepFrameBuffer & buf, |
80 | | vector<unsigned int> & counts, //per-pixel counts |
81 | | vector< vector<float *> > & pointers, //per-channel-per-pixel pointers to data |
82 | | const Header & header, |
83 | | int start, |
84 | | int end); |
85 | | |
86 | | Data(); |
87 | | }; |
88 | | |
89 | 0 | CompositeDeepScanLine::Data::Data() : _zback(false) , _comp(NULL) {} |
90 | | |
91 | 0 | CompositeDeepScanLine::CompositeDeepScanLine() : _Data(new Data) {} |
92 | | |
93 | | CompositeDeepScanLine::~CompositeDeepScanLine() |
94 | 0 | { |
95 | 0 | delete _Data; |
96 | 0 | } |
97 | | |
98 | | void |
99 | | CompositeDeepScanLine::addSource(DeepScanLineInputPart* part) |
100 | 0 | { |
101 | 0 | _Data->check_valid(part->header()); |
102 | 0 | _Data->_part.push_back(part); |
103 | 0 | } |
104 | | |
105 | | void |
106 | | CompositeDeepScanLine::addSource(DeepScanLineInputFile* file) |
107 | 0 | { |
108 | 0 | _Data->check_valid(file->header()); |
109 | 0 | _Data->_file.push_back(file); |
110 | 0 | } |
111 | | |
112 | | int |
113 | | CompositeDeepScanLine::sources() const |
114 | 0 | { |
115 | 0 | return int(_Data->_part.size())+int(_Data->_file.size()); |
116 | 0 | } |
117 | | |
118 | | void |
119 | | CompositeDeepScanLine::Data::check_valid(const Header & header) |
120 | 0 | { |
121 | |
|
122 | 0 | bool has_z=false; |
123 | 0 | bool has_alpha=false; |
124 | | // check good channel names |
125 | 0 | for( ChannelList::ConstIterator i=header.channels().begin();i!=header.channels().end();++i) |
126 | 0 | { |
127 | 0 | std::string n(i.name()); |
128 | 0 | if(n=="ZBack") |
129 | 0 | { |
130 | 0 | _zback=true; |
131 | 0 | } |
132 | 0 | else if(n=="Z") |
133 | 0 | { |
134 | 0 | has_z=true; |
135 | 0 | } |
136 | 0 | else if(n=="A") |
137 | 0 | { |
138 | 0 | has_alpha=true; |
139 | 0 | } |
140 | 0 | } |
141 | | |
142 | 0 | if(!has_z) |
143 | 0 | { |
144 | 0 | throw IEX_NAMESPACE::ArgExc("Deep data provided to CompositeDeepScanLine is missing a Z channel"); |
145 | 0 | } |
146 | | |
147 | 0 | if(!has_alpha) |
148 | 0 | { |
149 | 0 | throw IEX_NAMESPACE::ArgExc("Deep data provided to CompositeDeepScanLine is missing an alpha channel"); |
150 | 0 | } |
151 | | |
152 | | |
153 | 0 | if(_part.size()==0 && _file.size()==0) |
154 | 0 | { |
155 | | // first in - update and return |
156 | |
|
157 | 0 | _dataWindow = header.dataWindow(); |
158 | | |
159 | 0 | return; |
160 | 0 | } |
161 | | |
162 | | |
163 | 0 | const Header * const match_header = _part.size()>0 ? &_part[0]->header() : &_file[0]->header(); |
164 | | |
165 | | // check the sizes match |
166 | 0 | if(match_header->displayWindow() != header.displayWindow()) |
167 | 0 | { |
168 | 0 | throw IEX_NAMESPACE::ArgExc("Deep data provided to CompositeDeepScanLine has a different displayWindow to previously provided data"); |
169 | 0 | } |
170 | | |
171 | 0 | _dataWindow.extendBy(header.dataWindow()); |
172 | | |
173 | 0 | } |
174 | | void |
175 | | CompositeDeepScanLine::Data::handleDeepFrameBuffer (DeepFrameBuffer& buf, |
176 | | std::vector< unsigned int > & counts, |
177 | | vector< std::vector< float* > > & pointers, |
178 | | const Header& header, |
179 | | int start, |
180 | | int end) |
181 | 0 | { |
182 | 0 | int width=_dataWindow.size().x+1; |
183 | 0 | size_t pixelcount = width * (end-start+1); |
184 | 0 | pointers.resize(_channels.size()); |
185 | 0 | counts.resize(pixelcount); |
186 | 0 | buf.insertSampleCountSlice (Slice (OPENEXR_IMF_INTERNAL_NAMESPACE::UINT, |
187 | 0 | (char *) (&counts[0]-_dataWindow.min.x-start*width), |
188 | 0 | sizeof(unsigned int), |
189 | 0 | sizeof(unsigned int)*width)); |
190 | |
|
191 | 0 | pointers[0].resize(pixelcount); |
192 | 0 | buf.insert ("Z", DeepSlice (OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT, |
193 | 0 | (char *)(&pointers[0][0]-_dataWindow.min.x-start*width), |
194 | 0 | sizeof(float *), |
195 | 0 | sizeof(float *)*width, |
196 | 0 | sizeof(float) )); |
197 | |
|
198 | 0 | if(_zback) |
199 | 0 | { |
200 | 0 | pointers[1].resize(pixelcount); |
201 | 0 | buf.insert ("ZBack", DeepSlice (OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT, |
202 | 0 | (char *)(&pointers[1][0]-_dataWindow.min.x-start*width), |
203 | 0 | sizeof(float *), |
204 | 0 | sizeof(float *)*width, |
205 | 0 | sizeof(float) )); |
206 | 0 | } |
207 | |
|
208 | 0 | pointers[2].resize(pixelcount); |
209 | 0 | buf.insert ("A", DeepSlice (OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT, |
210 | 0 | (char *)(&pointers[2][0]-_dataWindow.min.x-start*width), |
211 | 0 | sizeof(float *), |
212 | 0 | sizeof(float *)*width, |
213 | 0 | sizeof(float) )); |
214 | | |
215 | |
|
216 | 0 | size_t i =0; |
217 | 0 | for(FrameBuffer::ConstIterator qt = _outputFrameBuffer.begin(); |
218 | 0 | qt != _outputFrameBuffer.end(); |
219 | 0 | qt++) |
220 | 0 | { |
221 | 0 | int channel_in_source = _bufferMap[i]; |
222 | 0 | if(channel_in_source>2) |
223 | 0 | { |
224 | | // not dealt with yet (0,1,2 previously inserted) |
225 | 0 | pointers[channel_in_source].resize(pixelcount); |
226 | 0 | buf.insert (qt.name(), |
227 | 0 | DeepSlice (OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT, |
228 | 0 | (char *)(&pointers[channel_in_source][0]-_dataWindow.min.x-start*width), |
229 | 0 | sizeof(float *), |
230 | 0 | sizeof(float *)*width, |
231 | 0 | sizeof(float) )); |
232 | 0 | } |
233 | |
|
234 | 0 | i++; |
235 | 0 | } |
236 | |
|
237 | 0 | } |
238 | | |
239 | | void |
240 | | CompositeDeepScanLine::setCompositing(DeepCompositing* c) |
241 | 0 | { |
242 | 0 | _Data->_comp=c; |
243 | 0 | } |
244 | | |
245 | | const IMATH_NAMESPACE::Box2i& CompositeDeepScanLine::dataWindow() const |
246 | 0 | { |
247 | 0 | return _Data->_dataWindow; |
248 | 0 | } |
249 | | |
250 | | |
251 | | void |
252 | | CompositeDeepScanLine::setFrameBuffer(const FrameBuffer& fr) |
253 | 0 | { |
254 | | |
255 | | // |
256 | | // count channels; build map between channels in frame buffer |
257 | | // and channels in internal buffers |
258 | | // |
259 | | |
260 | 0 | _Data->_channels.resize(3); |
261 | 0 | _Data->_channels[0]="Z"; |
262 | 0 | _Data->_channels[1]=_Data->_zback ? "ZBack" : "Z"; |
263 | 0 | _Data->_channels[2]="A"; |
264 | 0 | _Data->_bufferMap.resize(0); |
265 | | |
266 | 0 | for(FrameBuffer::ConstIterator q=fr.begin();q!=fr.end();q++) |
267 | 0 | { |
268 | 0 | string name(q.name()); |
269 | 0 | if(name=="ZBack") |
270 | 0 | { |
271 | 0 | _Data->_bufferMap.push_back(1); |
272 | 0 | }else if(name=="Z") |
273 | 0 | { |
274 | 0 | _Data->_bufferMap.push_back(0); |
275 | 0 | }else if(name=="A") |
276 | 0 | { |
277 | 0 | _Data->_bufferMap.push_back(2); |
278 | 0 | }else{ |
279 | 0 | _Data->_bufferMap.push_back(_Data->_channels.size()); |
280 | 0 | _Data->_channels.push_back(name); |
281 | 0 | } |
282 | 0 | } |
283 | | |
284 | 0 | _Data->_outputFrameBuffer=fr; |
285 | 0 | } |
286 | | |
287 | | namespace |
288 | | { |
289 | | |
290 | | class LineCompositeTask : public Task |
291 | | { |
292 | | public: |
293 | | |
294 | | LineCompositeTask ( TaskGroup* group , |
295 | | CompositeDeepScanLine::Data * data, |
296 | | int y, |
297 | | int start, |
298 | | vector<const char*>* names, |
299 | | vector<vector< vector<float *> > >* pointers, |
300 | | vector<unsigned int>* total_sizes, |
301 | | vector<unsigned int>* num_sources |
302 | | ) : Task(group) , |
303 | | _Data(data), |
304 | | _y(y), |
305 | | _start(start), |
306 | | _names(names), |
307 | | _pointers(pointers), |
308 | | _total_sizes(total_sizes), |
309 | | _num_sources(num_sources) |
310 | 0 | {} |
311 | | |
312 | 0 | virtual ~LineCompositeTask () {} |
313 | | |
314 | | virtual void execute (); |
315 | | CompositeDeepScanLine::Data* _Data; |
316 | | int _y; |
317 | | int _start; |
318 | | vector<const char *>* _names; |
319 | | vector<vector< vector<float *> > >* _pointers; |
320 | | vector<unsigned int>* _total_sizes; |
321 | | vector<unsigned int>* _num_sources; |
322 | | |
323 | | }; |
324 | | |
325 | | |
326 | | void |
327 | | composite_line(int y, |
328 | | int start, |
329 | | CompositeDeepScanLine::Data * _Data, |
330 | | vector<const char *> & names, |
331 | | const vector<vector< vector<float *> > > & pointers, |
332 | | const vector<unsigned int> & total_sizes, |
333 | | const vector<unsigned int> & num_sources |
334 | | ) |
335 | 0 | { |
336 | 0 | vector<float> output_pixel(names.size()); //the pixel we'll output to |
337 | 0 | vector<const float *> inputs(names.size()); |
338 | 0 | DeepCompositing d; // fallback compositing engine |
339 | 0 | DeepCompositing * comp= _Data->_comp ? _Data->_comp : &d; |
340 | |
|
341 | 0 | int pixel = (y-start)*(_Data->_dataWindow.max.x+1-_Data->_dataWindow.min.x); |
342 | | |
343 | 0 | for(int x=_Data->_dataWindow.min.x;x<=_Data->_dataWindow.max.x;x++) |
344 | 0 | { |
345 | | // set inputs[] to point to the first sample of the first part of each channel |
346 | | // if there's a zback, set all channel independently... |
347 | |
|
348 | 0 | if(_Data->_zback) |
349 | 0 | { |
350 | |
|
351 | 0 | for(size_t channel=0;channel<names.size();channel++) |
352 | 0 | { |
353 | 0 | inputs[channel]=pointers[0][channel][pixel]; |
354 | 0 | } |
355 | |
|
356 | 0 | }else{ |
357 | | |
358 | | // otherwise, set 0 and 1 to point to Z |
359 | | |
360 | |
|
361 | 0 | inputs[0]=pointers[0][0][pixel]; |
362 | 0 | inputs[1]=pointers[0][0][pixel]; |
363 | 0 | for(size_t channel=2;channel<names.size();channel++) |
364 | 0 | { |
365 | 0 | inputs[channel]=pointers[0][channel][pixel]; |
366 | 0 | } |
367 | |
|
368 | 0 | } |
369 | 0 | comp->composite_pixel(&output_pixel[0], |
370 | 0 | &inputs[0], |
371 | 0 | &names[0], |
372 | 0 | names.size(), |
373 | 0 | total_sizes[pixel], |
374 | 0 | num_sources[pixel] |
375 | 0 | ); |
376 | | |
377 | |
|
378 | 0 | size_t channel_number=0; |
379 | | |
380 | | |
381 | | // |
382 | | // write out composited value into internal frame buffer |
383 | | // |
384 | 0 | for(FrameBuffer::Iterator it = _Data->_outputFrameBuffer.begin();it !=_Data->_outputFrameBuffer.end();it++) |
385 | 0 | { |
386 | |
|
387 | 0 | float value = output_pixel[ _Data->_bufferMap[channel_number] ]; // value to write |
388 | | |
389 | | |
390 | | // cast to half float if necessary |
391 | 0 | if(it.slice().type==OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT) |
392 | 0 | { |
393 | 0 | * (float *)(it.slice().base + y*it.slice().yStride + x*it.slice().xStride) = value; |
394 | 0 | } |
395 | 0 | else if(it.slice().type==HALF) |
396 | 0 | { |
397 | 0 | * (half *)(it.slice().base + y*it.slice().yStride + x*it.slice().xStride) = half(value); |
398 | 0 | } |
399 | |
|
400 | 0 | channel_number++; |
401 | |
|
402 | 0 | } |
403 | |
|
404 | 0 | pixel++; |
405 | |
|
406 | 0 | }// next pixel on row |
407 | 0 | } |
408 | | |
409 | | void LineCompositeTask::execute() |
410 | 0 | { |
411 | 0 | composite_line(_y,_start,_Data,*_names,*_pointers,*_total_sizes,*_num_sources); |
412 | 0 | } |
413 | | |
414 | | |
415 | | } |
416 | | |
417 | | void |
418 | | CompositeDeepScanLine::readPixels(int start, int end) |
419 | 0 | { |
420 | 0 | size_t parts = _Data->_file.size() + _Data->_part.size(); // total of files+parts |
421 | | |
422 | 0 | vector<DeepFrameBuffer> framebuffers(parts); |
423 | 0 | vector< vector<unsigned int> > counts(parts); |
424 | | |
425 | | // |
426 | | // for each part, a pointer to an array of channels |
427 | | // |
428 | 0 | vector<vector< vector<float *> > > pointers(parts); |
429 | 0 | vector<const Header *> headers(parts); |
430 | | |
431 | 0 | { |
432 | 0 | size_t i; |
433 | 0 | for(i=0;i<_Data->_file.size();i++) |
434 | 0 | { |
435 | 0 | headers[i] = &_Data->_file[i]->header(); |
436 | 0 | } |
437 | | |
438 | 0 | for(size_t j=0;j<_Data->_part.size();j++) |
439 | 0 | { |
440 | 0 | headers[i+j] = &_Data->_part[j]->header(); |
441 | 0 | } |
442 | 0 | } |
443 | | |
444 | | |
445 | 0 | for(size_t i=0;i<parts;i++) |
446 | 0 | { |
447 | 0 | _Data->handleDeepFrameBuffer(framebuffers[i],counts[i],pointers[i],*headers[i],start,end); |
448 | 0 | } |
449 | | |
450 | | // |
451 | | // set frame buffers and read scanlines from all parts |
452 | | // TODO what happens if SCANLINE not in data window? |
453 | | // |
454 | | |
455 | 0 | { |
456 | 0 | size_t i=0; |
457 | 0 | for(i=0;i<_Data->_file.size();i++) |
458 | 0 | { |
459 | 0 | _Data->_file[i]->setFrameBuffer(framebuffers[i]); |
460 | 0 | _Data->_file[i]->readPixelSampleCounts(start,end); |
461 | 0 | } |
462 | 0 | for(size_t j=0;j<_Data->_part.size();j++) |
463 | 0 | { |
464 | 0 | _Data->_part[j]->setFrameBuffer(framebuffers[i+j]); |
465 | 0 | _Data->_part[j]->readPixelSampleCounts(start,end); |
466 | 0 | } |
467 | 0 | } |
468 | | |
469 | | |
470 | | // |
471 | | // total width |
472 | | // |
473 | | |
474 | 0 | size_t total_width = _Data->_dataWindow.size().x+1; |
475 | 0 | size_t total_pixels = total_width*(end-start+1); |
476 | 0 | vector<unsigned int> total_sizes(total_pixels); |
477 | 0 | vector<unsigned int> num_sources(total_pixels); //number of parts with non-zero sample count |
478 | | |
479 | 0 | size_t overall_sample_count=0; // sum of all samples in all images between start and end |
480 | | |
481 | | |
482 | | // |
483 | | // accumulate pixel counts |
484 | | // |
485 | 0 | for(size_t ptr=0;ptr<total_pixels;ptr++) |
486 | 0 | { |
487 | 0 | total_sizes[ptr]=0; |
488 | 0 | num_sources[ptr]=0; |
489 | 0 | for(size_t j=0;j<parts;j++) |
490 | 0 | { |
491 | 0 | total_sizes[ptr]+=counts[j][ptr]; |
492 | 0 | if(counts[j][ptr]>0) num_sources[ptr]++; |
493 | 0 | } |
494 | 0 | overall_sample_count+=total_sizes[ptr]; |
495 | | |
496 | | |
497 | | |
498 | 0 | } |
499 | | |
500 | | |
501 | | |
502 | | |
503 | | // |
504 | | // allocate arrays for pixel data |
505 | | // samples array accessed as in pixels[channel][sample] |
506 | | // |
507 | | |
508 | 0 | vector<vector<float> > samples( _Data->_channels.size() ); |
509 | | |
510 | 0 | for(size_t channel=0;channel<_Data->_channels.size();channel++) |
511 | 0 | { |
512 | 0 | if( channel!=1 || _Data->_zback) |
513 | 0 | { |
514 | 0 | samples[channel].resize(overall_sample_count); |
515 | 0 | } |
516 | 0 | } |
517 | | |
518 | 0 | for(size_t channel=0;channel<samples.size();channel++) |
519 | 0 | { |
520 | | |
521 | 0 | if( channel!=1 || _Data->_zback) |
522 | 0 | { |
523 | | |
524 | 0 | samples[channel].resize(overall_sample_count); |
525 | | |
526 | | |
527 | | // |
528 | | // allocate pointers for channel data |
529 | | // |
530 | | |
531 | 0 | size_t offset=0; |
532 | | |
533 | 0 | for(size_t pixel=0;pixel<total_pixels;pixel++) |
534 | 0 | { |
535 | 0 | for(size_t part=0 ; part<parts && offset<overall_sample_count ; part++ ) |
536 | 0 | { |
537 | 0 | pointers[part][channel][pixel]=&samples[channel][offset]; |
538 | 0 | offset+=counts[part][pixel]; |
539 | 0 | } |
540 | 0 | } |
541 | | |
542 | 0 | } |
543 | 0 | } |
544 | | |
545 | | // |
546 | | // read data |
547 | | // |
548 | | |
549 | 0 | for(size_t i=0;i<_Data->_file.size();i++) |
550 | 0 | { |
551 | 0 | _Data->_file[i]->readPixels(start,end); |
552 | 0 | } |
553 | 0 | for(size_t j=0;j<_Data->_part.size();j++) |
554 | 0 | { |
555 | 0 | _Data->_part[j]->readPixels(start,end); |
556 | 0 | } |
557 | | |
558 | | |
559 | | |
560 | | |
561 | | // |
562 | | // composite pixels and write back to framebuffer |
563 | | // |
564 | | |
565 | | |
566 | | // turn vector of strings into array of char * |
567 | | // and make sure 'ZBack' channel is correct |
568 | 0 | vector<const char *> names(_Data->_channels.size()); |
569 | 0 | for(size_t i=0;i<names.size();i++) |
570 | 0 | { |
571 | 0 | names[i]=_Data->_channels[i].c_str(); |
572 | 0 | } |
573 | | |
574 | 0 | if(!_Data->_zback) names[1]=names[0]; // no zback channel, so make it point to z |
575 | | |
576 | | |
577 | | |
578 | 0 | TaskGroup g; |
579 | 0 | for(int y=start;y<=end;y++) |
580 | 0 | { |
581 | 0 | ThreadPool::addGlobalTask(new LineCompositeTask(&g,_Data,y,start,&names,&pointers,&total_sizes,&num_sources)); |
582 | 0 | }//next row |
583 | 0 | } |
584 | | |
585 | | const FrameBuffer& |
586 | | CompositeDeepScanLine::frameBuffer() const |
587 | 0 | { |
588 | 0 | return _Data->_outputFrameBuffer; |
589 | 0 | } |
590 | | |
591 | | OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT |