Cycles / SSS Render Passes:
[blender.git] / source / blender / render / intern / source / render_result.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2006 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/render/intern/source/render_result.c
29  *  \ingroup render
30  */
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "BLI_utildefines.h"
39 #include "BLI_fileops.h"
40 #include "BLI_listbase.h"
41 #include "BLI_path_util.h"
42 #include "BLI_rect.h"
43 #include "BLI_string.h"
44 #include "BLI_threads.h"
45
46 #include "BKE_image.h"
47 #include "BKE_global.h"
48 #include "BKE_main.h"
49 #include "BKE_report.h"
50 #include "BKE_freestyle.h"
51
52 #include "IMB_imbuf.h"
53 #include "IMB_imbuf_types.h"
54 #include "IMB_colormanagement.h"
55
56 #include "intern/openexr/openexr_multi.h"
57
58 #include "render_result.h"
59 #include "render_types.h"
60
61 /********************************** Free *************************************/
62
63 void render_result_free(RenderResult *res)
64 {
65         if (res == NULL) return;
66
67         while (res->layers.first) {
68                 RenderLayer *rl = res->layers.first;
69                 
70                 if (rl->rectf) MEM_freeN(rl->rectf);
71                 /* acolrect and scolrect are optionally allocated in shade_tile, only free here since it can be used for drawing */
72                 if (rl->acolrect) MEM_freeN(rl->acolrect);
73                 if (rl->scolrect) MEM_freeN(rl->scolrect);
74                 
75                 while (rl->passes.first) {
76                         RenderPass *rpass = rl->passes.first;
77                         if (rpass->rect) MEM_freeN(rpass->rect);
78                         BLI_remlink(&rl->passes, rpass);
79                         MEM_freeN(rpass);
80                 }
81                 BLI_remlink(&res->layers, rl);
82                 MEM_freeN(rl);
83         }
84         
85         if (res->rect32)
86                 MEM_freeN(res->rect32);
87         if (res->rectz)
88                 MEM_freeN(res->rectz);
89         if (res->rectf)
90                 MEM_freeN(res->rectf);
91         if (res->text)
92                 MEM_freeN(res->text);
93         
94         MEM_freeN(res);
95 }
96
97 /* version that's compatible with fullsample buffers */
98 void render_result_free_list(ListBase *lb, RenderResult *rr)
99 {
100         RenderResult *rrnext;
101         
102         for (; rr; rr = rrnext) {
103                 rrnext = rr->next;
104                 
105                 if (lb && lb->first)
106                         BLI_remlink(lb, rr);
107                 
108                 render_result_free(rr);
109         }
110 }
111
112 /********************************* Names *************************************/
113
114 /* NOTE: OpenEXR only supports 32 chars for layer+pass names
115  * In blender we now use max 10 chars for pass, max 20 for layer */
116 static const char *get_pass_name(int passtype, int channel)
117 {
118         
119         if (passtype == SCE_PASS_COMBINED) {
120                 if (channel == -1) return "Combined";
121                 if (channel == 0) return "Combined.R";
122                 if (channel == 1) return "Combined.G";
123                 if (channel == 2) return "Combined.B";
124                 return "Combined.A";
125         }
126         if (passtype == SCE_PASS_Z) {
127                 if (channel == -1) return "Depth";
128                 return "Depth.Z";
129         }
130         if (passtype == SCE_PASS_VECTOR) {
131                 if (channel == -1) return "Vector";
132                 if (channel == 0) return "Vector.X";
133                 if (channel == 1) return "Vector.Y";
134                 if (channel == 2) return "Vector.Z";
135                 return "Vector.W";
136         }
137         if (passtype == SCE_PASS_NORMAL) {
138                 if (channel == -1) return "Normal";
139                 if (channel == 0) return "Normal.X";
140                 if (channel == 1) return "Normal.Y";
141                 return "Normal.Z";
142         }
143         if (passtype == SCE_PASS_UV) {
144                 if (channel == -1) return "UV";
145                 if (channel == 0) return "UV.U";
146                 if (channel == 1) return "UV.V";
147                 return "UV.A";
148         }
149         if (passtype == SCE_PASS_RGBA) {
150                 if (channel == -1) return "Color";
151                 if (channel == 0) return "Color.R";
152                 if (channel == 1) return "Color.G";
153                 if (channel == 2) return "Color.B";
154                 return "Color.A";
155         }
156         if (passtype == SCE_PASS_EMIT) {
157                 if (channel == -1) return "Emit";
158                 if (channel == 0) return "Emit.R";
159                 if (channel == 1) return "Emit.G";
160                 return "Emit.B";
161         }
162         if (passtype == SCE_PASS_DIFFUSE) {
163                 if (channel == -1) return "Diffuse";
164                 if (channel == 0) return "Diffuse.R";
165                 if (channel == 1) return "Diffuse.G";
166                 return "Diffuse.B";
167         }
168         if (passtype == SCE_PASS_SPEC) {
169                 if (channel == -1) return "Spec";
170                 if (channel == 0) return "Spec.R";
171                 if (channel == 1) return "Spec.G";
172                 return "Spec.B";
173         }
174         if (passtype == SCE_PASS_SHADOW) {
175                 if (channel == -1) return "Shadow";
176                 if (channel == 0) return "Shadow.R";
177                 if (channel == 1) return "Shadow.G";
178                 return "Shadow.B";
179         }
180         if (passtype == SCE_PASS_AO) {
181                 if (channel == -1) return "AO";
182                 if (channel == 0) return "AO.R";
183                 if (channel == 1) return "AO.G";
184                 return "AO.B";
185         }
186         if (passtype == SCE_PASS_ENVIRONMENT) {
187                 if (channel == -1) return "Env";
188                 if (channel == 0) return "Env.R";
189                 if (channel == 1) return "Env.G";
190                 return "Env.B";
191         }
192         if (passtype == SCE_PASS_INDIRECT) {
193                 if (channel == -1) return "Indirect";
194                 if (channel == 0) return "Indirect.R";
195                 if (channel == 1) return "Indirect.G";
196                 return "Indirect.B";
197         }
198         if (passtype == SCE_PASS_REFLECT) {
199                 if (channel == -1) return "Reflect";
200                 if (channel == 0) return "Reflect.R";
201                 if (channel == 1) return "Reflect.G";
202                 return "Reflect.B";
203         }
204         if (passtype == SCE_PASS_REFRACT) {
205                 if (channel == -1) return "Refract";
206                 if (channel == 0) return "Refract.R";
207                 if (channel == 1) return "Refract.G";
208                 return "Refract.B";
209         }
210         if (passtype == SCE_PASS_INDEXOB) {
211                 if (channel == -1) return "IndexOB";
212                 return "IndexOB.X";
213         }
214         if (passtype == SCE_PASS_INDEXMA) {
215                 if (channel == -1) return "IndexMA";
216                 return "IndexMA.X";
217         }
218         if (passtype == SCE_PASS_MIST) {
219                 if (channel == -1) return "Mist";
220                 return "Mist.Z";
221         }
222         if (passtype == SCE_PASS_RAYHITS) {
223                 if (channel == -1) return "Rayhits";
224                 if (channel == 0) return "Rayhits.R";
225                 if (channel == 1) return "Rayhits.G";
226                 return "Rayhits.B";
227         }
228         if (passtype == SCE_PASS_DIFFUSE_DIRECT) {
229                 if (channel == -1) return "DiffDir";
230                 if (channel == 0) return "DiffDir.R";
231                 if (channel == 1) return "DiffDir.G";
232                 return "DiffDir.B";
233         }
234         if (passtype == SCE_PASS_DIFFUSE_INDIRECT) {
235                 if (channel == -1) return "DiffInd";
236                 if (channel == 0) return "DiffInd.R";
237                 if (channel == 1) return "DiffInd.G";
238                 return "DiffInd.B";
239         }
240         if (passtype == SCE_PASS_DIFFUSE_COLOR) {
241                 if (channel == -1) return "DiffCol";
242                 if (channel == 0) return "DiffCol.R";
243                 if (channel == 1) return "DiffCol.G";
244                 return "DiffCol.B";
245         }
246         if (passtype == SCE_PASS_GLOSSY_DIRECT) {
247                 if (channel == -1) return "GlossDir";
248                 if (channel == 0) return "GlossDir.R";
249                 if (channel == 1) return "GlossDir.G";
250                 return "GlossDir.B";
251         }
252         if (passtype == SCE_PASS_GLOSSY_INDIRECT) {
253                 if (channel == -1) return "GlossInd";
254                 if (channel == 0) return "GlossInd.R";
255                 if (channel == 1) return "GlossInd.G";
256                 return "GlossInd.B";
257         }
258         if (passtype == SCE_PASS_GLOSSY_COLOR) {
259                 if (channel == -1) return "GlossCol";
260                 if (channel == 0) return "GlossCol.R";
261                 if (channel == 1) return "GlossCol.G";
262                 return "GlossCol.B";
263         }
264         if (passtype == SCE_PASS_TRANSM_DIRECT) {
265                 if (channel == -1) return "TransDir";
266                 if (channel == 0) return "TransDir.R";
267                 if (channel == 1) return "TransDir.G";
268                 return "TransDir.B";
269         }
270         if (passtype == SCE_PASS_TRANSM_INDIRECT) {
271                 if (channel == -1) return "TransInd";
272                 if (channel == 0) return "TransInd.R";
273                 if (channel == 1) return "TransInd.G";
274                 return "TransInd.B";
275         }
276         if (passtype == SCE_PASS_TRANSM_COLOR) {
277                 if (channel == -1) return "TransCol";
278                 if (channel == 0) return "TransCol.R";
279                 if (channel == 1) return "TransCol.G";
280                 return "TransCol.B";
281         }
282         if (passtype == SCE_PASS_SUBS_DIRECT) {
283                 if (channel == -1) return "SubsDir";
284                 if (channel == 0) return "SubsDir.R";
285                 if (channel == 1) return "SubsDir.G";
286                 return "SubsDir.B";
287         }
288         if (passtype == SCE_PASS_SUBS_INDIRECT) {
289                 if (channel == -1) return "SubsInd";
290                 if (channel == 0) return "SubsInd.R";
291                 if (channel == 1) return "SubsInd.G";
292                 return "SubsInd.B";
293         }
294         if (passtype == SCE_PASS_SUBS_COLOR) {
295                 if (channel == -1) return "SubsCol";
296                 if (channel == 0) return "SubsCol.R";
297                 if (channel == 1) return "SubsCol.G";
298                 return "SubsCol.B";
299         }
300         return "Unknown";
301 }
302
303 static int passtype_from_name(const char *str)
304 {
305         
306         if (strcmp(str, "Combined") == 0)
307                 return SCE_PASS_COMBINED;
308
309         if (strcmp(str, "Depth") == 0)
310                 return SCE_PASS_Z;
311
312         if (strcmp(str, "Vector") == 0)
313                 return SCE_PASS_VECTOR;
314
315         if (strcmp(str, "Normal") == 0)
316                 return SCE_PASS_NORMAL;
317
318         if (strcmp(str, "UV") == 0)
319                 return SCE_PASS_UV;
320
321         if (strcmp(str, "Color") == 0)
322                 return SCE_PASS_RGBA;
323
324         if (strcmp(str, "Emit") == 0)
325                 return SCE_PASS_EMIT;
326
327         if (strcmp(str, "Diffuse") == 0)
328                 return SCE_PASS_DIFFUSE;
329
330         if (strcmp(str, "Spec") == 0)
331                 return SCE_PASS_SPEC;
332
333         if (strcmp(str, "Shadow") == 0)
334                 return SCE_PASS_SHADOW;
335         
336         if (strcmp(str, "AO") == 0)
337                 return SCE_PASS_AO;
338
339         if (strcmp(str, "Env") == 0)
340                 return SCE_PASS_ENVIRONMENT;
341
342         if (strcmp(str, "Indirect") == 0)
343                 return SCE_PASS_INDIRECT;
344
345         if (strcmp(str, "Reflect") == 0)
346                 return SCE_PASS_REFLECT;
347
348         if (strcmp(str, "Refract") == 0)
349                 return SCE_PASS_REFRACT;
350
351         if (strcmp(str, "IndexOB") == 0)
352                 return SCE_PASS_INDEXOB;
353
354         if (strcmp(str, "IndexMA") == 0)
355                 return SCE_PASS_INDEXMA;
356
357         if (strcmp(str, "Mist") == 0)
358                 return SCE_PASS_MIST;
359         
360         if (strcmp(str, "RayHits") == 0)
361                 return SCE_PASS_RAYHITS;
362
363         if (strcmp(str, "DiffDir") == 0)
364                 return SCE_PASS_DIFFUSE_DIRECT;
365
366         if (strcmp(str, "DiffInd") == 0)
367                 return SCE_PASS_DIFFUSE_INDIRECT;
368
369         if (strcmp(str, "DiffCol") == 0)
370                 return SCE_PASS_DIFFUSE_COLOR;
371
372         if (strcmp(str, "GlossDir") == 0)
373                 return SCE_PASS_GLOSSY_DIRECT;
374
375         if (strcmp(str, "GlossInd") == 0)
376                 return SCE_PASS_GLOSSY_INDIRECT;
377
378         if (strcmp(str, "GlossCol") == 0)
379                 return SCE_PASS_GLOSSY_COLOR;
380
381         if (strcmp(str, "TransDir") == 0)
382                 return SCE_PASS_TRANSM_DIRECT;
383
384         if (strcmp(str, "TransInd") == 0)
385                 return SCE_PASS_TRANSM_INDIRECT;
386
387         if (strcmp(str, "TransCol") == 0)
388                 return SCE_PASS_TRANSM_COLOR;
389                 
390         if (strcmp(str, "SubsDir") == 0)
391                 return SCE_PASS_SUBS_DIRECT;
392
393         if (strcmp(str, "SubsInd") == 0)
394                 return SCE_PASS_SUBS_INDIRECT;
395
396         if (strcmp(str, "SubsCol") == 0)
397                 return SCE_PASS_SUBS_COLOR;
398
399         return 0;
400 }
401
402 /********************************** New **************************************/
403
404 static void render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype)
405 {
406         const char *typestr = get_pass_name(passtype, 0);
407         RenderPass *rpass = MEM_callocN(sizeof(RenderPass), typestr);
408         int rectsize = rr->rectx * rr->recty * channels;
409         
410         BLI_addtail(&rl->passes, rpass);
411         rpass->passtype = passtype;
412         rpass->channels = channels;
413         rpass->rectx = rl->rectx;
414         rpass->recty = rl->recty;
415         BLI_strncpy(rpass->name, get_pass_name(rpass->passtype, -1), sizeof(rpass->name));
416         
417         if (rl->exrhandle) {
418                 int a;
419                 for (a = 0; a < channels; a++)
420                         IMB_exr_add_channel(rl->exrhandle, rl->name, get_pass_name(passtype, a), 0, 0, NULL);
421         }
422         else {
423                 float *rect;
424                 int x;
425                 
426                 rpass->rect = MEM_mapallocN(sizeof(float) * rectsize, typestr);
427                 
428                 if (passtype == SCE_PASS_VECTOR) {
429                         /* initialize to max speed */
430                         rect = rpass->rect;
431                         for (x = rectsize - 1; x >= 0; x--)
432                                 rect[x] = PASS_VECTOR_MAX;
433                 }
434                 else if (passtype == SCE_PASS_Z) {
435                         rect = rpass->rect;
436                         for (x = rectsize - 1; x >= 0; x--)
437                                 rect[x] = 10e10;
438                 }
439         }
440 }
441
442 /* called by main render as well for parts */
443 /* will read info from Render *re to define layers */
444 /* called in threads */
445 /* re->winx,winy is coordinate space of entire image, partrct the part within */
446 RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuffers, const char *layername)
447 {
448         RenderResult *rr;
449         RenderLayer *rl;
450         SceneRenderLayer *srl;
451         int rectx, recty, nr;
452         
453         rectx = BLI_rcti_size_x(partrct);
454         recty = BLI_rcti_size_y(partrct);
455         
456         if (rectx <= 0 || recty <= 0)
457                 return NULL;
458         
459         rr = MEM_callocN(sizeof(RenderResult), "new render result");
460         rr->rectx = rectx;
461         rr->recty = recty;
462         rr->renrect.xmin = 0; rr->renrect.xmax = rectx - 2 * crop;
463         /* crop is one or two extra pixels rendered for filtering, is used for merging and display too */
464         rr->crop = crop;
465
466         /* tilerect is relative coordinates within render disprect. do not subtract crop yet */
467         rr->tilerect.xmin = partrct->xmin - re->disprect.xmin;
468         rr->tilerect.xmax = partrct->xmax - re->disprect.xmin;
469         rr->tilerect.ymin = partrct->ymin - re->disprect.ymin;
470         rr->tilerect.ymax = partrct->ymax - re->disprect.ymin;
471         
472         if (savebuffers) {
473                 rr->do_exr_tile = TRUE;
474         }
475
476         /* check renderdata for amount of layers */
477         for (nr = 0, srl = re->r.layers.first; srl; srl = srl->next, nr++) {
478
479                 if (layername && layername[0])
480                         if (strcmp(srl->name, layername) != 0)
481                                 continue;
482
483                 if ((re->r.scemode & R_SINGLE_LAYER) && nr != re->r.actlay)
484                         continue;
485                 if (srl->layflag & SCE_LAY_DISABLE)
486                         continue;
487                 
488                 rl = MEM_callocN(sizeof(RenderLayer), "new render layer");
489                 BLI_addtail(&rr->layers, rl);
490                 
491                 BLI_strncpy(rl->name, srl->name, sizeof(rl->name));
492                 rl->lay = srl->lay;
493                 rl->lay_zmask = srl->lay_zmask;
494                 rl->lay_exclude = srl->lay_exclude;
495                 rl->layflag = srl->layflag;
496                 rl->passflag = srl->passflag; /* for debugging: srl->passflag | SCE_PASS_RAYHITS; */
497                 rl->pass_xor = srl->pass_xor;
498                 rl->light_override = srl->light_override;
499                 rl->mat_override = srl->mat_override;
500                 rl->rectx = rectx;
501                 rl->recty = recty;
502                 
503                 if (rr->do_exr_tile) {
504                         rl->exrhandle = IMB_exr_get_handle();
505
506                         IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.R", 0, 0, NULL);
507                         IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.G", 0, 0, NULL);
508                         IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.B", 0, 0, NULL);
509                         IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.A", 0, 0, NULL);
510                 }
511                 else
512                         rl->rectf = MEM_mapallocN(rectx * recty * sizeof(float) * 4, "Combined rgba");
513                 
514                 if (srl->passflag  & SCE_PASS_Z)
515                         render_layer_add_pass(rr, rl, 1, SCE_PASS_Z);
516                 if (srl->passflag  & SCE_PASS_VECTOR)
517                         render_layer_add_pass(rr, rl, 4, SCE_PASS_VECTOR);
518                 if (srl->passflag  & SCE_PASS_NORMAL)
519                         render_layer_add_pass(rr, rl, 3, SCE_PASS_NORMAL);
520                 if (srl->passflag  & SCE_PASS_UV) 
521                         render_layer_add_pass(rr, rl, 3, SCE_PASS_UV);
522                 if (srl->passflag  & SCE_PASS_RGBA)
523                         render_layer_add_pass(rr, rl, 4, SCE_PASS_RGBA);
524                 if (srl->passflag  & SCE_PASS_EMIT)
525                         render_layer_add_pass(rr, rl, 3, SCE_PASS_EMIT);
526                 if (srl->passflag  & SCE_PASS_DIFFUSE)
527                         render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE);
528                 if (srl->passflag  & SCE_PASS_SPEC)
529                         render_layer_add_pass(rr, rl, 3, SCE_PASS_SPEC);
530                 if (srl->passflag  & SCE_PASS_AO)
531                         render_layer_add_pass(rr, rl, 3, SCE_PASS_AO);
532                 if (srl->passflag  & SCE_PASS_ENVIRONMENT)
533                         render_layer_add_pass(rr, rl, 3, SCE_PASS_ENVIRONMENT);
534                 if (srl->passflag  & SCE_PASS_INDIRECT)
535                         render_layer_add_pass(rr, rl, 3, SCE_PASS_INDIRECT);
536                 if (srl->passflag  & SCE_PASS_SHADOW)
537                         render_layer_add_pass(rr, rl, 3, SCE_PASS_SHADOW);
538                 if (srl->passflag  & SCE_PASS_REFLECT)
539                         render_layer_add_pass(rr, rl, 3, SCE_PASS_REFLECT);
540                 if (srl->passflag  & SCE_PASS_REFRACT)
541                         render_layer_add_pass(rr, rl, 3, SCE_PASS_REFRACT);
542                 if (srl->passflag  & SCE_PASS_INDEXOB)
543                         render_layer_add_pass(rr, rl, 1, SCE_PASS_INDEXOB);
544                 if (srl->passflag  & SCE_PASS_INDEXMA)
545                         render_layer_add_pass(rr, rl, 1, SCE_PASS_INDEXMA);
546                 if (srl->passflag  & SCE_PASS_MIST)
547                         render_layer_add_pass(rr, rl, 1, SCE_PASS_MIST);
548                 if (rl->passflag & SCE_PASS_RAYHITS)
549                         render_layer_add_pass(rr, rl, 4, SCE_PASS_RAYHITS);
550                 if (srl->passflag  & SCE_PASS_DIFFUSE_DIRECT)
551                         render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_DIRECT);
552                 if (srl->passflag  & SCE_PASS_DIFFUSE_INDIRECT)
553                         render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_INDIRECT);
554                 if (srl->passflag  & SCE_PASS_DIFFUSE_COLOR)
555                         render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_COLOR);
556                 if (srl->passflag  & SCE_PASS_GLOSSY_DIRECT)
557                         render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_DIRECT);
558                 if (srl->passflag  & SCE_PASS_GLOSSY_INDIRECT)
559                         render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_INDIRECT);
560                 if (srl->passflag  & SCE_PASS_GLOSSY_COLOR)
561                         render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_COLOR);
562                 if (srl->passflag  & SCE_PASS_TRANSM_DIRECT)
563                         render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_DIRECT);
564                 if (srl->passflag  & SCE_PASS_TRANSM_INDIRECT)
565                         render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_INDIRECT);
566                 if (srl->passflag  & SCE_PASS_TRANSM_COLOR)
567                         render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_COLOR);
568                 if (srl->passflag  & SCE_PASS_SUBS_DIRECT)
569                         render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBS_DIRECT);
570                 if (srl->passflag  & SCE_PASS_SUBS_INDIRECT)
571                         render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBS_INDIRECT);
572                 if (srl->passflag  & SCE_PASS_SUBS_COLOR)
573                         render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBS_COLOR);
574         }
575         /* sss, previewrender and envmap don't do layers, so we make a default one */
576         if (rr->layers.first == NULL && !(layername && layername[0])) {
577                 rl = MEM_callocN(sizeof(RenderLayer), "new render layer");
578                 BLI_addtail(&rr->layers, rl);
579                 
580                 rl->rectx = rectx;
581                 rl->recty = recty;
582
583                 /* duplicate code... */
584                 if (rr->do_exr_tile) {
585                         rl->exrhandle = IMB_exr_get_handle();
586
587                         IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.R", 0, 0, NULL);
588                         IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.G", 0, 0, NULL);
589                         IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.B", 0, 0, NULL);
590                         IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.A", 0, 0, NULL);
591                 }
592                 else {
593                         rl->rectf = MEM_mapallocN(rectx * recty * sizeof(float) * 4, "Combined rgba");
594                 }
595                 
596                 /* note, this has to be in sync with scene.c */
597                 rl->lay = (1 << 20) - 1;
598                 rl->layflag = 0x7FFF;    /* solid ztra halo strand */
599                 rl->passflag = SCE_PASS_COMBINED;
600                 
601                 re->r.actlay = 0;
602         }
603         
604         /* border render; calculate offset for use in compositor. compo is centralized coords */
605         /* XXX obsolete? I now use it for drawing border render offset (ton) */
606         rr->xof = re->disprect.xmin + BLI_rcti_cent_x(&re->disprect) - (re->winx / 2);
607         rr->yof = re->disprect.ymin + BLI_rcti_cent_y(&re->disprect) - (re->winy / 2);
608         
609         return rr;
610 }
611
612 /* allocate osa new results for samples */
613 RenderResult *render_result_new_full_sample(Render *re, ListBase *lb, rcti *partrct, int crop, int savebuffers)
614 {
615         int a;
616         
617         if (re->osa == 0)
618                 return render_result_new(re, partrct, crop, savebuffers, RR_ALL_LAYERS);
619         
620         for (a = 0; a < re->osa; a++) {
621                 RenderResult *rr = render_result_new(re, partrct, crop, savebuffers, RR_ALL_LAYERS);
622                 BLI_addtail(lb, rr);
623                 rr->sample_nr = a;
624         }
625         
626         return lb->first;
627 }
628
629 /* callbacks for render_result_new_from_exr */
630 static void *ml_addlayer_cb(void *base, const char *str)
631 {
632         RenderResult *rr = base;
633         RenderLayer *rl;
634         
635         rl = MEM_callocN(sizeof(RenderLayer), "new render layer");
636         BLI_addtail(&rr->layers, rl);
637         
638         BLI_strncpy(rl->name, str, EXR_LAY_MAXNAME);
639         return rl;
640 }
641
642 static void ml_addpass_cb(void *UNUSED(base), void *lay, const char *str, float *rect, int totchan, const char *chan_id)
643 {
644         RenderLayer *rl = lay;
645         RenderPass *rpass = MEM_callocN(sizeof(RenderPass), "loaded pass");
646         int a;
647         
648         BLI_addtail(&rl->passes, rpass);
649         rpass->channels = totchan;
650
651         rpass->passtype = passtype_from_name(str);
652         if (rpass->passtype == 0) printf("unknown pass %s\n", str);
653         rl->passflag |= rpass->passtype;
654         
655         BLI_strncpy(rpass->name, str, EXR_PASS_MAXNAME);
656         /* channel id chars */
657         for (a = 0; a < totchan; a++)
658                 rpass->chan_id[a] = chan_id[a];
659         
660         rpass->rect = rect;
661 }
662
663 /* from imbuf, if a handle was returned we convert this to render result */
664 RenderResult *render_result_new_from_exr(void *exrhandle, const char *colorspace, int predivide, int rectx, int recty)
665 {
666         RenderResult *rr = MEM_callocN(sizeof(RenderResult), __func__);
667         RenderLayer *rl;
668         RenderPass *rpass;
669         const char *to_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR);
670
671         rr->rectx = rectx;
672         rr->recty = recty;
673         
674         IMB_exr_multilayer_convert(exrhandle, rr, ml_addlayer_cb, ml_addpass_cb);
675
676         for (rl = rr->layers.first; rl; rl = rl->next) {
677                 rl->rectx = rectx;
678                 rl->recty = recty;
679
680                 for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
681                         rpass->rectx = rectx;
682                         rpass->recty = recty;
683
684                         if (rpass->channels >= 3) {
685                                 IMB_colormanagement_transform(rpass->rect, rpass->rectx, rpass->recty, rpass->channels,
686                                                               colorspace, to_colorspace, predivide);
687                         }
688                 }
689         }
690         
691         return rr;
692 }
693
694 /*********************************** Merge ***********************************/
695
696 static void do_merge_tile(RenderResult *rr, RenderResult *rrpart, float *target, float *tile, int pixsize)
697 {
698         int y, ofs, copylen, tilex, tiley;
699         
700         copylen = tilex = rrpart->rectx;
701         tiley = rrpart->recty;
702         
703         if (rrpart->crop) { /* filters add pixel extra */
704                 tile += pixsize * (rrpart->crop + rrpart->crop * tilex);
705                 
706                 copylen = tilex - 2 * rrpart->crop;
707                 tiley -= 2 * rrpart->crop;
708                 
709                 ofs = (rrpart->tilerect.ymin + rrpart->crop) * rr->rectx + (rrpart->tilerect.xmin + rrpart->crop);
710                 target += pixsize * ofs;
711         }
712         else {
713                 ofs = (rrpart->tilerect.ymin * rr->rectx + rrpart->tilerect.xmin);
714                 target += pixsize * ofs;
715         }
716
717         copylen *= sizeof(float) * pixsize;
718         tilex *= pixsize;
719         ofs = pixsize * rr->rectx;
720
721         for (y = 0; y < tiley; y++) {
722                 memcpy(target, tile, copylen);
723                 target += ofs;
724                 tile += tilex;
725         }
726 }
727
728 /* used when rendering to a full buffer, or when reading the exr part-layer-pass file */
729 /* no test happens here if it fits... we also assume layers are in sync */
730 /* is used within threads */
731 void render_result_merge(RenderResult *rr, RenderResult *rrpart)
732 {
733         RenderLayer *rl, *rlp;
734         RenderPass *rpass, *rpassp;
735         
736         for (rl = rr->layers.first; rl; rl = rl->next) {
737                 rlp = RE_GetRenderLayer(rrpart, rl->name);
738                 if (rlp) {
739                         /* combined */
740                         if (rl->rectf && rlp->rectf)
741                                 do_merge_tile(rr, rrpart, rl->rectf, rlp->rectf, 4);
742
743                         /* passes are allocated in sync */
744                         for (rpass = rl->passes.first, rpassp = rlp->passes.first;
745                              rpass && rpassp;
746                              rpass = rpass->next, rpassp = rpassp->next)
747                         {
748                                 do_merge_tile(rr, rrpart, rpass->rect, rpassp->rect, rpass->channels);
749                         }
750                 }
751         }
752 }
753
754 /* for passes read from files, these have names stored */
755 static char *make_pass_name(RenderPass *rpass, int chan)
756 {
757         static char name[16];
758         int len;
759         
760         BLI_strncpy(name, rpass->name, EXR_PASS_MAXNAME);
761         len = strlen(name);
762         name[len] = '.';
763         name[len + 1] = rpass->chan_id[chan];
764         name[len + 2] = 0;
765
766         return name;
767 }
768
769 /* filename already made absolute */
770 /* called from within UI, saves both rendered result as a file-read result */
771 int RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *filename, int compress)
772 {
773         RenderLayer *rl;
774         RenderPass *rpass;
775         void *exrhandle = IMB_exr_get_handle();
776         int success;
777
778         BLI_make_existing_file(filename);
779         
780         /* composite result */
781         if (rr->rectf) {
782                 IMB_exr_add_channel(exrhandle, "Composite", "Combined.R", 4, 4 * rr->rectx, rr->rectf);
783                 IMB_exr_add_channel(exrhandle, "Composite", "Combined.G", 4, 4 * rr->rectx, rr->rectf + 1);
784                 IMB_exr_add_channel(exrhandle, "Composite", "Combined.B", 4, 4 * rr->rectx, rr->rectf + 2);
785                 IMB_exr_add_channel(exrhandle, "Composite", "Combined.A", 4, 4 * rr->rectx, rr->rectf + 3);
786         }
787         
788         /* add layers/passes and assign channels */
789         for (rl = rr->layers.first; rl; rl = rl->next) {
790                 
791                 /* combined */
792                 if (rl->rectf) {
793                         int a, xstride = 4;
794                         for (a = 0; a < xstride; a++) {
795                                 IMB_exr_add_channel(exrhandle, rl->name, get_pass_name(SCE_PASS_COMBINED, a),
796                                                     xstride, xstride * rr->rectx, rl->rectf + a);
797                         }
798                 }
799                 
800                 /* passes are allocated in sync */
801                 for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
802                         int a, xstride = rpass->channels;
803                         for (a = 0; a < xstride; a++) {
804                                 if (rpass->passtype) {
805                                         IMB_exr_add_channel(exrhandle, rl->name, get_pass_name(rpass->passtype, a),
806                                                             xstride, xstride * rr->rectx, rpass->rect + a);
807                                 }
808                                 else {
809                                         IMB_exr_add_channel(exrhandle, rl->name, make_pass_name(rpass, a),
810                                                             xstride, xstride * rr->rectx, rpass->rect + a);
811                                 }
812                         }
813                 }
814         }
815
816         /* when the filename has no permissions, this can fail */
817         if (IMB_exr_begin_write(exrhandle, filename, rr->rectx, rr->recty, compress)) {
818                 IMB_exr_write_channels(exrhandle);
819                 success = TRUE;
820         }
821         else {
822                 /* TODO, get the error from openexr's exception */
823                 BKE_report(reports, RPT_ERROR, "Error writing render result (see console)");
824                 success = FALSE;
825         }
826         IMB_exr_close(exrhandle);
827
828         return success;
829 }
830
831 /**************************** Single Layer Rendering *************************/
832
833 void render_result_single_layer_begin(Render *re)
834 {
835         /* all layers except the active one get temporally pushed away */
836
837         /* officially pushed result should be NULL... error can happen with do_seq */
838         RE_FreeRenderResult(re->pushedresult);
839         
840         re->pushedresult = re->result;
841         re->result = NULL;
842 }
843
844 /* if scemode is R_SINGLE_LAYER, at end of rendering, merge the both render results */
845 void render_result_single_layer_end(Render *re)
846 {
847         SceneRenderLayer *srl;
848         RenderLayer *rlpush;
849         RenderLayer *rl;
850         int nr;
851
852         if (re->result == NULL) {
853                 printf("pop render result error; no current result!\n");
854                 return;
855         }
856
857         if (!re->pushedresult)
858                 return;
859
860         if (re->pushedresult->rectx == re->result->rectx && re->pushedresult->recty == re->result->recty) {
861                 /* find which layer in re->pushedresult should be replaced */
862                 rl = re->result->layers.first;
863                 
864                 /* render result should be empty after this */
865                 BLI_remlink(&re->result->layers, rl);
866                 
867                 /* reconstruct render result layers */
868                 for (nr = 0, srl = re->scene->r.layers.first; srl; srl = srl->next, nr++) {
869                         if (nr == re->r.actlay) {
870                                 BLI_addtail(&re->result->layers, rl);
871                         }
872                         else {
873                                 rlpush = RE_GetRenderLayer(re->pushedresult, srl->name);
874                                 if (rlpush) {
875                                         BLI_remlink(&re->pushedresult->layers, rlpush);
876                                         BLI_addtail(&re->result->layers, rlpush);
877                                 }
878                         }
879                 }
880         }
881
882         RE_FreeRenderResult(re->pushedresult);
883         re->pushedresult = NULL;
884 }
885
886 /************************* EXR Tile File Rendering ***************************/
887
888 static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart)
889 {
890         RenderLayer *rlp, *rl;
891         RenderPass *rpassp;
892         int offs, partx, party;
893         
894         BLI_lock_thread(LOCK_IMAGE);
895         
896         for (rlp = rrpart->layers.first; rlp; rlp = rlp->next) {
897                 rl = RE_GetRenderLayer(rr, rlp->name);
898
899                 /* should never happen but prevents crash if it does */
900                 BLI_assert(rl);
901                 if (UNLIKELY(rl == NULL)) {
902                         continue;
903                 }
904
905                 if (rrpart->crop) { /* filters add pixel extra */
906                         offs = (rrpart->crop + rrpart->crop * rrpart->rectx);
907                 }
908                 else {
909                         offs = 0;
910                 }
911                 
912                 /* combined */
913                 if (rlp->rectf) {
914                         int a, xstride = 4;
915                         for (a = 0; a < xstride; a++) {
916                                 IMB_exr_set_channel(rl->exrhandle, rlp->name, get_pass_name(SCE_PASS_COMBINED, a), 
917                                                     xstride, xstride * rrpart->rectx, rlp->rectf + a + xstride * offs);
918                         }
919                 }
920                 
921                 /* passes are allocated in sync */
922                 for (rpassp = rlp->passes.first; rpassp; rpassp = rpassp->next) {
923                         int a, xstride = rpassp->channels;
924                         for (a = 0; a < xstride; a++) {
925                                 IMB_exr_set_channel(rl->exrhandle, rlp->name, get_pass_name(rpassp->passtype, a), 
926                                                     xstride, xstride * rrpart->rectx, rpassp->rect + a + xstride * offs);
927                         }
928                 }
929                 
930         }
931
932         party = rrpart->tilerect.ymin + rrpart->crop;
933         partx = rrpart->tilerect.xmin + rrpart->crop;
934
935         for (rlp = rrpart->layers.first; rlp; rlp = rlp->next) {
936                 rl = RE_GetRenderLayer(rr, rlp->name);
937
938                 /* should never happen but prevents crash if it does */
939                 BLI_assert(rl);
940                 if (UNLIKELY(rl == NULL)) {
941                         continue;
942                 }
943
944                 IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0);
945         }
946
947         BLI_unlock_thread(LOCK_IMAGE);
948 }
949
950 static void save_empty_result_tiles(Render *re)
951 {
952         RenderPart *pa;
953         RenderResult *rr;
954         RenderLayer *rl;
955         
956         for (rr = re->result; rr; rr = rr->next) {
957                 for (rl = rr->layers.first; rl; rl = rl->next) {
958                         IMB_exrtile_clear_channels(rl->exrhandle);
959                 
960                         for (pa = re->parts.first; pa; pa = pa->next) {
961                                 if (pa->status != PART_STATUS_READY) {
962                                         int party = pa->disprect.ymin - re->disprect.ymin + pa->crop;
963                                         int partx = pa->disprect.xmin - re->disprect.xmin + pa->crop;
964                                         IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0);
965                                 }
966                         }
967                 }
968         }
969 }
970
971 /* begin write of exr tile file */
972 void render_result_exr_file_begin(Render *re)
973 {
974         RenderResult *rr;
975         RenderLayer *rl;
976         char str[FILE_MAX];
977
978         for (rr = re->result; rr; rr = rr->next) {
979                 for (rl = rr->layers.first; rl; rl = rl->next) {
980                         render_result_exr_file_path(re->scene, rl->name, rr->sample_nr, str);
981                         printf("write exr tmp file, %dx%d, %s\n", rr->rectx, rr->recty, str);
982                         IMB_exrtile_begin_write(rl->exrhandle, str, 0, rr->rectx, rr->recty, re->partx, re->party);
983                 }
984         }
985 }
986
987 /* end write of exr tile file, read back first sample */
988 void render_result_exr_file_end(Render *re)
989 {
990         RenderResult *rr;
991         RenderLayer *rl;
992
993         save_empty_result_tiles(re);
994         
995         for (rr = re->result; rr; rr = rr->next) {
996                 for (rl = rr->layers.first; rl; rl = rl->next) {
997                         IMB_exr_close(rl->exrhandle);
998                         rl->exrhandle = NULL;
999                 }
1000
1001                 rr->do_exr_tile = FALSE;
1002         }
1003         
1004         render_result_free_list(&re->fullresult, re->result);
1005         re->result = NULL;
1006
1007         render_result_exr_file_read(re, 0);
1008 }
1009
1010 /* save part into exr file */
1011 void render_result_exr_file_merge(RenderResult *rr, RenderResult *rrpart)
1012 {
1013         for (; rr && rrpart; rr = rr->next, rrpart = rrpart->next)
1014                 save_render_result_tile(rr, rrpart);
1015 }
1016
1017 /* path to temporary exr file */
1018 void render_result_exr_file_path(Scene *scene, const char *layname, int sample, char *filepath)
1019 {
1020         char name[FILE_MAXFILE + MAX_ID_NAME + MAX_ID_NAME + 100], fi[FILE_MAXFILE];
1021         
1022         BLI_split_file_part(G.main->name, fi, sizeof(fi));
1023         if (sample == 0)
1024                 BLI_snprintf(name, sizeof(name), "%s_%s_%s.exr", fi, scene->id.name + 2, layname);
1025         else
1026                 BLI_snprintf(name, sizeof(name), "%s_%s_%s%d.exr", fi, scene->id.name + 2, layname, sample);
1027
1028         BLI_make_file_string("/", filepath, BLI_temporary_dir(), name);
1029 }
1030
1031 /* only for temp buffer files, makes exact copy of render result */
1032 int render_result_exr_file_read(Render *re, int sample)
1033 {
1034         RenderLayer *rl;
1035         char str[FILE_MAX];
1036         int success = TRUE;
1037
1038         RE_FreeRenderResult(re->result);
1039         re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS);
1040
1041         for (rl = re->result->layers.first; rl; rl = rl->next) {
1042
1043                 render_result_exr_file_path(re->scene, rl->name, sample, str);
1044                 printf("read exr tmp file: %s\n", str);
1045
1046                 if (!render_result_exr_file_read_path(re->result, rl, str)) {
1047                         printf("cannot read: %s\n", str);
1048                         success = FALSE;
1049
1050                 }
1051         }
1052
1053         return success;
1054 }
1055
1056 /* called for reading temp files, and for external engines */
1057 int render_result_exr_file_read_path(RenderResult *rr, RenderLayer *rl_single, const char *filepath)
1058 {
1059         RenderLayer *rl;
1060         RenderPass *rpass;
1061         void *exrhandle = IMB_exr_get_handle();
1062         int rectx, recty;
1063
1064         if (IMB_exr_begin_read(exrhandle, filepath, &rectx, &recty) == 0) {
1065                 printf("failed being read %s\n", filepath);
1066                 IMB_exr_close(exrhandle);
1067                 return 0;
1068         }
1069
1070         if (rr == NULL || rectx != rr->rectx || recty != rr->recty) {
1071                 if (rr)
1072                         printf("error in reading render result: dimensions don't match\n");
1073                 else
1074                         printf("error in reading render result: NULL result pointer\n");
1075                 IMB_exr_close(exrhandle);
1076                 return 0;
1077         }
1078
1079         for (rl = rr->layers.first; rl; rl = rl->next) {
1080                 if (rl_single && rl_single != rl)
1081                         continue;
1082
1083                 /* combined */
1084                 if (rl->rectf) {
1085                         int a, xstride = 4;
1086                         for (a = 0; a < xstride; a++)
1087                                 IMB_exr_set_channel(exrhandle, rl->name, get_pass_name(SCE_PASS_COMBINED, a), 
1088                                                     xstride, xstride * rectx, rl->rectf + a);
1089                 }
1090                 
1091                 /* passes are allocated in sync */
1092                 for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
1093                         int a, xstride = rpass->channels;
1094                         for (a = 0; a < xstride; a++)
1095                                 IMB_exr_set_channel(exrhandle, rl->name, get_pass_name(rpass->passtype, a), 
1096                                                     xstride, xstride * rectx, rpass->rect + a);
1097
1098                         BLI_strncpy(rpass->name, get_pass_name(rpass->passtype, -1), sizeof(rpass->name));
1099                 }
1100         }
1101
1102         IMB_exr_read_channels(exrhandle);
1103         IMB_exr_close(exrhandle);
1104
1105         return 1;
1106 }
1107
1108 /*************************** Combined Pixel Rect *****************************/
1109
1110 ImBuf *render_result_rect_to_ibuf(RenderResult *rr, RenderData *rd)
1111 {
1112         ImBuf *ibuf = IMB_allocImBuf(rr->rectx, rr->recty, rd->im_format.planes, 0);
1113         
1114         /* if not exists, BKE_imbuf_write makes one */
1115         ibuf->rect = (unsigned int *)rr->rect32;
1116         ibuf->rect_float = rr->rectf;
1117         ibuf->zbuf_float = rr->rectz;
1118         
1119         /* float factor for random dither, imbuf takes care of it */
1120         ibuf->dither = rd->dither_intensity;
1121         
1122         /* prepare to gamma correct to sRGB color space
1123          * note that sequence editor can generate 8bpc render buffers
1124          */
1125         if (ibuf->rect) {
1126                 if (BKE_imtype_valid_depths(rd->im_format.imtype) & (R_IMF_CHAN_DEPTH_12 | R_IMF_CHAN_DEPTH_16 | R_IMF_CHAN_DEPTH_24 | R_IMF_CHAN_DEPTH_32)) {
1127                         IMB_float_from_rect(ibuf);
1128                 }
1129                 else {
1130                         /* ensure no float buffer remained from previous frame */
1131                         ibuf->rect_float = NULL;
1132                 }
1133         }
1134
1135         /* color -> grayscale */
1136         /* editing directly would alter the render view */
1137         if (rd->im_format.planes == R_IMF_PLANES_BW) {
1138                 ImBuf *ibuf_bw = IMB_dupImBuf(ibuf);
1139                 IMB_color_to_bw(ibuf_bw);
1140                 IMB_freeImBuf(ibuf);
1141                 ibuf = ibuf_bw;
1142         }
1143
1144         return ibuf;
1145 }
1146
1147 void render_result_rect_from_ibuf(RenderResult *rr, RenderData *UNUSED(rd), ImBuf *ibuf)
1148 {
1149         if (ibuf->rect_float) {
1150                 if (!rr->rectf)
1151                         rr->rectf = MEM_mallocN(4 * sizeof(float) * rr->rectx * rr->recty, "render_seq rectf");
1152                 
1153                 memcpy(rr->rectf, ibuf->rect_float, 4 * sizeof(float) * rr->rectx * rr->recty);
1154
1155                 /* TSK! Since sequence render doesn't free the *rr render result, the old rect32
1156                  * can hang around when sequence render has rendered a 32 bits one before */
1157                 if (rr->rect32) {
1158                         MEM_freeN(rr->rect32);
1159                         rr->rect32 = NULL;
1160                 }
1161         }
1162         else if (ibuf->rect) {
1163                 if (!rr->rect32)
1164                         rr->rect32 = MEM_mallocN(sizeof(int) * rr->rectx * rr->recty, "render_seq rect");
1165
1166                 memcpy(rr->rect32, ibuf->rect, 4 * rr->rectx * rr->recty);
1167
1168                 /* Same things as above, old rectf can hang around from previous render. */
1169                 if (rr->rectf) {
1170                         MEM_freeN(rr->rectf);
1171                         rr->rectf = NULL;
1172                 }
1173         }
1174 }
1175
1176 void render_result_rect_fill_zero(RenderResult *rr)
1177 {
1178         if (rr->rectf)
1179                 memset(rr->rectf, 0, 4 * sizeof(float) * rr->rectx * rr->recty);
1180         else if (rr->rect32)
1181                 memset(rr->rect32, 0, 4 * rr->rectx * rr->recty);
1182         else
1183                 rr->rect32 = MEM_callocN(sizeof(int) * rr->rectx * rr->recty, "render_seq rect");
1184 }
1185
1186 void render_result_rect_get_pixels(RenderResult *rr, unsigned int *rect, int rectx, int recty,
1187                                    const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
1188 {
1189         if (rr->rect32) {
1190                 memcpy(rect, rr->rect32, sizeof(int) * rr->rectx * rr->recty);
1191         }
1192         else if (rr->rectf) {
1193                 IMB_display_buffer_transform_apply((unsigned char *) rect, rr->rectf, rr->rectx, rr->recty, 4,
1194                                                    view_settings, display_settings, TRUE);
1195         }
1196         else
1197                 /* else fill with black */
1198                 memset(rect, 0, sizeof(int) * rectx * recty);
1199 }
1200