2012-04-30 14:24:11 +00:00
|
|
|
/*
|
2012-01-05 17:50:09 +00:00
|
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2006 Blender Foundation.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* The Original Code is: all of this file.
|
|
|
|
*
|
|
|
|
* Contributor(s): none yet.
|
|
|
|
*
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
*/
|
|
|
|
|
|
|
|
/** \file blender/render/intern/source/render_result.c
|
|
|
|
* \ingroup render
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
2012-09-04 18:27:47 +00:00
|
|
|
#include <stdlib.h>
|
2012-01-05 17:50:09 +00:00
|
|
|
#include <string.h>
|
2016-01-11 12:32:29 +11:00
|
|
|
#include <errno.h>
|
2012-01-05 17:50:09 +00:00
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
2014-11-23 14:37:13 +01:00
|
|
|
#include "BKE_appdir.h"
|
2013-03-05 03:17:46 +00:00
|
|
|
#include "BLI_utildefines.h"
|
2012-01-05 17:50:09 +00:00
|
|
|
#include "BLI_listbase.h"
|
2014-11-14 11:00:10 +01:00
|
|
|
#include "BLI_hash_md5.h"
|
2012-01-05 17:50:09 +00:00
|
|
|
#include "BLI_path_util.h"
|
2012-08-20 15:29:02 +00:00
|
|
|
#include "BLI_rect.h"
|
2012-01-05 17:50:09 +00:00
|
|
|
#include "BLI_string.h"
|
|
|
|
#include "BLI_threads.h"
|
|
|
|
|
2013-01-10 16:37:48 +00:00
|
|
|
#include "BKE_image.h"
|
|
|
|
#include "BKE_global.h"
|
|
|
|
#include "BKE_main.h"
|
|
|
|
#include "BKE_report.h"
|
2015-04-06 10:40:12 -03:00
|
|
|
#include "BKE_camera.h"
|
|
|
|
#include "BKE_scene.h"
|
2013-01-10 16:37:48 +00:00
|
|
|
|
2012-01-05 17:50:09 +00:00
|
|
|
#include "IMB_imbuf.h"
|
|
|
|
#include "IMB_imbuf_types.h"
|
Color Management, Stage 2: Switch color pipeline to use OpenColorIO
Replace old color pipeline which was supporting linear/sRGB color spaces
only with OpenColorIO-based pipeline.
This introduces two configurable color spaces:
- Input color space for images and movie clips. This space is used to convert
images/movies from color space in which file is saved to Blender's linear
space (for float images, byte images are not internally converted, only input
space is stored for such images and used later).
This setting could be found in image/clip data block settings.
- Display color space which defines space in which particular display is working.
This settings could be found in scene's Color Management panel.
When render result is being displayed on the screen, apart from converting image
to display space, some additional conversions could happen.
This conversions are:
- View, which defines tone curve applying before display transformation.
These are different ways to view the image on the same display device.
For example it could be used to emulate film view on sRGB display.
- Exposure affects on image exposure before tone map is applied.
- Gamma is post-display gamma correction, could be used to match particular
display gamma.
- RGB curves are user-defined curves which are applying before display
transformation, could be used for different purposes.
All this settings by default are only applying on render result and does not
affect on other images. If some particular image needs to be affected by this
transformation, "View as Render" setting of image data block should be set to
truth. Movie clips are always affected by all display transformations.
This commit also introduces configurable color space in which sequencer is
working. This setting could be found in scene's Color Management panel and
it should be used if such stuff as grading needs to be done in color space
different from sRGB (i.e. when Film view on sRGB display is use, using VD16
space as sequencer's internal space would make grading working in space
which is close to the space using for display).
Some technical notes:
- Image buffer's float buffer is now always in linear space, even if it was
created from 16bit byte images.
- Space of byte buffer is stored in image buffer's rect_colorspace property.
- Profile of image buffer was removed since it's not longer meaningful.
- OpenGL and GLSL is supposed to always work in sRGB space. It is possible
to support other spaces, but it's quite large project which isn't so
much important.
- Legacy Color Management option disabled is emulated by using None display.
It could have some regressions, but there's no clear way to avoid them.
- If OpenColorIO is disabled on build time, it should make blender behaving
in the same way as previous release with color management enabled.
More details could be found at this page (more details would be added soon):
http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.64/Color_Management
--
Thanks to Xavier Thomas, Lukas Toene for initial work on OpenColorIO
integration and to Brecht van Lommel for some further development and code/
usecase review!
2012-09-15 10:05:07 +00:00
|
|
|
#include "IMB_colormanagement.h"
|
2012-01-05 17:50:09 +00:00
|
|
|
|
|
|
|
#include "intern/openexr/openexr_multi.h"
|
|
|
|
|
|
|
|
#include "render_result.h"
|
|
|
|
#include "render_types.h"
|
|
|
|
|
|
|
|
/********************************** Free *************************************/
|
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
static void render_result_views_free(RenderResult *res)
|
|
|
|
{
|
|
|
|
while (res->views.first) {
|
|
|
|
RenderView *rv = res->views.first;
|
|
|
|
BLI_remlink(&res->views, rv);
|
|
|
|
|
|
|
|
if (rv->rect32)
|
|
|
|
MEM_freeN(rv->rect32);
|
|
|
|
|
|
|
|
if (rv->rectz)
|
|
|
|
MEM_freeN(rv->rectz);
|
|
|
|
|
|
|
|
if (rv->rectf)
|
|
|
|
MEM_freeN(rv->rectf);
|
|
|
|
|
|
|
|
MEM_freeN(rv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-05 17:50:09 +00:00
|
|
|
void render_result_free(RenderResult *res)
|
|
|
|
{
|
2012-06-13 17:23:44 +00:00
|
|
|
if (res == NULL) return;
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
while (res->layers.first) {
|
2012-06-13 17:23:44 +00:00
|
|
|
RenderLayer *rl = res->layers.first;
|
2015-04-06 10:40:12 -03:00
|
|
|
|
2012-01-05 17:50:09 +00:00
|
|
|
/* acolrect and scolrect are optionally allocated in shade_tile, only free here since it can be used for drawing */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (rl->acolrect) MEM_freeN(rl->acolrect);
|
|
|
|
if (rl->scolrect) MEM_freeN(rl->scolrect);
|
2014-01-01 16:59:38 +06:00
|
|
|
if (rl->display_buffer) MEM_freeN(rl->display_buffer);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
while (rl->passes.first) {
|
2012-06-13 17:23:44 +00:00
|
|
|
RenderPass *rpass = rl->passes.first;
|
2012-03-24 06:38:07 +00:00
|
|
|
if (rpass->rect) MEM_freeN(rpass->rect);
|
2012-01-05 17:50:09 +00:00
|
|
|
BLI_remlink(&rl->passes, rpass);
|
|
|
|
MEM_freeN(rpass);
|
|
|
|
}
|
|
|
|
BLI_remlink(&res->layers, rl);
|
|
|
|
MEM_freeN(rl);
|
|
|
|
}
|
2015-04-06 10:40:12 -03:00
|
|
|
|
|
|
|
render_result_views_free(res);
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (res->rect32)
|
2012-01-05 17:50:09 +00:00
|
|
|
MEM_freeN(res->rect32);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (res->rectz)
|
2012-01-05 17:50:09 +00:00
|
|
|
MEM_freeN(res->rectz);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (res->rectf)
|
2012-01-05 17:50:09 +00:00
|
|
|
MEM_freeN(res->rectf);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (res->text)
|
2012-01-05 17:50:09 +00:00
|
|
|
MEM_freeN(res->text);
|
2014-12-05 21:56:29 +05:00
|
|
|
if (res->error)
|
|
|
|
MEM_freeN(res->error);
|
2015-04-21 18:33:33 +02:00
|
|
|
if (res->stamp_data)
|
|
|
|
MEM_freeN(res->stamp_data);
|
|
|
|
|
2012-01-05 17:50:09 +00:00
|
|
|
MEM_freeN(res);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* version that's compatible with fullsample buffers */
|
|
|
|
void render_result_free_list(ListBase *lb, RenderResult *rr)
|
|
|
|
{
|
|
|
|
RenderResult *rrnext;
|
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
for (; rr; rr = rrnext) {
|
|
|
|
rrnext = rr->next;
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (lb && lb->first)
|
2012-01-05 17:50:09 +00:00
|
|
|
BLI_remlink(lb, rr);
|
|
|
|
|
|
|
|
render_result_free(rr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
/********************************* multiview *************************************/
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
/* create a new views Listbase in rr without duplicating the memory pointers */
|
|
|
|
void render_result_views_shallowcopy(RenderResult *dst, RenderResult *src)
|
|
|
|
{
|
|
|
|
RenderView *rview;
|
|
|
|
|
|
|
|
if (dst == NULL || src == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (rview = src->views.first; rview; rview = rview->next) {
|
|
|
|
RenderView *rv;
|
|
|
|
|
|
|
|
rv = MEM_mallocN(sizeof(RenderView), "new render view");
|
|
|
|
BLI_addtail(&dst->views, rv);
|
|
|
|
|
|
|
|
BLI_strncpy(rv->name, rview->name, sizeof(rv->name));
|
|
|
|
rv->rectf = rview->rectf;
|
|
|
|
rv->rectz = rview->rectz;
|
|
|
|
rv->rect32 = rview->rect32;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* free the views created temporarily */
|
|
|
|
void render_result_views_shallowdelete(RenderResult *rr)
|
|
|
|
{
|
|
|
|
if (rr == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
while (rr->views.first) {
|
|
|
|
RenderView *rv = rr->views.first;
|
|
|
|
BLI_remlink(&rr->views, rv);
|
|
|
|
MEM_freeN(rv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *name_from_passtype(int passtype, int channel)
|
2012-01-05 17:50:09 +00:00
|
|
|
{
|
2012-03-24 06:38:07 +00:00
|
|
|
if (passtype == SCE_PASS_COMBINED) {
|
2012-06-13 17:23:44 +00:00
|
|
|
if (channel == -1) return "Combined";
|
|
|
|
if (channel == 0) return "Combined.R";
|
|
|
|
if (channel == 1) return "Combined.G";
|
|
|
|
if (channel == 2) return "Combined.B";
|
2012-01-05 17:50:09 +00:00
|
|
|
return "Combined.A";
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (passtype == SCE_PASS_Z) {
|
2012-06-13 17:23:44 +00:00
|
|
|
if (channel == -1) return "Depth";
|
2012-01-05 17:50:09 +00:00
|
|
|
return "Depth.Z";
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (passtype == SCE_PASS_VECTOR) {
|
2012-06-13 17:23:44 +00:00
|
|
|
if (channel == -1) return "Vector";
|
|
|
|
if (channel == 0) return "Vector.X";
|
|
|
|
if (channel == 1) return "Vector.Y";
|
|
|
|
if (channel == 2) return "Vector.Z";
|
2012-01-05 17:50:09 +00:00
|
|
|
return "Vector.W";
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (passtype == SCE_PASS_NORMAL) {
|
2012-06-13 17:23:44 +00:00
|
|
|
if (channel == -1) return "Normal";
|
|
|
|
if (channel == 0) return "Normal.X";
|
|
|
|
if (channel == 1) return "Normal.Y";
|
2012-01-05 17:50:09 +00:00
|
|
|
return "Normal.Z";
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (passtype == SCE_PASS_UV) {
|
2012-06-13 17:23:44 +00:00
|
|
|
if (channel == -1) return "UV";
|
|
|
|
if (channel == 0) return "UV.U";
|
|
|
|
if (channel == 1) return "UV.V";
|
2012-01-05 17:50:09 +00:00
|
|
|
return "UV.A";
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (passtype == SCE_PASS_RGBA) {
|
2012-06-13 17:23:44 +00:00
|
|
|
if (channel == -1) return "Color";
|
|
|
|
if (channel == 0) return "Color.R";
|
|
|
|
if (channel == 1) return "Color.G";
|
|
|
|
if (channel == 2) return "Color.B";
|
2012-01-05 17:50:09 +00:00
|
|
|
return "Color.A";
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (passtype == SCE_PASS_EMIT) {
|
2012-06-13 17:23:44 +00:00
|
|
|
if (channel == -1) return "Emit";
|
|
|
|
if (channel == 0) return "Emit.R";
|
|
|
|
if (channel == 1) return "Emit.G";
|
2012-01-05 17:50:09 +00:00
|
|
|
return "Emit.B";
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (passtype == SCE_PASS_DIFFUSE) {
|
2012-06-13 17:23:44 +00:00
|
|
|
if (channel == -1) return "Diffuse";
|
|
|
|
if (channel == 0) return "Diffuse.R";
|
|
|
|
if (channel == 1) return "Diffuse.G";
|
2012-01-05 17:50:09 +00:00
|
|
|
return "Diffuse.B";
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (passtype == SCE_PASS_SPEC) {
|
2012-06-13 17:23:44 +00:00
|
|
|
if (channel == -1) return "Spec";
|
|
|
|
if (channel == 0) return "Spec.R";
|
|
|
|
if (channel == 1) return "Spec.G";
|
2012-01-05 17:50:09 +00:00
|
|
|
return "Spec.B";
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (passtype == SCE_PASS_SHADOW) {
|
2012-06-13 17:23:44 +00:00
|
|
|
if (channel == -1) return "Shadow";
|
|
|
|
if (channel == 0) return "Shadow.R";
|
|
|
|
if (channel == 1) return "Shadow.G";
|
2012-01-05 17:50:09 +00:00
|
|
|
return "Shadow.B";
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (passtype == SCE_PASS_AO) {
|
2012-06-13 17:23:44 +00:00
|
|
|
if (channel == -1) return "AO";
|
|
|
|
if (channel == 0) return "AO.R";
|
|
|
|
if (channel == 1) return "AO.G";
|
2012-01-05 17:50:09 +00:00
|
|
|
return "AO.B";
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (passtype == SCE_PASS_ENVIRONMENT) {
|
2012-06-13 17:23:44 +00:00
|
|
|
if (channel == -1) return "Env";
|
|
|
|
if (channel == 0) return "Env.R";
|
|
|
|
if (channel == 1) return "Env.G";
|
2012-01-05 17:50:09 +00:00
|
|
|
return "Env.B";
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (passtype == SCE_PASS_INDIRECT) {
|
2012-06-13 17:23:44 +00:00
|
|
|
if (channel == -1) return "Indirect";
|
|
|
|
if (channel == 0) return "Indirect.R";
|
|
|
|
if (channel == 1) return "Indirect.G";
|
2012-01-05 17:50:09 +00:00
|
|
|
return "Indirect.B";
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (passtype == SCE_PASS_REFLECT) {
|
2012-06-13 17:23:44 +00:00
|
|
|
if (channel == -1) return "Reflect";
|
|
|
|
if (channel == 0) return "Reflect.R";
|
|
|
|
if (channel == 1) return "Reflect.G";
|
2012-01-05 17:50:09 +00:00
|
|
|
return "Reflect.B";
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (passtype == SCE_PASS_REFRACT) {
|
2012-06-13 17:23:44 +00:00
|
|
|
if (channel == -1) return "Refract";
|
|
|
|
if (channel == 0) return "Refract.R";
|
|
|
|
if (channel == 1) return "Refract.G";
|
2012-01-05 17:50:09 +00:00
|
|
|
return "Refract.B";
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (passtype == SCE_PASS_INDEXOB) {
|
2012-06-13 17:23:44 +00:00
|
|
|
if (channel == -1) return "IndexOB";
|
2012-01-05 17:50:09 +00:00
|
|
|
return "IndexOB.X";
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (passtype == SCE_PASS_INDEXMA) {
|
2012-06-13 17:23:44 +00:00
|
|
|
if (channel == -1) return "IndexMA";
|
2012-01-05 17:50:09 +00:00
|
|
|
return "IndexMA.X";
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (passtype == SCE_PASS_MIST) {
|
2012-06-13 17:23:44 +00:00
|
|
|
if (channel == -1) return "Mist";
|
2012-01-05 17:50:09 +00:00
|
|
|
return "Mist.Z";
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (passtype == SCE_PASS_RAYHITS) {
|
2012-06-13 17:23:44 +00:00
|
|
|
if (channel == -1) return "Rayhits";
|
|
|
|
if (channel == 0) return "Rayhits.R";
|
|
|
|
if (channel == 1) return "Rayhits.G";
|
2012-01-05 17:50:09 +00:00
|
|
|
return "Rayhits.B";
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (passtype == SCE_PASS_DIFFUSE_DIRECT) {
|
2012-06-13 17:23:44 +00:00
|
|
|
if (channel == -1) return "DiffDir";
|
|
|
|
if (channel == 0) return "DiffDir.R";
|
|
|
|
if (channel == 1) return "DiffDir.G";
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
return "DiffDir.B";
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (passtype == SCE_PASS_DIFFUSE_INDIRECT) {
|
2012-06-13 17:23:44 +00:00
|
|
|
if (channel == -1) return "DiffInd";
|
|
|
|
if (channel == 0) return "DiffInd.R";
|
|
|
|
if (channel == 1) return "DiffInd.G";
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
return "DiffInd.B";
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (passtype == SCE_PASS_DIFFUSE_COLOR) {
|
2012-06-13 17:23:44 +00:00
|
|
|
if (channel == -1) return "DiffCol";
|
|
|
|
if (channel == 0) return "DiffCol.R";
|
|
|
|
if (channel == 1) return "DiffCol.G";
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
return "DiffCol.B";
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (passtype == SCE_PASS_GLOSSY_DIRECT) {
|
2012-06-13 17:23:44 +00:00
|
|
|
if (channel == -1) return "GlossDir";
|
|
|
|
if (channel == 0) return "GlossDir.R";
|
|
|
|
if (channel == 1) return "GlossDir.G";
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
return "GlossDir.B";
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (passtype == SCE_PASS_GLOSSY_INDIRECT) {
|
2012-06-13 17:23:44 +00:00
|
|
|
if (channel == -1) return "GlossInd";
|
|
|
|
if (channel == 0) return "GlossInd.R";
|
|
|
|
if (channel == 1) return "GlossInd.G";
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
return "GlossInd.B";
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (passtype == SCE_PASS_GLOSSY_COLOR) {
|
2012-06-13 17:23:44 +00:00
|
|
|
if (channel == -1) return "GlossCol";
|
|
|
|
if (channel == 0) return "GlossCol.R";
|
|
|
|
if (channel == 1) return "GlossCol.G";
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
return "GlossCol.B";
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (passtype == SCE_PASS_TRANSM_DIRECT) {
|
2012-06-13 17:23:44 +00:00
|
|
|
if (channel == -1) return "TransDir";
|
|
|
|
if (channel == 0) return "TransDir.R";
|
|
|
|
if (channel == 1) return "TransDir.G";
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
return "TransDir.B";
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (passtype == SCE_PASS_TRANSM_INDIRECT) {
|
2012-06-13 17:23:44 +00:00
|
|
|
if (channel == -1) return "TransInd";
|
|
|
|
if (channel == 0) return "TransInd.R";
|
|
|
|
if (channel == 1) return "TransInd.G";
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
return "TransInd.B";
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (passtype == SCE_PASS_TRANSM_COLOR) {
|
2012-06-13 17:23:44 +00:00
|
|
|
if (channel == -1) return "TransCol";
|
|
|
|
if (channel == 0) return "TransCol.R";
|
|
|
|
if (channel == 1) return "TransCol.G";
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
return "TransCol.B";
|
|
|
|
}
|
2013-08-03 13:12:09 +00:00
|
|
|
if (passtype == SCE_PASS_SUBSURFACE_DIRECT) {
|
|
|
|
if (channel == -1) return "SubsurfaceDir";
|
|
|
|
if (channel == 0) return "SubsurfaceDir.R";
|
|
|
|
if (channel == 1) return "SubsurfaceDir.G";
|
2013-08-03 21:45:57 +00:00
|
|
|
return "SubsurfaceDir.B";
|
2013-08-03 13:12:09 +00:00
|
|
|
}
|
|
|
|
if (passtype == SCE_PASS_SUBSURFACE_INDIRECT) {
|
|
|
|
if (channel == -1) return "SubsurfaceInd";
|
|
|
|
if (channel == 0) return "SubsurfaceInd.R";
|
|
|
|
if (channel == 1) return "SubsurfaceInd.G";
|
2013-08-03 21:45:57 +00:00
|
|
|
return "SubsurfaceInd.B";
|
2013-08-03 13:12:09 +00:00
|
|
|
}
|
|
|
|
if (passtype == SCE_PASS_SUBSURFACE_COLOR) {
|
|
|
|
if (channel == -1) return "SubsurfaceCol";
|
|
|
|
if (channel == 0) return "SubsurfaceCol.R";
|
|
|
|
if (channel == 1) return "SubsurfaceCol.G";
|
2013-08-03 21:45:57 +00:00
|
|
|
return "SubsurfaceCol.B";
|
2013-08-03 13:12:09 +00:00
|
|
|
}
|
2012-01-05 17:50:09 +00:00
|
|
|
return "Unknown";
|
|
|
|
}
|
|
|
|
|
2016-06-01 17:25:05 +02:00
|
|
|
static int passtype_from_name(const char *str, int passflag)
|
2012-01-05 17:50:09 +00:00
|
|
|
{
|
2016-06-01 17:25:05 +02:00
|
|
|
/* We do not really support several pass of the same types, so in case we are opening an EXR file with several pass
|
|
|
|
* names detected as same pass type, only return that pass type the first time, and return 'uknown' for the others.
|
|
|
|
* See T48466. */
|
|
|
|
#define RETURN_PASS(_passtype) return (passflag & (_passtype)) ? 0 : (_passtype)
|
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "Combined"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_COMBINED);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "Depth"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_Z);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "Vector"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_VECTOR);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "Normal"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_NORMAL);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "UV"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_UV);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "Color"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_RGBA);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "Emit"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_EMIT);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "Diffuse"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_DIFFUSE);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "Spec"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_SPEC);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "Shadow"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_SHADOW);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "AO"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_AO);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "Env"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_ENVIRONMENT);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "Indirect"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_INDIRECT);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "Reflect"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_REFLECT);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "Refract"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_REFRACT);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "IndexOB"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_INDEXOB);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "IndexMA"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_INDEXMA);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "Mist"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_MIST);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "RayHits"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_RAYHITS);
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "DiffDir"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_DIFFUSE_DIRECT);
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "DiffInd"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_DIFFUSE_INDIRECT);
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "DiffCol"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_DIFFUSE_COLOR);
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "GlossDir"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_GLOSSY_DIRECT);
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "GlossInd"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_GLOSSY_INDIRECT);
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "GlossCol"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_GLOSSY_COLOR);
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "TransDir"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_TRANSM_DIRECT);
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "TransInd"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_TRANSM_INDIRECT);
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "TransCol"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_TRANSM_COLOR);
|
2013-08-03 13:12:09 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "SubsurfaceDir"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_SUBSURFACE_DIRECT);
|
2013-08-03 13:12:09 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "SubsurfaceInd"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_SUBSURFACE_INDIRECT);
|
2013-08-03 13:12:09 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
if (STRPREFIX(str, "SubsurfaceCol"))
|
2016-06-01 17:25:05 +02:00
|
|
|
RETURN_PASS(SCE_PASS_SUBSURFACE_COLOR);
|
Cycles: Render Passes
Currently supported passes:
* Combined, Z, Normal, Object Index, Material Index, Emission, Environment,
Diffuse/Glossy/Transmission x Direct/Indirect/Color
Not supported yet:
* UV, Vector, Mist
Only enabled for CPU devices at the moment, will do GPU tweaks tommorrow,
also for environment importance sampling.
Documentation:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes
2012-01-25 17:23:52 +00:00
|
|
|
|
2012-01-05 17:50:09 +00:00
|
|
|
return 0;
|
2016-06-01 17:25:05 +02:00
|
|
|
|
|
|
|
#undef RETURN_PASS
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
|
|
|
|
static void set_pass_name(char *passname, int passtype, int channel, const char *view)
|
|
|
|
{
|
2015-06-26 19:41:51 +02:00
|
|
|
const char delims[] = {'.', '\0'};
|
2015-06-27 11:00:47 +02:00
|
|
|
const char *sep;
|
|
|
|
const char *token;
|
2015-06-26 19:41:51 +02:00
|
|
|
size_t len;
|
2015-04-06 10:40:12 -03:00
|
|
|
|
|
|
|
const char *passtype_name = name_from_passtype(passtype, channel);
|
|
|
|
|
|
|
|
if (view == NULL || view[0] == '\0') {
|
|
|
|
BLI_strncpy(passname, passtype_name, EXR_PASS_MAXNAME);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-06-26 19:41:51 +02:00
|
|
|
len = BLI_str_rpartition(passtype_name, delims, &sep, &token);
|
2015-04-06 10:40:12 -03:00
|
|
|
|
2015-06-26 19:41:51 +02:00
|
|
|
if (sep) {
|
|
|
|
BLI_snprintf(passname, EXR_PASS_MAXNAME, "%.*s.%s.%s", (int)len, passtype_name, view, token);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BLI_snprintf(passname, EXR_PASS_MAXNAME, "%s.%s", passtype_name, view);
|
|
|
|
}
|
2015-04-06 10:40:12 -03:00
|
|
|
}
|
|
|
|
|
2012-01-05 17:50:09 +00:00
|
|
|
/********************************** New **************************************/
|
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
static RenderPass *render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype, const char *viewname)
|
2012-01-05 17:50:09 +00:00
|
|
|
{
|
2015-10-24 01:01:10 +11:00
|
|
|
const int view_id = BLI_findstringindex(&rr->views, viewname, offsetof(RenderView, name));
|
2015-04-06 10:40:12 -03:00
|
|
|
const char *typestr = name_from_passtype(passtype, -1);
|
2012-06-13 17:23:44 +00:00
|
|
|
RenderPass *rpass = MEM_callocN(sizeof(RenderPass), typestr);
|
2015-04-30 12:10:58 +02:00
|
|
|
size_t rectsize = ((size_t)rr->rectx) * rr->recty * channels;
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
rpass->passtype = passtype;
|
|
|
|
rpass->channels = channels;
|
|
|
|
rpass->rectx = rl->rectx;
|
|
|
|
rpass->recty = rl->recty;
|
2015-04-06 10:40:12 -03:00
|
|
|
rpass->view_id = view_id;
|
|
|
|
|
|
|
|
set_pass_name(rpass->name, rpass->passtype, -1, viewname);
|
|
|
|
BLI_strncpy(rpass->internal_name, typestr, sizeof(rpass->internal_name));
|
|
|
|
BLI_strncpy(rpass->view, viewname, sizeof(rpass->view));
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2012-09-04 13:29:07 +00:00
|
|
|
if (rl->exrhandle) {
|
2012-01-05 17:50:09 +00:00
|
|
|
int a;
|
2012-06-13 17:23:44 +00:00
|
|
|
for (a = 0; a < channels; a++)
|
2015-06-19 13:00:18 +02:00
|
|
|
IMB_exr_add_channel(rl->exrhandle, rl->name, name_from_passtype(passtype, a), viewname, 0, 0, NULL, false);
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
float *rect;
|
|
|
|
int x;
|
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
rpass->rect = MEM_mapallocN(sizeof(float) * rectsize, typestr);
|
2016-03-03 13:21:04 +05:00
|
|
|
if (rpass->rect == NULL) {
|
|
|
|
MEM_freeN(rpass);
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
if (passtype == SCE_PASS_VECTOR) {
|
2012-01-05 17:50:09 +00:00
|
|
|
/* initialize to max speed */
|
2012-06-13 17:23:44 +00:00
|
|
|
rect = rpass->rect;
|
|
|
|
for (x = rectsize - 1; x >= 0; x--)
|
|
|
|
rect[x] = PASS_VECTOR_MAX;
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
2012-06-13 17:23:44 +00:00
|
|
|
else if (passtype == SCE_PASS_Z) {
|
|
|
|
rect = rpass->rect;
|
|
|
|
for (x = rectsize - 1; x >= 0; x--)
|
|
|
|
rect[x] = 10e10;
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
}
|
2016-03-03 13:21:04 +05:00
|
|
|
|
|
|
|
BLI_addtail(&rl->passes, rpass);
|
|
|
|
|
2014-10-04 19:00:26 +06:00
|
|
|
return rpass;
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
2016-08-03 23:31:48 +02:00
|
|
|
/* wrapper called from render_opengl */
|
|
|
|
RenderPass *gp_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype, const char *viewname)
|
|
|
|
{
|
|
|
|
return render_layer_add_pass(rr, rl, channels, passtype, viewname);
|
|
|
|
}
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2014-10-04 19:00:26 +06:00
|
|
|
#ifdef WITH_CYCLES_DEBUG
|
2015-07-24 17:45:14 +02:00
|
|
|
const char *RE_debug_pass_name_get(int debug_type)
|
2014-10-04 19:00:26 +06:00
|
|
|
{
|
|
|
|
switch (debug_type) {
|
|
|
|
case RENDER_PASS_DEBUG_BVH_TRAVERSAL_STEPS:
|
|
|
|
return "BVH Traversal Steps";
|
2015-06-12 00:12:03 +02:00
|
|
|
case RENDER_PASS_DEBUG_BVH_TRAVERSED_INSTANCES:
|
|
|
|
return "BVH Traversed Instances";
|
2015-06-11 10:42:38 +02:00
|
|
|
case RENDER_PASS_DEBUG_RAY_BOUNCES:
|
|
|
|
return "Ray Bounces";
|
2014-10-04 19:00:26 +06:00
|
|
|
}
|
|
|
|
return "Unknown";
|
|
|
|
}
|
|
|
|
|
2015-07-24 17:45:14 +02:00
|
|
|
int RE_debug_pass_num_channels_get(int UNUSED(debug_type))
|
2015-07-24 12:29:05 +02:00
|
|
|
{
|
|
|
|
/* Only single case currently, might be handy for further debug passes. */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-10-04 19:00:26 +06:00
|
|
|
static RenderPass *render_layer_add_debug_pass(RenderResult *rr,
|
|
|
|
RenderLayer *rl,
|
|
|
|
int pass_type,
|
2015-04-06 10:40:12 -03:00
|
|
|
int debug_type,
|
|
|
|
const char *view)
|
2014-10-04 19:00:26 +06:00
|
|
|
{
|
2015-07-24 17:45:14 +02:00
|
|
|
const char *name = RE_debug_pass_name_get(debug_type);
|
|
|
|
int channels = RE_debug_pass_num_channels_get(debug_type);
|
2015-04-06 10:40:12 -03:00
|
|
|
RenderPass *rpass = render_layer_add_pass(rr, rl, channels, pass_type, view);
|
2016-03-03 13:21:04 +05:00
|
|
|
if (rpass == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2014-10-04 19:00:26 +06:00
|
|
|
rpass->debug_type = debug_type;
|
|
|
|
BLI_strncpy(rpass->name,
|
2015-07-24 17:45:14 +02:00
|
|
|
name,
|
2014-10-04 19:00:26 +06:00
|
|
|
sizeof(rpass->name));
|
2015-06-09 10:53:32 +02:00
|
|
|
BLI_strncpy(rpass->internal_name, rpass->name, sizeof(rpass->internal_name));
|
2014-10-04 19:00:26 +06:00
|
|
|
return rpass;
|
|
|
|
}
|
2015-07-24 23:05:11 +02:00
|
|
|
|
|
|
|
int RE_debug_pass_type_get(Render *re)
|
|
|
|
{
|
|
|
|
return re->r.debug_pass_type;
|
|
|
|
}
|
2014-10-04 19:00:26 +06:00
|
|
|
#endif
|
|
|
|
|
2012-01-05 17:50:09 +00:00
|
|
|
/* called by main render as well for parts */
|
|
|
|
/* will read info from Render *re to define layers */
|
|
|
|
/* called in threads */
|
|
|
|
/* re->winx,winy is coordinate space of entire image, partrct the part within */
|
2015-04-06 10:40:12 -03:00
|
|
|
RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuffers, const char *layername, const char *viewname)
|
2012-01-05 17:50:09 +00:00
|
|
|
{
|
|
|
|
RenderResult *rr;
|
|
|
|
RenderLayer *rl;
|
2015-04-06 10:40:12 -03:00
|
|
|
RenderView *rv;
|
2012-01-05 17:50:09 +00:00
|
|
|
SceneRenderLayer *srl;
|
2015-04-06 10:40:12 -03:00
|
|
|
int rectx, recty;
|
2015-05-12 11:36:52 -03:00
|
|
|
int nr;
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2012-09-23 18:50:56 +00:00
|
|
|
rectx = BLI_rcti_size_x(partrct);
|
|
|
|
recty = BLI_rcti_size_y(partrct);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
if (rectx <= 0 || recty <= 0)
|
2012-01-05 17:50:09 +00:00
|
|
|
return NULL;
|
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
rr = MEM_callocN(sizeof(RenderResult), "new render result");
|
|
|
|
rr->rectx = rectx;
|
|
|
|
rr->recty = recty;
|
|
|
|
rr->renrect.xmin = 0; rr->renrect.xmax = rectx - 2 * crop;
|
2012-01-05 17:50:09 +00:00
|
|
|
/* crop is one or two extra pixels rendered for filtering, is used for merging and display too */
|
2012-06-13 17:23:44 +00:00
|
|
|
rr->crop = crop;
|
2012-12-31 13:52:13 +00:00
|
|
|
|
2012-01-05 17:50:09 +00:00
|
|
|
/* tilerect is relative coordinates within render disprect. do not subtract crop yet */
|
2012-03-24 02:51:46 +00:00
|
|
|
rr->tilerect.xmin = partrct->xmin - re->disprect.xmin;
|
2012-09-04 13:29:07 +00:00
|
|
|
rr->tilerect.xmax = partrct->xmax - re->disprect.xmin;
|
2012-03-24 02:51:46 +00:00
|
|
|
rr->tilerect.ymin = partrct->ymin - re->disprect.ymin;
|
2012-09-04 13:29:07 +00:00
|
|
|
rr->tilerect.ymax = partrct->ymax - re->disprect.ymin;
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (savebuffers) {
|
2014-04-01 11:34:00 +11:00
|
|
|
rr->do_exr_tile = true;
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
2012-09-04 13:29:07 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
render_result_views_new(rr, &re->r);
|
|
|
|
|
2012-01-05 17:50:09 +00:00
|
|
|
/* check renderdata for amount of layers */
|
2012-06-13 17:23:44 +00:00
|
|
|
for (nr = 0, srl = re->r.layers.first; srl; srl = srl->next, nr++) {
|
2012-09-04 13:29:07 +00:00
|
|
|
|
|
|
|
if (layername && layername[0])
|
2015-01-26 16:03:11 +01:00
|
|
|
if (!STREQ(srl->name, layername))
|
2012-09-04 13:29:07 +00:00
|
|
|
continue;
|
|
|
|
|
2014-04-30 15:29:03 +09:00
|
|
|
if (re->r.scemode & R_SINGLE_LAYER) {
|
|
|
|
if (nr != re->r.actlay)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (srl->layflag & SCE_LAY_DISABLE)
|
|
|
|
continue;
|
|
|
|
}
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
rl = MEM_callocN(sizeof(RenderLayer), "new render layer");
|
2012-01-05 17:50:09 +00:00
|
|
|
BLI_addtail(&rr->layers, rl);
|
|
|
|
|
|
|
|
BLI_strncpy(rl->name, srl->name, sizeof(rl->name));
|
2012-06-13 17:23:44 +00:00
|
|
|
rl->lay = srl->lay;
|
|
|
|
rl->lay_zmask = srl->lay_zmask;
|
|
|
|
rl->lay_exclude = srl->lay_exclude;
|
|
|
|
rl->layflag = srl->layflag;
|
2012-07-07 22:51:57 +00:00
|
|
|
rl->passflag = srl->passflag; /* for debugging: srl->passflag | SCE_PASS_RAYHITS; */
|
2012-06-13 17:23:44 +00:00
|
|
|
rl->pass_xor = srl->pass_xor;
|
|
|
|
rl->light_override = srl->light_override;
|
|
|
|
rl->mat_override = srl->mat_override;
|
|
|
|
rl->rectx = rectx;
|
|
|
|
rl->recty = recty;
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2012-09-04 13:29:07 +00:00
|
|
|
if (rr->do_exr_tile) {
|
2016-03-03 13:13:42 +05:00
|
|
|
rl->display_buffer = MEM_mapallocN((size_t)rectx * recty * sizeof(unsigned int),
|
|
|
|
"Combined display space rgba");
|
2016-03-03 13:21:04 +05:00
|
|
|
if (rl->display_buffer == NULL) {
|
|
|
|
render_result_free(rr);
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-09-04 13:29:07 +00:00
|
|
|
rl->exrhandle = IMB_exr_get_handle();
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
2015-04-06 10:40:12 -03:00
|
|
|
|
|
|
|
for (rv = rr->views.first; rv; rv = rv->next) {
|
|
|
|
const char *view = rv->name;
|
|
|
|
|
|
|
|
if (viewname && viewname[0])
|
|
|
|
if (!STREQ(view, viewname))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (rr->do_exr_tile)
|
|
|
|
IMB_exr_add_view(rl->exrhandle, view);
|
|
|
|
|
2016-03-03 13:21:04 +05:00
|
|
|
#define RENDER_LAYER_ADD_PASS_SAFE(rr, rl, channels, passtype, viewname) \
|
|
|
|
do { \
|
|
|
|
if (render_layer_add_pass(rr, rl, channels, passtype, viewname) == NULL) { \
|
|
|
|
render_result_free(rr); \
|
|
|
|
return NULL; \
|
|
|
|
} \
|
|
|
|
} while (false)
|
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
/* a renderlayer should always have a Combined pass*/
|
|
|
|
render_layer_add_pass(rr, rl, 4, SCE_PASS_COMBINED, view);
|
|
|
|
|
|
|
|
if (srl->passflag & SCE_PASS_Z)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, SCE_PASS_Z, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (srl->passflag & SCE_PASS_VECTOR)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 4, SCE_PASS_VECTOR, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (srl->passflag & SCE_PASS_NORMAL)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_NORMAL, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (srl->passflag & SCE_PASS_UV)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_UV, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (srl->passflag & SCE_PASS_RGBA)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 4, SCE_PASS_RGBA, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (srl->passflag & SCE_PASS_EMIT)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_EMIT, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (srl->passflag & SCE_PASS_DIFFUSE)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_DIFFUSE, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (srl->passflag & SCE_PASS_SPEC)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_SPEC, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (srl->passflag & SCE_PASS_AO)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_AO, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (srl->passflag & SCE_PASS_ENVIRONMENT)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_ENVIRONMENT, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (srl->passflag & SCE_PASS_INDIRECT)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_INDIRECT, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (srl->passflag & SCE_PASS_SHADOW)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_SHADOW, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (srl->passflag & SCE_PASS_REFLECT)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_REFLECT, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (srl->passflag & SCE_PASS_REFRACT)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_REFRACT, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (srl->passflag & SCE_PASS_INDEXOB)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, SCE_PASS_INDEXOB, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (srl->passflag & SCE_PASS_INDEXMA)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, SCE_PASS_INDEXMA, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (srl->passflag & SCE_PASS_MIST)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, SCE_PASS_MIST, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (rl->passflag & SCE_PASS_RAYHITS)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 4, SCE_PASS_RAYHITS, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (srl->passflag & SCE_PASS_DIFFUSE_DIRECT)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_DIFFUSE_DIRECT, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (srl->passflag & SCE_PASS_DIFFUSE_INDIRECT)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_DIFFUSE_INDIRECT, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (srl->passflag & SCE_PASS_DIFFUSE_COLOR)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_DIFFUSE_COLOR, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (srl->passflag & SCE_PASS_GLOSSY_DIRECT)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_GLOSSY_DIRECT, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (srl->passflag & SCE_PASS_GLOSSY_INDIRECT)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_GLOSSY_INDIRECT, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (srl->passflag & SCE_PASS_GLOSSY_COLOR)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_GLOSSY_COLOR, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (srl->passflag & SCE_PASS_TRANSM_DIRECT)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_TRANSM_DIRECT, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (srl->passflag & SCE_PASS_TRANSM_INDIRECT)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_TRANSM_INDIRECT, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (srl->passflag & SCE_PASS_TRANSM_COLOR)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_TRANSM_COLOR, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (srl->passflag & SCE_PASS_SUBSURFACE_DIRECT)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_SUBSURFACE_DIRECT, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (srl->passflag & SCE_PASS_SUBSURFACE_INDIRECT)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_SUBSURFACE_INDIRECT, view);
|
2015-04-06 10:40:12 -03:00
|
|
|
if (srl->passflag & SCE_PASS_SUBSURFACE_COLOR)
|
2016-03-03 13:21:04 +05:00
|
|
|
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_SUBSURFACE_COLOR, view);
|
2014-10-04 19:00:26 +06:00
|
|
|
|
|
|
|
#ifdef WITH_CYCLES_DEBUG
|
2015-04-06 10:40:12 -03:00
|
|
|
if (BKE_scene_use_new_shading_nodes(re->scene)) {
|
2016-03-03 13:21:04 +05:00
|
|
|
if (render_layer_add_debug_pass(rr, rl, SCE_PASS_DEBUG,
|
|
|
|
re->r.debug_pass_type, view) == NULL)
|
|
|
|
{
|
|
|
|
render_result_free(rr);
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-04-06 10:40:12 -03:00
|
|
|
}
|
2014-10-04 19:00:26 +06:00
|
|
|
#endif
|
2016-03-03 13:21:04 +05:00
|
|
|
|
|
|
|
#undef RENDER_LAYER_ADD_PASS_SAFE
|
2015-04-06 10:40:12 -03:00
|
|
|
}
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
/* sss, previewrender and envmap don't do layers, so we make a default one */
|
2014-02-08 06:07:10 +11:00
|
|
|
if (BLI_listbase_is_empty(&rr->layers) && !(layername && layername[0])) {
|
2012-06-13 17:23:44 +00:00
|
|
|
rl = MEM_callocN(sizeof(RenderLayer), "new render layer");
|
2012-01-05 17:50:09 +00:00
|
|
|
BLI_addtail(&rr->layers, rl);
|
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
rl->rectx = rectx;
|
|
|
|
rl->recty = recty;
|
2012-01-05 17:50:09 +00:00
|
|
|
|
|
|
|
/* duplicate code... */
|
2012-09-04 13:29:07 +00:00
|
|
|
if (rr->do_exr_tile) {
|
2014-05-02 14:32:52 +02:00
|
|
|
rl->display_buffer = MEM_mapallocN(rectx * recty * sizeof(unsigned int), "Combined display space rgba");
|
2012-09-04 13:29:07 +00:00
|
|
|
rl->exrhandle = IMB_exr_get_handle();
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
2015-04-06 10:40:12 -03:00
|
|
|
|
|
|
|
for (rv = rr->views.first; rv; rv = rv->next) {
|
|
|
|
const char *view = rv->name;
|
|
|
|
|
|
|
|
if (viewname && viewname[0])
|
|
|
|
if (strcmp(view, viewname) != 0)
|
|
|
|
continue;
|
|
|
|
|
2015-05-12 11:36:52 -03:00
|
|
|
if (rr->do_exr_tile)
|
2015-04-06 10:40:12 -03:00
|
|
|
IMB_exr_add_view(rl->exrhandle, view);
|
|
|
|
|
2015-05-12 11:36:52 -03:00
|
|
|
/* a renderlayer should always have a Combined pass */
|
|
|
|
render_layer_add_pass(rr, rl, 4, SCE_PASS_COMBINED, view);
|
2012-09-04 18:27:47 +00:00
|
|
|
}
|
2015-04-06 10:40:12 -03:00
|
|
|
|
2012-01-05 17:50:09 +00:00
|
|
|
/* note, this has to be in sync with scene.c */
|
2012-06-13 17:23:44 +00:00
|
|
|
rl->lay = (1 << 20) - 1;
|
|
|
|
rl->layflag = 0x7FFF; /* solid ztra halo strand */
|
|
|
|
rl->passflag = SCE_PASS_COMBINED;
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
re->r.actlay = 0;
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* border render; calculate offset for use in compositor. compo is centralized coords */
|
Blender Internal Render in viewport
Because of our release soon, feature has been added behind the Debug Menu.
CTRL+ALT+D and set it to -1. Or commandline --debug-value -1.
When debug set to -1, you can put the viewport to 'render' mode, just like
for Cycles. Notes for testers: (and please no bugs in tracker for this :)
- It renders without AA, MBlur, Panorama, Sequence, Composite
- Only active render layer gets rendered. Select another layer will re-render.
- But yes: it works for FreeStyle renders!
- Also does great for local view.
- BI is not well suited for incremental renders on view changes. This only
works for non-raytrace scenes, or zoom in ortho or camera mode, or for
Material changes. In most cases a full re-render is being done.
- ESC works to stop the preview render.
- Borders render as well. (CTRL+B)
- Force a refresh with arrow key left/right. A lot of settings don't trigger
re-render yet.
Tech notes:
- FreeStyle is adding a lot of temp objects/meshes in the Main database. This
caused DepsGraph to trigger changes (and redraws). I've prepended the names
for these temp objects with char number 27 (ESC), and made these names be
ignored for tag update checking.
- Fixed some bugs that were noticable with such excessive re-renders, like
for opening file window, quit during renders.
2013-04-16 17:39:20 +00:00
|
|
|
/* XXX obsolete? I now use it for drawing border render offset (ton) */
|
2012-09-23 18:50:56 +00:00
|
|
|
rr->xof = re->disprect.xmin + BLI_rcti_cent_x(&re->disprect) - (re->winx / 2);
|
|
|
|
rr->yof = re->disprect.ymin + BLI_rcti_cent_y(&re->disprect) - (re->winy / 2);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
|
|
|
return rr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* allocate osa new results for samples */
|
2015-04-06 10:40:12 -03:00
|
|
|
RenderResult *render_result_new_full_sample(Render *re, ListBase *lb, rcti *partrct, int crop, int savebuffers, const char *viewname)
|
2012-01-05 17:50:09 +00:00
|
|
|
{
|
|
|
|
int a;
|
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
if (re->osa == 0)
|
2015-04-06 10:40:12 -03:00
|
|
|
return render_result_new(re, partrct, crop, savebuffers, RR_ALL_LAYERS, viewname);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
for (a = 0; a < re->osa; a++) {
|
2015-04-06 10:40:12 -03:00
|
|
|
RenderResult *rr = render_result_new(re, partrct, crop, savebuffers, RR_ALL_LAYERS, viewname);
|
2012-01-05 17:50:09 +00:00
|
|
|
BLI_addtail(lb, rr);
|
2012-06-13 17:23:44 +00:00
|
|
|
rr->sample_nr = a;
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return lb->first;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* callbacks for render_result_new_from_exr */
|
2012-07-08 00:04:41 +00:00
|
|
|
static void *ml_addlayer_cb(void *base, const char *str)
|
2012-01-05 17:50:09 +00:00
|
|
|
{
|
2012-06-13 17:23:44 +00:00
|
|
|
RenderResult *rr = base;
|
2012-01-05 17:50:09 +00:00
|
|
|
RenderLayer *rl;
|
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
rl = MEM_callocN(sizeof(RenderLayer), "new render layer");
|
2012-01-05 17:50:09 +00:00
|
|
|
BLI_addtail(&rr->layers, rl);
|
|
|
|
|
|
|
|
BLI_strncpy(rl->name, str, EXR_LAY_MAXNAME);
|
|
|
|
return rl;
|
|
|
|
}
|
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
static void ml_addpass_cb(void *base, void *lay, const char *str, float *rect, int totchan, const char *chan_id, const char *view)
|
2012-01-05 17:50:09 +00:00
|
|
|
{
|
2015-04-06 10:40:12 -03:00
|
|
|
RenderResult *rr = base;
|
2012-06-13 17:23:44 +00:00
|
|
|
RenderLayer *rl = lay;
|
|
|
|
RenderPass *rpass = MEM_callocN(sizeof(RenderPass), "loaded pass");
|
2012-01-05 17:50:09 +00:00
|
|
|
int a;
|
|
|
|
|
|
|
|
BLI_addtail(&rl->passes, rpass);
|
2012-06-13 17:23:44 +00:00
|
|
|
rpass->channels = totchan;
|
2016-06-01 17:25:05 +02:00
|
|
|
rpass->passtype = passtype_from_name(str, rl->passflag);
|
|
|
|
if (rpass->passtype == 0)
|
|
|
|
printf("unknown pass %s\n", str);
|
2012-01-05 17:50:09 +00:00
|
|
|
rl->passflag |= rpass->passtype;
|
|
|
|
|
|
|
|
/* channel id chars */
|
2012-06-13 17:23:44 +00:00
|
|
|
for (a = 0; a < totchan; a++)
|
|
|
|
rpass->chan_id[a] = chan_id[a];
|
2015-04-06 10:40:12 -03:00
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
rpass->rect = rect;
|
2015-04-06 10:40:12 -03:00
|
|
|
if (view[0] != '\0') {
|
|
|
|
BLI_snprintf(rpass->name, sizeof(rpass->name), "%s.%s", str, view);
|
|
|
|
rpass->view_id = BLI_findstringindex(&rr->views, view, offsetof(RenderView, name));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BLI_strncpy(rpass->name, str, sizeof(rpass->name));
|
|
|
|
rpass->view_id = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_strncpy(rpass->view, view, sizeof(rpass->view));
|
|
|
|
BLI_strncpy(rpass->internal_name, str, sizeof(rpass->internal_name));
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
static void *ml_addview_cb(void *base, const char *str)
|
|
|
|
{
|
|
|
|
RenderResult *rr = base;
|
|
|
|
RenderView *rv;
|
|
|
|
|
|
|
|
rv = MEM_callocN(sizeof(RenderView), "new render view");
|
|
|
|
BLI_strncpy(rv->name, str, EXR_VIEW_MAXNAME);
|
|
|
|
|
|
|
|
/* For stereo drawing we need to ensure:
|
|
|
|
* STEREO_LEFT_NAME == STEREO_LEFT_ID and
|
|
|
|
* STEREO_RIGHT_NAME == STEREO_RIGHT_ID */
|
|
|
|
|
|
|
|
if (STREQ(str, STEREO_LEFT_NAME)) {
|
|
|
|
BLI_addhead(&rr->views, rv);
|
|
|
|
}
|
|
|
|
else if (STREQ(str, STEREO_RIGHT_NAME)) {
|
|
|
|
RenderView *left_rv = BLI_findstring(&rr->views, STEREO_LEFT_NAME, offsetof(RenderView, name));
|
|
|
|
|
|
|
|
if (left_rv == NULL) {
|
|
|
|
BLI_addhead(&rr->views, rv);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BLI_insertlinkafter(&rr->views, left_rv, rv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BLI_addtail(&rr->views, rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int order_render_passes(const void *a, const void *b)
|
|
|
|
{
|
|
|
|
// 1 if a is after b
|
|
|
|
RenderPass *rpa = (RenderPass *) a;
|
|
|
|
RenderPass *rpb = (RenderPass *) b;
|
|
|
|
|
|
|
|
if (rpa->passtype > rpb->passtype)
|
|
|
|
return 1;
|
|
|
|
else if (rpa->passtype < rpb->passtype)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* they have the same type */
|
|
|
|
/* left first */
|
|
|
|
if (STREQ(rpa->view, STEREO_LEFT_NAME))
|
|
|
|
return 0;
|
|
|
|
else if (STREQ(rpb->view, STEREO_LEFT_NAME))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* right second */
|
|
|
|
if (STREQ(rpa->view, STEREO_RIGHT_NAME))
|
|
|
|
return 0;
|
|
|
|
else if (STREQ(rpb->view, STEREO_RIGHT_NAME))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* remaining in ascending id order */
|
|
|
|
return (rpa->view_id < rpb->view_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* from imbuf, if a handle was returned and it's not a singlelayer multiview we convert this to render result */
|
2014-04-01 11:34:00 +11:00
|
|
|
RenderResult *render_result_new_from_exr(void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty)
|
2012-01-05 17:50:09 +00:00
|
|
|
{
|
2012-07-08 00:04:41 +00:00
|
|
|
RenderResult *rr = MEM_callocN(sizeof(RenderResult), __func__);
|
2012-01-05 17:50:09 +00:00
|
|
|
RenderLayer *rl;
|
|
|
|
RenderPass *rpass;
|
2012-09-23 18:50:56 +00:00
|
|
|
const char *to_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR);
|
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
rr->rectx = rectx;
|
|
|
|
rr->recty = recty;
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
IMB_exr_multilayer_convert(exrhandle, rr, ml_addview_cb, ml_addlayer_cb, ml_addpass_cb);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
for (rl = rr->layers.first; rl; rl = rl->next) {
|
|
|
|
rl->rectx = rectx;
|
|
|
|
rl->recty = recty;
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
BLI_listbase_sort(&rl->passes, order_render_passes);
|
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
|
|
|
|
rpass->rectx = rectx;
|
|
|
|
rpass->recty = recty;
|
2012-09-23 18:50:56 +00:00
|
|
|
|
|
|
|
if (rpass->channels >= 3) {
|
|
|
|
IMB_colormanagement_transform(rpass->rect, rpass->rectx, rpass->recty, rpass->channels,
|
|
|
|
colorspace, to_colorspace, predivide);
|
|
|
|
}
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rr;
|
|
|
|
}
|
|
|
|
|
2015-04-28 17:36:44 -03:00
|
|
|
void render_result_view_new(RenderResult *rr, const char *viewname)
|
|
|
|
{
|
|
|
|
RenderView *rv = MEM_callocN(sizeof(RenderView), "new render view");
|
|
|
|
BLI_addtail(&rr->views, rv);
|
|
|
|
BLI_strncpy(rv->name, viewname, sizeof(rv->name));
|
|
|
|
}
|
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
void render_result_views_new(RenderResult *rr, RenderData *rd)
|
|
|
|
{
|
|
|
|
SceneRenderView *srv;
|
|
|
|
|
|
|
|
/* clear previously existing views - for sequencer */
|
|
|
|
render_result_views_free(rr);
|
|
|
|
|
|
|
|
/* check renderdata for amount of views */
|
|
|
|
if ((rd->scemode & R_MULTIVIEW)) {
|
|
|
|
for (srv = rd->views.first; srv; srv = srv->next) {
|
2015-04-28 17:36:44 -03:00
|
|
|
if (BKE_scene_multiview_is_render_view_active(rd, srv) == false)
|
|
|
|
continue;
|
|
|
|
render_result_view_new(rr, srv->name);
|
2015-04-06 10:40:12 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we always need at least one view */
|
|
|
|
if (BLI_listbase_count_ex(&rr->views, 1) == 0) {
|
2015-04-29 16:35:19 -03:00
|
|
|
render_result_view_new(rr, "");
|
2015-04-06 10:40:12 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-05 17:50:09 +00:00
|
|
|
/*********************************** Merge ***********************************/
|
|
|
|
|
|
|
|
static void do_merge_tile(RenderResult *rr, RenderResult *rrpart, float *target, float *tile, int pixsize)
|
|
|
|
{
|
2015-04-30 12:10:58 +02:00
|
|
|
int y, tilex, tiley;
|
|
|
|
size_t ofs, copylen;
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
copylen = tilex = rrpart->rectx;
|
|
|
|
tiley = rrpart->recty;
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
if (rrpart->crop) { /* filters add pixel extra */
|
2015-04-30 12:10:58 +02:00
|
|
|
tile += pixsize * (rrpart->crop + ((size_t)rrpart->crop) * tilex);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
copylen = tilex - 2 * rrpart->crop;
|
|
|
|
tiley -= 2 * rrpart->crop;
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2015-04-30 12:10:58 +02:00
|
|
|
ofs = (((size_t)rrpart->tilerect.ymin) + rrpart->crop) * rr->rectx + (rrpart->tilerect.xmin + rrpart->crop);
|
2012-06-13 17:23:44 +00:00
|
|
|
target += pixsize * ofs;
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
else {
|
2015-04-30 12:10:58 +02:00
|
|
|
ofs = (((size_t)rrpart->tilerect.ymin) * rr->rectx + rrpart->tilerect.xmin);
|
2012-06-13 17:23:44 +00:00
|
|
|
target += pixsize * ofs;
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
copylen *= sizeof(float) * pixsize;
|
2012-01-05 17:50:09 +00:00
|
|
|
tilex *= pixsize;
|
2012-06-13 17:23:44 +00:00
|
|
|
ofs = pixsize * rr->rectx;
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
for (y = 0; y < tiley; y++) {
|
2012-01-05 17:50:09 +00:00
|
|
|
memcpy(target, tile, copylen);
|
2012-06-13 17:23:44 +00:00
|
|
|
target += ofs;
|
|
|
|
tile += tilex;
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* used when rendering to a full buffer, or when reading the exr part-layer-pass file */
|
|
|
|
/* no test happens here if it fits... we also assume layers are in sync */
|
|
|
|
/* is used within threads */
|
|
|
|
void render_result_merge(RenderResult *rr, RenderResult *rrpart)
|
|
|
|
{
|
|
|
|
RenderLayer *rl, *rlp;
|
|
|
|
RenderPass *rpass, *rpassp;
|
|
|
|
|
2012-09-04 13:29:07 +00:00
|
|
|
for (rl = rr->layers.first; rl; rl = rl->next) {
|
2012-09-04 18:27:47 +00:00
|
|
|
rlp = RE_GetRenderLayer(rrpart, rl->name);
|
|
|
|
if (rlp) {
|
|
|
|
/* passes are allocated in sync */
|
|
|
|
for (rpass = rl->passes.first, rpassp = rlp->passes.first;
|
|
|
|
rpass && rpassp;
|
2015-04-06 10:40:12 -03:00
|
|
|
rpass = rpass->next)
|
2012-09-04 18:27:47 +00:00
|
|
|
{
|
2015-04-06 10:40:12 -03:00
|
|
|
/* renderresult have all passes, renderpart only the active view's passes */
|
|
|
|
if (strcmp(rpassp->name, rpass->name) != 0)
|
|
|
|
continue;
|
|
|
|
|
2012-09-04 18:27:47 +00:00
|
|
|
do_merge_tile(rr, rrpart, rpass->rect, rpassp->rect, rpass->channels);
|
2015-04-06 10:40:12 -03:00
|
|
|
|
|
|
|
/* manually get next render pass */
|
|
|
|
rpassp = rpassp->next;
|
2012-09-04 13:29:07 +00:00
|
|
|
}
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* for passes read from files, these have names stored */
|
|
|
|
static char *make_pass_name(RenderPass *rpass, int chan)
|
|
|
|
{
|
2015-04-06 10:40:12 -03:00
|
|
|
static char name[EXR_PASS_MAXNAME];
|
2012-01-05 17:50:09 +00:00
|
|
|
int len;
|
|
|
|
|
|
|
|
BLI_strncpy(name, rpass->name, EXR_PASS_MAXNAME);
|
2012-06-13 17:23:44 +00:00
|
|
|
len = strlen(name);
|
|
|
|
name[len] = '.';
|
|
|
|
name[len + 1] = rpass->chan_id[chan];
|
|
|
|
name[len + 2] = 0;
|
2012-01-05 17:50:09 +00:00
|
|
|
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
/* called from within UI and render pipeline, saves both rendered result as a file-read result
|
|
|
|
* if multiview is true saves all views in a multiview exr
|
|
|
|
* else if view is not NULL saves single view
|
|
|
|
* else saves stereo3d
|
|
|
|
*/
|
|
|
|
bool RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *filename, ImageFormatData *imf, const bool multiview, const char *view)
|
2012-01-05 17:50:09 +00:00
|
|
|
{
|
|
|
|
RenderLayer *rl;
|
|
|
|
RenderPass *rpass;
|
2015-04-06 10:40:12 -03:00
|
|
|
RenderView *rview;
|
2012-06-13 17:23:44 +00:00
|
|
|
void *exrhandle = IMB_exr_get_handle();
|
2015-04-13 19:56:56 -03:00
|
|
|
bool success;
|
2015-04-06 10:40:12 -03:00
|
|
|
int a, nr;
|
|
|
|
const char *chan_view = NULL;
|
|
|
|
int compress = (imf ? imf->exr_codec : 0);
|
|
|
|
size_t width, height;
|
|
|
|
|
|
|
|
const bool is_mono = view && !multiview;
|
2015-07-06 12:34:40 +02:00
|
|
|
const bool use_half_float = (imf != NULL) ? (imf->depth == R_IMF_CHAN_DEPTH_16) : false;
|
2015-04-06 10:40:12 -03:00
|
|
|
|
|
|
|
width = rr->rectx;
|
|
|
|
height = rr->recty;
|
|
|
|
|
|
|
|
if (imf && imf->imtype == R_IMF_IMTYPE_OPENEXR && multiview) {
|
|
|
|
/* single layer OpenEXR */
|
|
|
|
const char *RGBAZ[] = {"R", "G", "B", "A", "Z"};
|
|
|
|
for (nr = 0, rview = rr->views.first; rview; rview = rview->next, nr++) {
|
|
|
|
IMB_exr_add_view(exrhandle, rview->name);
|
|
|
|
|
|
|
|
if (rview->rectf) {
|
2015-06-19 13:00:18 +02:00
|
|
|
for (a = 0; a < 4; a++) {
|
2015-04-06 10:40:12 -03:00
|
|
|
IMB_exr_add_channel(exrhandle, "", RGBAZ[a],
|
2015-06-19 13:00:18 +02:00
|
|
|
rview->name, 4, 4 * width, rview->rectf + a,
|
|
|
|
use_half_float);
|
|
|
|
}
|
|
|
|
if (rview->rectz) {
|
|
|
|
/* Z pass is always stored as float. */
|
2015-04-06 10:40:12 -03:00
|
|
|
IMB_exr_add_channel(exrhandle, "", RGBAZ[4],
|
2015-06-19 13:00:18 +02:00
|
|
|
rview->name, 1, width, rview->rectz,
|
|
|
|
false);
|
|
|
|
}
|
2015-04-06 10:40:12 -03:00
|
|
|
}
|
|
|
|
}
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
2015-04-06 10:40:12 -03:00
|
|
|
else {
|
|
|
|
for (nr = 0, rview = rr->views.first; rview; rview = rview->next, nr++) {
|
|
|
|
if (is_mono) {
|
|
|
|
if (!STREQ(view, rview->name)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
chan_view = "";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* if rendered only one view, we treat as a a non-view render */
|
|
|
|
chan_view = rview->name;
|
|
|
|
}
|
|
|
|
|
|
|
|
IMB_exr_add_view(exrhandle, rview->name);
|
|
|
|
|
|
|
|
if (rview->rectf) {
|
2015-06-19 13:00:18 +02:00
|
|
|
for (a = 0; a < 4; a++) {
|
2015-04-06 10:40:12 -03:00
|
|
|
IMB_exr_add_channel(exrhandle, "Composite", name_from_passtype(SCE_PASS_COMBINED, a),
|
2015-06-19 13:00:18 +02:00
|
|
|
chan_view, 4, 4 * width, rview->rectf + a,
|
|
|
|
use_half_float);
|
|
|
|
}
|
2012-09-04 18:27:47 +00:00
|
|
|
}
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
2015-04-06 10:40:12 -03:00
|
|
|
|
|
|
|
/* add layers/passes and assign channels */
|
|
|
|
for (rl = rr->layers.first; rl; rl = rl->next) {
|
|
|
|
|
|
|
|
/* passes are allocated in sync */
|
|
|
|
for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
|
|
|
|
const int xstride = rpass->channels;
|
|
|
|
|
|
|
|
if (is_mono) {
|
|
|
|
if (!STREQ(view, rpass->view)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
chan_view = "";
|
2012-09-04 18:27:47 +00:00
|
|
|
}
|
|
|
|
else {
|
2015-04-06 10:40:12 -03:00
|
|
|
/* if rendered only one view, we treat as a a non-view render */
|
|
|
|
chan_view = (nr > 1 ? rpass->view :"");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (a = 0; a < xstride; a++) {
|
|
|
|
if (rpass->passtype) {
|
|
|
|
IMB_exr_add_channel(exrhandle, rl->name, name_from_passtype(rpass->passtype, a), chan_view,
|
2015-06-19 13:00:18 +02:00
|
|
|
xstride, xstride * width, rpass->rect + a,
|
|
|
|
rpass->passtype == SCE_PASS_Z ? false : use_half_float);
|
2015-04-06 10:40:12 -03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
IMB_exr_add_channel(exrhandle, rl->name, make_pass_name(rpass, a), chan_view,
|
2015-06-19 13:00:18 +02:00
|
|
|
xstride, xstride * width, rpass->rect + a,
|
|
|
|
use_half_float);
|
2015-04-06 10:40:12 -03:00
|
|
|
}
|
2012-09-04 18:27:47 +00:00
|
|
|
}
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-11 12:32:29 +11:00
|
|
|
errno = 0;
|
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
BLI_make_existing_file(filename);
|
|
|
|
|
2015-05-26 12:02:14 +02:00
|
|
|
if (IMB_exr_begin_write(exrhandle, filename, width, height, compress, rr->stamp_data)) {
|
2012-01-05 17:50:09 +00:00
|
|
|
IMB_exr_write_channels(exrhandle);
|
2015-04-13 19:56:56 -03:00
|
|
|
success = true;
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* TODO, get the error from openexr's exception */
|
2016-01-11 12:32:29 +11:00
|
|
|
BKE_reportf(reports, RPT_ERROR, "Error writing render result, %s (see console)", strerror(errno));
|
2014-04-01 11:34:00 +11:00
|
|
|
success = false;
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
IMB_exr_close(exrhandle);
|
2012-01-05 17:50:09 +00:00
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**************************** Single Layer Rendering *************************/
|
|
|
|
|
|
|
|
void render_result_single_layer_begin(Render *re)
|
|
|
|
{
|
|
|
|
/* all layers except the active one get temporally pushed away */
|
|
|
|
|
|
|
|
/* officially pushed result should be NULL... error can happen with do_seq */
|
|
|
|
RE_FreeRenderResult(re->pushedresult);
|
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
re->pushedresult = re->result;
|
|
|
|
re->result = NULL;
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* if scemode is R_SINGLE_LAYER, at end of rendering, merge the both render results */
|
|
|
|
void render_result_single_layer_end(Render *re)
|
|
|
|
{
|
|
|
|
SceneRenderLayer *srl;
|
|
|
|
RenderLayer *rlpush;
|
|
|
|
RenderLayer *rl;
|
|
|
|
int nr;
|
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
if (re->result == NULL) {
|
2012-01-05 17:50:09 +00:00
|
|
|
printf("pop render result error; no current result!\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!re->pushedresult)
|
2012-01-05 17:50:09 +00:00
|
|
|
return;
|
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
if (re->pushedresult->rectx == re->result->rectx && re->pushedresult->recty == re->result->recty) {
|
2012-01-05 17:50:09 +00:00
|
|
|
/* find which layer in re->pushedresult should be replaced */
|
2012-06-13 17:23:44 +00:00
|
|
|
rl = re->result->layers.first;
|
2012-01-05 17:50:09 +00:00
|
|
|
|
|
|
|
/* render result should be empty after this */
|
|
|
|
BLI_remlink(&re->result->layers, rl);
|
|
|
|
|
|
|
|
/* reconstruct render result layers */
|
2014-02-21 16:35:23 +01:00
|
|
|
for (nr = 0, srl = re->r.layers.first; srl; srl = srl->next, nr++) {
|
2012-09-04 18:27:47 +00:00
|
|
|
if (nr == re->r.actlay) {
|
2012-01-05 17:50:09 +00:00
|
|
|
BLI_addtail(&re->result->layers, rl);
|
2012-09-04 18:27:47 +00:00
|
|
|
}
|
2012-01-05 17:50:09 +00:00
|
|
|
else {
|
2012-06-13 17:23:44 +00:00
|
|
|
rlpush = RE_GetRenderLayer(re->pushedresult, srl->name);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (rlpush) {
|
2012-01-05 17:50:09 +00:00
|
|
|
BLI_remlink(&re->pushedresult->layers, rlpush);
|
|
|
|
BLI_addtail(&re->result->layers, rlpush);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RE_FreeRenderResult(re->pushedresult);
|
2012-06-13 17:23:44 +00:00
|
|
|
re->pushedresult = NULL;
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/************************* EXR Tile File Rendering ***************************/
|
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart, const char *viewname)
|
2012-01-05 17:50:09 +00:00
|
|
|
{
|
2012-09-04 13:29:07 +00:00
|
|
|
RenderLayer *rlp, *rl;
|
2012-01-05 17:50:09 +00:00
|
|
|
RenderPass *rpassp;
|
|
|
|
int offs, partx, party;
|
|
|
|
|
|
|
|
BLI_lock_thread(LOCK_IMAGE);
|
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
for (rlp = rrpart->layers.first; rlp; rlp = rlp->next) {
|
2012-09-04 18:27:47 +00:00
|
|
|
rl = RE_GetRenderLayer(rr, rlp->name);
|
|
|
|
|
|
|
|
/* should never happen but prevents crash if it does */
|
|
|
|
BLI_assert(rl);
|
|
|
|
if (UNLIKELY(rl == NULL)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
if (rrpart->crop) { /* filters add pixel extra */
|
|
|
|
offs = (rrpart->crop + rrpart->crop * rrpart->rectx);
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-06-13 17:23:44 +00:00
|
|
|
offs = 0;
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
2015-04-06 10:40:12 -03:00
|
|
|
|
2012-01-05 17:50:09 +00:00
|
|
|
/* passes are allocated in sync */
|
2012-06-13 17:23:44 +00:00
|
|
|
for (rpassp = rlp->passes.first; rpassp; rpassp = rpassp->next) {
|
2015-04-06 10:40:12 -03:00
|
|
|
const int xstride = rpassp->channels;
|
|
|
|
int a;
|
|
|
|
char passname[EXR_PASS_MAXNAME];
|
|
|
|
|
2012-09-04 18:27:47 +00:00
|
|
|
for (a = 0; a < xstride; a++) {
|
2015-04-06 10:40:12 -03:00
|
|
|
set_pass_name(passname, rpassp->passtype, a, rpassp->view);
|
|
|
|
|
|
|
|
IMB_exr_set_channel(rl->exrhandle, rlp->name, passname,
|
2012-06-13 17:23:44 +00:00
|
|
|
xstride, xstride * rrpart->rectx, rpassp->rect + a + xstride * offs);
|
2012-09-04 18:27:47 +00:00
|
|
|
}
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
party = rrpart->tilerect.ymin + rrpart->crop;
|
|
|
|
partx = rrpart->tilerect.xmin + rrpart->crop;
|
2012-09-04 13:29:07 +00:00
|
|
|
|
|
|
|
for (rlp = rrpart->layers.first; rlp; rlp = rlp->next) {
|
2012-09-04 18:27:47 +00:00
|
|
|
rl = RE_GetRenderLayer(rr, rlp->name);
|
|
|
|
|
|
|
|
/* should never happen but prevents crash if it does */
|
|
|
|
BLI_assert(rl);
|
|
|
|
if (UNLIKELY(rl == NULL)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0, viewname);
|
2012-09-04 13:29:07 +00:00
|
|
|
}
|
2012-01-05 17:50:09 +00:00
|
|
|
|
|
|
|
BLI_unlock_thread(LOCK_IMAGE);
|
|
|
|
}
|
|
|
|
|
2015-06-17 17:48:15 +02:00
|
|
|
void render_result_save_empty_result_tiles(Render *re)
|
2012-01-05 17:50:09 +00:00
|
|
|
{
|
|
|
|
RenderPart *pa;
|
|
|
|
RenderResult *rr;
|
2012-09-04 13:29:07 +00:00
|
|
|
RenderLayer *rl;
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
for (rr = re->result; rr; rr = rr->next) {
|
2012-09-04 13:29:07 +00:00
|
|
|
for (rl = rr->layers.first; rl; rl = rl->next) {
|
2015-04-06 10:40:12 -03:00
|
|
|
IMB_exr_clear_channels(rl->exrhandle);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2012-09-04 13:29:07 +00:00
|
|
|
for (pa = re->parts.first; pa; pa = pa->next) {
|
2013-01-01 16:15:13 +00:00
|
|
|
if (pa->status != PART_STATUS_READY) {
|
2012-09-04 13:29:07 +00:00
|
|
|
int party = pa->disprect.ymin - re->disprect.ymin + pa->crop;
|
|
|
|
int partx = pa->disprect.xmin - re->disprect.xmin + pa->crop;
|
2015-04-06 10:40:12 -03:00
|
|
|
IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0, re->viewname);
|
2012-09-04 13:29:07 +00:00
|
|
|
}
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* begin write of exr tile file */
|
|
|
|
void render_result_exr_file_begin(Render *re)
|
|
|
|
{
|
|
|
|
RenderResult *rr;
|
2012-09-04 13:29:07 +00:00
|
|
|
RenderLayer *rl;
|
2012-01-05 17:50:09 +00:00
|
|
|
char str[FILE_MAX];
|
2012-09-04 13:29:07 +00:00
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
for (rr = re->result; rr; rr = rr->next) {
|
2012-09-04 13:29:07 +00:00
|
|
|
for (rl = rr->layers.first; rl; rl = rl->next) {
|
|
|
|
render_result_exr_file_path(re->scene, rl->name, rr->sample_nr, str);
|
|
|
|
printf("write exr tmp file, %dx%d, %s\n", rr->rectx, rr->recty, str);
|
|
|
|
IMB_exrtile_begin_write(rl->exrhandle, str, 0, rr->rectx, rr->recty, re->partx, re->party);
|
|
|
|
}
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* end write of exr tile file, read back first sample */
|
|
|
|
void render_result_exr_file_end(Render *re)
|
|
|
|
{
|
|
|
|
RenderResult *rr;
|
2012-09-04 13:29:07 +00:00
|
|
|
RenderLayer *rl;
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
for (rr = re->result; rr; rr = rr->next) {
|
2012-09-04 13:29:07 +00:00
|
|
|
for (rl = rr->layers.first; rl; rl = rl->next) {
|
|
|
|
IMB_exr_close(rl->exrhandle);
|
|
|
|
rl->exrhandle = NULL;
|
|
|
|
}
|
|
|
|
|
2014-04-01 11:34:00 +11:00
|
|
|
rr->do_exr_tile = false;
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
render_result_free_list(&re->fullresult, re->result);
|
2012-06-13 17:23:44 +00:00
|
|
|
re->result = NULL;
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2014-06-28 19:13:54 +02:00
|
|
|
render_result_exr_file_read_sample(re, 0);
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* save part into exr file */
|
2015-04-06 10:40:12 -03:00
|
|
|
void render_result_exr_file_merge(RenderResult *rr, RenderResult *rrpart, const char *viewname)
|
2012-01-05 17:50:09 +00:00
|
|
|
{
|
2012-06-13 17:23:44 +00:00
|
|
|
for (; rr && rrpart; rr = rr->next, rrpart = rrpart->next)
|
2015-04-06 10:40:12 -03:00
|
|
|
save_render_result_tile(rr, rrpart, viewname);
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* path to temporary exr file */
|
2012-09-04 13:29:07 +00:00
|
|
|
void render_result_exr_file_path(Scene *scene, const char *layname, int sample, char *filepath)
|
2012-01-05 17:50:09 +00:00
|
|
|
{
|
2015-07-14 09:34:53 +10:00
|
|
|
char name[FILE_MAXFILE + MAX_ID_NAME + MAX_ID_NAME + 100];
|
|
|
|
const char *fi = BLI_path_basename(G.main->name);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2014-04-02 11:57:10 +02:00
|
|
|
if (sample == 0) {
|
T39690: Modifications to Blender's 'temp dir' system.
Current temporary data of Blender suffers one major issue - default 'temp' dir on Windows is never
automatically cleaned up, and can end being quite big when used by Blender, especially when we have
to store per-process data (using getpid() in file names).
To address this, this patch:
* Divides tempdir paths in two, one for 'base' temp dir (the same as previous unique tempdir path),
the other is a mkdtemp-generated sub-dir, specific to each Blender instance.
* Only uses base tempdir when we need some shallow persistance accross Blender sessions - and we always
reuse the same filename (quit.blend...) or generate small file (crash reports...).
* Uses temp sub-dir for heavy files like pointcache or renderEXRs (Save Buffer option).
* Erases temp sub-dir on quit or crash.
To get this working it also adds a working 'recursive delete' to BLI_delete() under Windows.
Note that, as in current code, the 'recover render result' hack-feature that was possible
with SaveBuffer option is still removed. A real renderresult cache feature will be added
soon, though.
Reviewers: campbellbarton, brecht, sergey
Reviewed By: campbellbarton, sergey
CC: sergey
Differential Revision: https://developer.blender.org/D531
2014-06-23 13:42:19 +02:00
|
|
|
BLI_snprintf(name, sizeof(name), "%s_%s_%s.exr", fi, scene->id.name + 2, layname);
|
2014-04-02 11:57:10 +02:00
|
|
|
}
|
|
|
|
else {
|
T39690: Modifications to Blender's 'temp dir' system.
Current temporary data of Blender suffers one major issue - default 'temp' dir on Windows is never
automatically cleaned up, and can end being quite big when used by Blender, especially when we have
to store per-process data (using getpid() in file names).
To address this, this patch:
* Divides tempdir paths in two, one for 'base' temp dir (the same as previous unique tempdir path),
the other is a mkdtemp-generated sub-dir, specific to each Blender instance.
* Only uses base tempdir when we need some shallow persistance accross Blender sessions - and we always
reuse the same filename (quit.blend...) or generate small file (crash reports...).
* Uses temp sub-dir for heavy files like pointcache or renderEXRs (Save Buffer option).
* Erases temp sub-dir on quit or crash.
To get this working it also adds a working 'recursive delete' to BLI_delete() under Windows.
Note that, as in current code, the 'recover render result' hack-feature that was possible
with SaveBuffer option is still removed. A real renderresult cache feature will be added
soon, though.
Reviewers: campbellbarton, brecht, sergey
Reviewed By: campbellbarton, sergey
CC: sergey
Differential Revision: https://developer.blender.org/D531
2014-06-23 13:42:19 +02:00
|
|
|
BLI_snprintf(name, sizeof(name), "%s_%s_%s%d.exr", fi, scene->id.name + 2, layname, sample);
|
2014-04-02 11:57:10 +02:00
|
|
|
}
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2015-01-16 18:48:59 +01:00
|
|
|
/* Make name safe for paths, see T43275. */
|
|
|
|
BLI_filename_make_safe(name);
|
|
|
|
|
2014-11-23 15:54:29 +01:00
|
|
|
BLI_make_file_string("/", filepath, BKE_tempdir_session(), name);
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
|
2014-06-28 19:13:54 +02:00
|
|
|
/* only for temp buffer, makes exact copy of render result */
|
|
|
|
int render_result_exr_file_read_sample(Render *re, int sample)
|
2012-01-05 17:50:09 +00:00
|
|
|
{
|
2012-09-04 13:29:07 +00:00
|
|
|
RenderLayer *rl;
|
2014-06-28 19:13:54 +02:00
|
|
|
char str[FILE_MAXFILE + MAX_ID_NAME + MAX_ID_NAME + 100] = "";
|
2014-04-01 11:34:00 +11:00
|
|
|
bool success = true;
|
2012-01-05 17:50:09 +00:00
|
|
|
|
|
|
|
RE_FreeRenderResult(re->result);
|
2015-04-06 10:40:12 -03:00
|
|
|
re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2012-09-04 13:29:07 +00:00
|
|
|
for (rl = re->result->layers.first; rl; rl = rl->next) {
|
|
|
|
render_result_exr_file_path(re->scene, rl->name, sample, str);
|
|
|
|
printf("read exr tmp file: %s\n", str);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2012-09-04 13:29:07 +00:00
|
|
|
if (!render_result_exr_file_read_path(re->result, rl, str)) {
|
|
|
|
printf("cannot read: %s\n", str);
|
2014-04-01 11:34:00 +11:00
|
|
|
success = false;
|
2012-09-04 13:29:07 +00:00
|
|
|
}
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* called for reading temp files, and for external engines */
|
2012-09-04 13:29:07 +00:00
|
|
|
int render_result_exr_file_read_path(RenderResult *rr, RenderLayer *rl_single, const char *filepath)
|
2012-01-05 17:50:09 +00:00
|
|
|
{
|
|
|
|
RenderLayer *rl;
|
|
|
|
RenderPass *rpass;
|
2012-06-13 17:23:44 +00:00
|
|
|
void *exrhandle = IMB_exr_get_handle();
|
2012-01-05 17:50:09 +00:00
|
|
|
int rectx, recty;
|
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
if (IMB_exr_begin_read(exrhandle, filepath, &rectx, &recty) == 0) {
|
2012-01-05 17:50:09 +00:00
|
|
|
printf("failed being read %s\n", filepath);
|
|
|
|
IMB_exr_close(exrhandle);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
if (rr == NULL || rectx != rr->rectx || recty != rr->recty) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (rr)
|
2012-01-05 17:50:09 +00:00
|
|
|
printf("error in reading render result: dimensions don't match\n");
|
|
|
|
else
|
|
|
|
printf("error in reading render result: NULL result pointer\n");
|
|
|
|
IMB_exr_close(exrhandle);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-06-13 17:23:44 +00:00
|
|
|
for (rl = rr->layers.first; rl; rl = rl->next) {
|
2012-09-04 13:29:07 +00:00
|
|
|
if (rl_single && rl_single != rl)
|
|
|
|
continue;
|
2012-01-05 17:50:09 +00:00
|
|
|
|
|
|
|
/* passes are allocated in sync */
|
2012-06-13 17:23:44 +00:00
|
|
|
for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
|
2015-04-06 10:40:12 -03:00
|
|
|
const int xstride = rpass->channels;
|
|
|
|
int a;
|
|
|
|
char passname[EXR_PASS_MAXNAME];
|
|
|
|
|
|
|
|
for (a = 0; a < xstride; a++) {
|
|
|
|
set_pass_name(passname, rpass->passtype, a, rpass->view);
|
|
|
|
IMB_exr_set_channel(exrhandle, rl->name, passname,
|
2012-06-13 17:23:44 +00:00
|
|
|
xstride, xstride * rectx, rpass->rect + a);
|
2015-04-06 10:40:12 -03:00
|
|
|
}
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
set_pass_name(rpass->name, rpass->passtype, -1, rpass->view);
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
IMB_exr_read_channels(exrhandle);
|
|
|
|
IMB_exr_close(exrhandle);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-06-28 19:13:54 +02:00
|
|
|
static void render_result_exr_file_cache_path(Scene *sce, const char *root, char *r_path)
|
|
|
|
{
|
|
|
|
char filename_full[FILE_MAX + MAX_ID_NAME + 100], filename[FILE_MAXFILE], dirname[FILE_MAXDIR];
|
|
|
|
char path_digest[16] = {0};
|
|
|
|
char path_hexdigest[33];
|
|
|
|
|
|
|
|
/* If root is relative, use either current .blend file dir, or temp one if not saved. */
|
|
|
|
if (G.main->name[0]) {
|
|
|
|
BLI_split_dirfile(G.main->name, dirname, filename, sizeof(dirname), sizeof(filename));
|
|
|
|
BLI_replace_extension(filename, sizeof(filename), ""); /* strip '.blend' */
|
2014-11-14 11:53:27 +01:00
|
|
|
BLI_hash_md5_buffer(G.main->name, strlen(G.main->name), path_digest);
|
2014-06-28 19:13:54 +02:00
|
|
|
}
|
|
|
|
else {
|
2014-11-23 15:54:29 +01:00
|
|
|
BLI_strncpy(dirname, BKE_tempdir_base(), sizeof(dirname));
|
2014-06-28 19:13:54 +02:00
|
|
|
BLI_strncpy(filename, "UNSAVED", sizeof(filename));
|
|
|
|
}
|
2014-11-14 11:53:27 +01:00
|
|
|
BLI_hash_md5_to_hexdigest(path_digest, path_hexdigest);
|
2014-06-28 19:13:54 +02:00
|
|
|
|
|
|
|
/* Default to *non-volatile* tmp dir. */
|
|
|
|
if (*root == '\0') {
|
2014-11-23 15:54:29 +01:00
|
|
|
root = BKE_tempdir_base();
|
2014-06-28 19:13:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
BLI_snprintf(filename_full, sizeof(filename_full), "cached_RR_%s_%s_%s.exr",
|
|
|
|
filename, sce->id.name + 2, path_hexdigest);
|
|
|
|
BLI_make_file_string(dirname, r_path, root, filename_full);
|
|
|
|
}
|
|
|
|
|
|
|
|
void render_result_exr_file_cache_write(Render *re)
|
|
|
|
{
|
|
|
|
RenderResult *rr = re->result;
|
|
|
|
char str[FILE_MAXFILE + FILE_MAXFILE + MAX_ID_NAME + 100];
|
|
|
|
char *root = U.render_cachedir;
|
|
|
|
|
|
|
|
render_result_exr_file_cache_path(re->scene, root, str);
|
|
|
|
printf("Caching exr file, %dx%d, %s\n", rr->rectx, rr->recty, str);
|
2015-04-06 10:40:12 -03:00
|
|
|
|
|
|
|
RE_WriteRenderResult(NULL, rr, str, NULL, true, NULL);
|
2014-06-28 19:13:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* For cache, makes exact copy of render result */
|
|
|
|
bool render_result_exr_file_cache_read(Render *re)
|
|
|
|
{
|
|
|
|
char str[FILE_MAXFILE + MAX_ID_NAME + MAX_ID_NAME + 100] = "";
|
|
|
|
char *root = U.render_cachedir;
|
|
|
|
|
|
|
|
RE_FreeRenderResult(re->result);
|
2015-04-06 10:40:12 -03:00
|
|
|
re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
|
2014-06-28 19:13:54 +02:00
|
|
|
|
|
|
|
/* First try cache. */
|
|
|
|
render_result_exr_file_cache_path(re->scene, root, str);
|
|
|
|
|
|
|
|
printf("read exr cache file: %s\n", str);
|
|
|
|
if (!render_result_exr_file_read_path(re->result, NULL, str)) {
|
|
|
|
printf("cannot read: %s\n", str);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-01-05 17:50:09 +00:00
|
|
|
/*************************** Combined Pixel Rect *****************************/
|
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
ImBuf *render_result_rect_to_ibuf(RenderResult *rr, RenderData *rd, const int view_id)
|
2012-01-05 17:50:09 +00:00
|
|
|
{
|
2012-12-31 13:52:13 +00:00
|
|
|
ImBuf *ibuf = IMB_allocImBuf(rr->rectx, rr->recty, rd->im_format.planes, 0);
|
2015-04-29 11:26:30 -03:00
|
|
|
RenderView *rv = RE_RenderViewGetById(rr, view_id);
|
|
|
|
|
2012-05-05 16:03:57 +00:00
|
|
|
/* if not exists, BKE_imbuf_write makes one */
|
2015-04-29 11:26:30 -03:00
|
|
|
ibuf->rect = (unsigned int *) rv->rect32;
|
|
|
|
ibuf->rect_float = rv->rectf;
|
|
|
|
ibuf->zbuf_float = rv->rectz;
|
|
|
|
|
2012-01-05 17:50:09 +00:00
|
|
|
/* float factor for random dither, imbuf takes care of it */
|
2012-06-13 17:23:44 +00:00
|
|
|
ibuf->dither = rd->dither_intensity;
|
2012-01-05 17:50:09 +00:00
|
|
|
|
Color Management, Stage 2: Switch color pipeline to use OpenColorIO
Replace old color pipeline which was supporting linear/sRGB color spaces
only with OpenColorIO-based pipeline.
This introduces two configurable color spaces:
- Input color space for images and movie clips. This space is used to convert
images/movies from color space in which file is saved to Blender's linear
space (for float images, byte images are not internally converted, only input
space is stored for such images and used later).
This setting could be found in image/clip data block settings.
- Display color space which defines space in which particular display is working.
This settings could be found in scene's Color Management panel.
When render result is being displayed on the screen, apart from converting image
to display space, some additional conversions could happen.
This conversions are:
- View, which defines tone curve applying before display transformation.
These are different ways to view the image on the same display device.
For example it could be used to emulate film view on sRGB display.
- Exposure affects on image exposure before tone map is applied.
- Gamma is post-display gamma correction, could be used to match particular
display gamma.
- RGB curves are user-defined curves which are applying before display
transformation, could be used for different purposes.
All this settings by default are only applying on render result and does not
affect on other images. If some particular image needs to be affected by this
transformation, "View as Render" setting of image data block should be set to
truth. Movie clips are always affected by all display transformations.
This commit also introduces configurable color space in which sequencer is
working. This setting could be found in scene's Color Management panel and
it should be used if such stuff as grading needs to be done in color space
different from sRGB (i.e. when Film view on sRGB display is use, using VD16
space as sequencer's internal space would make grading working in space
which is close to the space using for display).
Some technical notes:
- Image buffer's float buffer is now always in linear space, even if it was
created from 16bit byte images.
- Space of byte buffer is stored in image buffer's rect_colorspace property.
- Profile of image buffer was removed since it's not longer meaningful.
- OpenGL and GLSL is supposed to always work in sRGB space. It is possible
to support other spaces, but it's quite large project which isn't so
much important.
- Legacy Color Management option disabled is emulated by using None display.
It could have some regressions, but there's no clear way to avoid them.
- If OpenColorIO is disabled on build time, it should make blender behaving
in the same way as previous release with color management enabled.
More details could be found at this page (more details would be added soon):
http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.64/Color_Management
--
Thanks to Xavier Thomas, Lukas Toene for initial work on OpenColorIO
integration and to Brecht van Lommel for some further development and code/
usecase review!
2012-09-15 10:05:07 +00:00
|
|
|
/* prepare to gamma correct to sRGB color space
|
|
|
|
* note that sequence editor can generate 8bpc render buffers
|
|
|
|
*/
|
|
|
|
if (ibuf->rect) {
|
|
|
|
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)) {
|
2013-11-22 16:48:08 +06:00
|
|
|
if (rd->im_format.depth == R_IMF_CHAN_DEPTH_8) {
|
|
|
|
/* Higher depth bits are supported but not needed for current file output. */
|
|
|
|
ibuf->rect_float = NULL;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
IMB_float_from_rect(ibuf);
|
|
|
|
}
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
2013-03-24 12:13:13 +00:00
|
|
|
else {
|
2013-02-10 09:27:25 +00:00
|
|
|
/* ensure no float buffer remained from previous frame */
|
|
|
|
ibuf->rect_float = NULL;
|
|
|
|
}
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
|
2012-07-03 19:09:07 +00:00
|
|
|
/* color -> grayscale */
|
2012-01-05 17:50:09 +00:00
|
|
|
/* editing directly would alter the render view */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (rd->im_format.planes == R_IMF_PLANES_BW) {
|
2012-06-13 17:23:44 +00:00
|
|
|
ImBuf *ibuf_bw = IMB_dupImBuf(ibuf);
|
2012-01-05 17:50:09 +00:00
|
|
|
IMB_color_to_bw(ibuf_bw);
|
|
|
|
IMB_freeImBuf(ibuf);
|
2012-06-13 17:23:44 +00:00
|
|
|
ibuf = ibuf_bw;
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ibuf;
|
|
|
|
}
|
|
|
|
|
2015-11-16 18:20:41 +05:00
|
|
|
void RE_render_result_rect_from_ibuf(RenderResult *rr, RenderData *UNUSED(rd), ImBuf *ibuf, const int view_id)
|
2012-01-05 17:50:09 +00:00
|
|
|
{
|
2015-04-29 11:18:18 -03:00
|
|
|
RenderView *rv = RE_RenderViewGetById(rr, view_id);
|
2015-04-06 10:40:12 -03:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ibuf->rect_float) {
|
2015-04-06 10:40:12 -03:00
|
|
|
if (!rv->rectf)
|
|
|
|
rv->rectf = MEM_mallocN(4 * sizeof(float) * rr->rectx * rr->recty, "render_seq rectf");
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
memcpy(rv->rectf, ibuf->rect_float, 4 * sizeof(float) * rr->rectx * rr->recty);
|
Color Management, Stage 2: Switch color pipeline to use OpenColorIO
Replace old color pipeline which was supporting linear/sRGB color spaces
only with OpenColorIO-based pipeline.
This introduces two configurable color spaces:
- Input color space for images and movie clips. This space is used to convert
images/movies from color space in which file is saved to Blender's linear
space (for float images, byte images are not internally converted, only input
space is stored for such images and used later).
This setting could be found in image/clip data block settings.
- Display color space which defines space in which particular display is working.
This settings could be found in scene's Color Management panel.
When render result is being displayed on the screen, apart from converting image
to display space, some additional conversions could happen.
This conversions are:
- View, which defines tone curve applying before display transformation.
These are different ways to view the image on the same display device.
For example it could be used to emulate film view on sRGB display.
- Exposure affects on image exposure before tone map is applied.
- Gamma is post-display gamma correction, could be used to match particular
display gamma.
- RGB curves are user-defined curves which are applying before display
transformation, could be used for different purposes.
All this settings by default are only applying on render result and does not
affect on other images. If some particular image needs to be affected by this
transformation, "View as Render" setting of image data block should be set to
truth. Movie clips are always affected by all display transformations.
This commit also introduces configurable color space in which sequencer is
working. This setting could be found in scene's Color Management panel and
it should be used if such stuff as grading needs to be done in color space
different from sRGB (i.e. when Film view on sRGB display is use, using VD16
space as sequencer's internal space would make grading working in space
which is close to the space using for display).
Some technical notes:
- Image buffer's float buffer is now always in linear space, even if it was
created from 16bit byte images.
- Space of byte buffer is stored in image buffer's rect_colorspace property.
- Profile of image buffer was removed since it's not longer meaningful.
- OpenGL and GLSL is supposed to always work in sRGB space. It is possible
to support other spaces, but it's quite large project which isn't so
much important.
- Legacy Color Management option disabled is emulated by using None display.
It could have some regressions, but there's no clear way to avoid them.
- If OpenColorIO is disabled on build time, it should make blender behaving
in the same way as previous release with color management enabled.
More details could be found at this page (more details would be added soon):
http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.64/Color_Management
--
Thanks to Xavier Thomas, Lukas Toene for initial work on OpenColorIO
integration and to Brecht van Lommel for some further development and code/
usecase review!
2012-09-15 10:05:07 +00:00
|
|
|
|
2012-01-05 17:50:09 +00:00
|
|
|
/* TSK! Since sequence render doesn't free the *rr render result, the old rect32
|
2012-03-09 18:28:30 +00:00
|
|
|
* can hang around when sequence render has rendered a 32 bits one before */
|
2015-04-09 17:19:50 +10:00
|
|
|
MEM_SAFE_FREE(rv->rect32);
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (ibuf->rect) {
|
2015-04-06 10:40:12 -03:00
|
|
|
if (!rv->rect32)
|
|
|
|
rv->rect32 = MEM_mallocN(sizeof(int) * rr->rectx * rr->recty, "render_seq rect");
|
2012-01-05 17:50:09 +00:00
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
memcpy(rv->rect32, ibuf->rect, 4 * rr->rectx * rr->recty);
|
2012-01-05 17:50:09 +00:00
|
|
|
|
|
|
|
/* Same things as above, old rectf can hang around from previous render. */
|
2015-04-09 17:19:50 +10:00
|
|
|
MEM_SAFE_FREE(rv->rectf);
|
2015-04-06 10:40:12 -03:00
|
|
|
}
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
void render_result_rect_fill_zero(RenderResult *rr, const int view_id)
|
2012-01-05 17:50:09 +00:00
|
|
|
{
|
2015-04-29 11:18:18 -03:00
|
|
|
RenderView *rv = RE_RenderViewGetById(rr, view_id);
|
2015-04-06 10:40:12 -03:00
|
|
|
|
|
|
|
if (rv->rectf)
|
|
|
|
memset(rv->rectf, 0, 4 * sizeof(float) * rr->rectx * rr->recty);
|
|
|
|
else if (rv->rect32)
|
|
|
|
memset(rv->rect32, 0, 4 * rr->rectx * rr->recty);
|
2012-01-05 17:50:09 +00:00
|
|
|
else
|
2015-04-06 10:40:12 -03:00
|
|
|
rv->rect32 = MEM_callocN(sizeof(int) * rr->rectx * rr->recty, "render_seq rect");
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
|
2012-12-31 13:52:13 +00:00
|
|
|
void render_result_rect_get_pixels(RenderResult *rr, unsigned int *rect, int rectx, int recty,
|
2015-04-06 10:40:12 -03:00
|
|
|
const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings,
|
|
|
|
const int view_id)
|
2012-01-05 17:50:09 +00:00
|
|
|
{
|
2015-04-29 11:26:30 -03:00
|
|
|
RenderView *rv = RE_RenderViewGetById(rr, view_id);
|
|
|
|
|
|
|
|
if (rv->rect32)
|
|
|
|
memcpy(rect, rv->rect32, sizeof(int) * rr->rectx * rr->recty);
|
|
|
|
else if (rv->rectf)
|
|
|
|
IMB_display_buffer_transform_apply((unsigned char *) rect, rv->rectf, rr->rectx, rr->recty, 4,
|
2013-09-05 17:13:43 +00:00
|
|
|
view_settings, display_settings, true);
|
2012-01-05 17:50:09 +00:00
|
|
|
else
|
|
|
|
/* else fill with black */
|
2012-06-13 17:23:44 +00:00
|
|
|
memset(rect, 0, sizeof(int) * rectx * recty);
|
2012-01-05 17:50:09 +00:00
|
|
|
}
|
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
|
|
|
|
/*************************** multiview functions *****************************/
|
|
|
|
|
|
|
|
bool RE_HasFakeLayer(RenderResult *res)
|
|
|
|
{
|
|
|
|
RenderView *rv;
|
|
|
|
|
|
|
|
if (res == NULL)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
rv = res->views.first;
|
|
|
|
if (rv == NULL)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return (rv->rect32 || rv->rectf);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RE_RenderResult_is_stereo(RenderResult *res)
|
|
|
|
{
|
|
|
|
if (! BLI_findstring(&res->views, STEREO_LEFT_NAME, offsetof(RenderView, name)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (! BLI_findstring(&res->views, STEREO_RIGHT_NAME, offsetof(RenderView, name)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-04-29 11:18:18 -03:00
|
|
|
RenderView *RE_RenderViewGetById(RenderResult *res, const int view_id)
|
|
|
|
{
|
|
|
|
RenderView *rv = BLI_findlink(&res->views, view_id);
|
2015-04-29 11:26:30 -03:00
|
|
|
BLI_assert(res->views.first);
|
2015-04-29 11:18:18 -03:00
|
|
|
return rv ? rv : res->views.first;
|
|
|
|
}
|
|
|
|
|
|
|
|
RenderView *RE_RenderViewGetByName(RenderResult *res, const char *viewname)
|
|
|
|
{
|
|
|
|
RenderView *rv = BLI_findstring(&res->views, viewname, offsetof(RenderView, name));
|
2015-04-29 11:26:30 -03:00
|
|
|
BLI_assert(res->views.first);
|
2015-04-29 11:18:18 -03:00
|
|
|
return rv ? rv : res->views.first;
|
|
|
|
}
|
2016-09-16 10:28:41 +02:00
|
|
|
|
|
|
|
static RenderPass *duplicate_render_pass(RenderPass *rpass)
|
|
|
|
{
|
|
|
|
RenderPass *new_rpass = MEM_mallocN(sizeof(RenderPass), "new render pass");
|
|
|
|
*new_rpass = *rpass;
|
|
|
|
new_rpass->next = new_rpass->prev = NULL;
|
|
|
|
if (new_rpass->rect != NULL) {
|
|
|
|
new_rpass->rect = MEM_dupallocN(new_rpass->rect);
|
|
|
|
}
|
|
|
|
return new_rpass;
|
|
|
|
}
|
|
|
|
|
|
|
|
static RenderLayer *duplicate_render_layer(RenderLayer *rl)
|
|
|
|
{
|
|
|
|
RenderLayer *new_rl = MEM_mallocN(sizeof(RenderLayer), "new render layer");
|
|
|
|
*new_rl = *rl;
|
|
|
|
new_rl->next = new_rl->prev = NULL;
|
|
|
|
new_rl->passes.first = new_rl->passes.last = NULL;
|
|
|
|
new_rl->exrhandle = NULL;
|
|
|
|
if (new_rl->acolrect != NULL) {
|
|
|
|
new_rl->acolrect = MEM_dupallocN(new_rl->acolrect);
|
|
|
|
}
|
|
|
|
if (new_rl->scolrect != NULL) {
|
|
|
|
new_rl->scolrect = MEM_dupallocN(new_rl->scolrect);
|
|
|
|
}
|
|
|
|
if (new_rl->display_buffer != NULL) {
|
|
|
|
new_rl->display_buffer = MEM_dupallocN(new_rl->display_buffer);
|
|
|
|
}
|
|
|
|
for (RenderPass *rpass = rl->passes.first; rpass != NULL; rpass = rpass->next) {
|
|
|
|
RenderPass *new_rpass = duplicate_render_pass(rpass);
|
|
|
|
BLI_addtail(&new_rl->passes, new_rpass);
|
|
|
|
}
|
|
|
|
return new_rl;
|
|
|
|
}
|
|
|
|
|
|
|
|
static RenderView *duplicate_render_view(RenderView *rview)
|
|
|
|
{
|
|
|
|
RenderView *new_rview = MEM_mallocN(sizeof(RenderView), "new render view");
|
|
|
|
*new_rview = *rview;
|
|
|
|
if (new_rview->rectf != NULL) {
|
|
|
|
new_rview->rectf = MEM_dupallocN(new_rview->rectf);
|
|
|
|
}
|
|
|
|
if (new_rview->rectf != NULL) {
|
|
|
|
new_rview->rectf = MEM_dupallocN(new_rview->rectf);
|
|
|
|
}
|
|
|
|
if (new_rview->rectz != NULL) {
|
|
|
|
new_rview->rectz = MEM_dupallocN(new_rview->rectz);
|
|
|
|
}
|
|
|
|
if (new_rview->rect32 != NULL) {
|
|
|
|
new_rview->rect32 = MEM_dupallocN(new_rview->rect32);
|
|
|
|
}
|
|
|
|
return new_rview;
|
|
|
|
}
|
|
|
|
|
|
|
|
RenderResult *RE_DuplicateRenderResult(RenderResult *rr)
|
|
|
|
{
|
|
|
|
RenderResult *new_rr = MEM_mallocN(sizeof(RenderResult), "new render result");
|
|
|
|
*new_rr = *rr;
|
|
|
|
new_rr->next = new_rr->prev = NULL;
|
|
|
|
new_rr->layers.first = new_rr->layers.last = NULL;
|
|
|
|
new_rr->views.first = new_rr->views.last = NULL;
|
|
|
|
for (RenderLayer *rl = rr->layers.first; rl != NULL; rl = rl->next) {
|
|
|
|
RenderLayer *new_rl = duplicate_render_layer(rl);
|
|
|
|
BLI_addtail(&new_rr->layers, new_rl);
|
|
|
|
}
|
|
|
|
for (RenderView *rview = rr->views.first; rview != NULL; rview = rview->next) {
|
|
|
|
RenderView *new_rview = duplicate_render_view(rview);
|
|
|
|
BLI_addtail(&new_rr->views, new_rview);
|
|
|
|
}
|
|
|
|
if (new_rr->rect32 != NULL) {
|
|
|
|
new_rr->rect32 = MEM_dupallocN(new_rr->rect32);
|
|
|
|
}
|
|
|
|
if (new_rr->rectf != NULL) {
|
|
|
|
new_rr->rectf = MEM_dupallocN(new_rr->rectf);
|
|
|
|
}
|
|
|
|
if (new_rr->rectz != NULL) {
|
|
|
|
new_rr->rectz = MEM_dupallocN(new_rr->rectz);
|
|
|
|
}
|
|
|
|
new_rr->stamp_data = MEM_dupallocN(new_rr->stamp_data);
|
|
|
|
return new_rr;
|
|
|
|
}
|