diff options
Diffstat (limited to 'source/blender/render')
22 files changed, 1388 insertions, 1134 deletions
diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt index 16cba944e01..effc564fdc9 100644 --- a/source/blender/render/CMakeLists.txt +++ b/source/blender/render/CMakeLists.txt @@ -54,6 +54,7 @@ set(SRC intern/raytrace/rayobject_qbvh.cpp intern/raytrace/rayobject_rtbuild.cpp intern/raytrace/rayobject_vbvh.cpp + intern/source/bake.c intern/source/convertblender.c intern/source/envmap.c intern/source/external_engine.c diff --git a/source/blender/render/extern/include/RE_engine.h b/source/blender/render/extern/include/RE_engine.h index 64135a16f5d..b687acae1f7 100644 --- a/source/blender/render/extern/include/RE_engine.h +++ b/source/blender/render/extern/include/RE_engine.h @@ -62,6 +62,7 @@ struct Scene; #define RE_ENGINE_DO_UPDATE 8 #define RE_ENGINE_RENDERING 16 #define RE_ENGINE_HIGHLIGHT_TILES 32 +#define RE_ENGINE_USED_FOR_VIEWPORT 64 extern ListBase R_engines; @@ -105,6 +106,7 @@ typedef struct RenderEngine { } RenderEngine; RenderEngine *RE_engine_create(RenderEngineType *type); +RenderEngine *RE_engine_create_ex(RenderEngineType *type, int use_for_viewport); void RE_engine_free(RenderEngine *engine); void RE_layer_load_from_file(struct RenderLayer *layer, struct ReportList *reports, const char *filename, int x, int y); diff --git a/source/blender/render/extern/include/RE_render_ext.h b/source/blender/render/extern/include/RE_render_ext.h index 2a9a1becc42..2dfbdd0d6f5 100644 --- a/source/blender/render/extern/include/RE_render_ext.h +++ b/source/blender/render/extern/include/RE_render_ext.h @@ -49,10 +49,11 @@ struct RNode; struct Render; struct MTex; struct ImBuf; +struct ImagePool; struct DerivedMesh; /* particle.c, effect.c, editmesh_modes.c and brush.c, returns 1 if rgb, 0 otherwise */ -int externtex(struct MTex *mtex, const float vec[3], float *tin, float *tr, float *tg, float *tb, float *ta, const int thread); +int externtex(struct MTex *mtex, const float vec[3], float *tin, float *tr, float *tg, float *tb, float *ta, const int thread, struct ImagePool *pool); /* particle.c */ void texture_rgb_blend(float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype); diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h index 10045a8f7e1..d686de21517 100644 --- a/source/blender/render/extern/include/RE_shader_ext.h +++ b/source/blender/render/extern/include/RE_shader_ext.h @@ -184,19 +184,24 @@ typedef struct ShadeInput { } ShadeInput; +typedef struct BakeImBufuserData { + float *displacement_buffer; + char *mask_buffer; +} BakeImBufuserData; /* node shaders... */ struct Tex; struct MTex; struct ImBuf; +struct ImagePool; /* this one uses nodes */ -int multitex_ext(struct Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres); +int multitex_ext(struct Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres, struct ImagePool *pool); /* nodes disabled */ -int multitex_ext_safe(struct Tex *tex, float texvec[3], struct TexResult *texres); +int multitex_ext_safe(struct Tex *tex, float texvec[3], struct TexResult *texres, struct ImagePool *pool); /* only for internal node usage */ int multitex_nodes(struct Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres, - const short thread, short which_output, struct ShadeInput *shi, struct MTex *mtex); + const short thread, short which_output, struct ShadeInput *shi, struct MTex *mtex, struct ImagePool *pool); /* shaded view and bake */ struct Render; @@ -206,6 +211,7 @@ struct Object; int RE_bake_shade_all_selected(struct Render *re, int type, struct Object *actob, short *do_update, float *progress); struct Image *RE_bake_shade_get_image(void); void RE_bake_ibuf_filter(struct ImBuf *ibuf, char *mask, const int filter); +void RE_bake_ibuf_normalize_displacement(struct ImBuf *ibuf, float *displacement, char *mask, float displacement_min, float displacement_max); #define BAKE_RESULT_OK 0 #define BAKE_RESULT_NO_OBJECTS 1 diff --git a/source/blender/render/intern/include/envmap.h b/source/blender/render/intern/include/envmap.h index d0f346f7402..a6c6d46e2e9 100644 --- a/source/blender/render/intern/include/envmap.h +++ b/source/blender/render/intern/include/envmap.h @@ -44,9 +44,10 @@ struct Render; struct TexResult; +struct ImagePool; void make_envmaps(struct Render *re); -int envmaptex(struct Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres); +int envmaptex(struct Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres, struct ImagePool *pool); #endif /* __ENVMAP_H__ */ diff --git a/source/blender/render/intern/include/pixelshading.h b/source/blender/render/intern/include/pixelshading.h index 30d574694b2..faf8c5f54f5 100644 --- a/source/blender/render/intern/include/pixelshading.h +++ b/source/blender/render/intern/include/pixelshading.h @@ -32,6 +32,8 @@ #ifndef __PIXELSHADING_H__ #define __PIXELSHADING_H__ +struct ImagePool; + /** * Render the pixel at (x,y) for object ap. Apply the jitter mask. * Output is given in float collector[4]. The type vector: diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index 3b8cd3c6aa5..deba6d165f2 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -62,6 +62,7 @@ struct RayFace; struct RenderEngine; struct ReportList; struct Main; +struct ImagePool; #define TABLEINITSIZE 1024 @@ -264,6 +265,8 @@ struct Render RenderStats i; struct ReportList *reports; + + struct ImagePool *pool; }; /* ------------------------------------------------------------------------- */ @@ -377,6 +380,7 @@ struct halosort { /* ------------------------------------------------------------------------- */ struct Material; struct MTFace; +struct ImagePool; typedef struct RadFace { float unshot[3], totrad[3]; @@ -409,6 +413,7 @@ typedef struct HaloRen { int pixels; unsigned int lay; struct Material *mat; + struct ImagePool *pool; } HaloRen; /* ------------------------------------------------------------------------- */ diff --git a/source/blender/render/intern/include/texture.h b/source/blender/render/intern/include/texture.h index 4b9fa2d2042..2dc12f39db7 100644 --- a/source/blender/render/intern/include/texture.h +++ b/source/blender/render/intern/include/texture.h @@ -60,6 +60,7 @@ struct TexResult; struct Tex; struct Image; struct ImBuf; +struct ImagePool; /* texture.h */ @@ -76,9 +77,9 @@ void render_realtime_texture(struct ShadeInput *shi, struct Image *ima); /* imagetexture.h */ -int imagewraposa(struct Tex *tex, struct Image *ima, struct ImBuf *ibuf, const float texvec[3], const float dxt[2], const float dyt[2], struct TexResult *texres); -int imagewrap(struct Tex *tex, struct Image *ima, struct ImBuf *ibuf, const float texvec[3], struct TexResult *texres); -void image_sample(struct Image *ima, float fx, float fy, float dx, float dy, float result[4]); +int imagewraposa(struct Tex *tex, struct Image *ima, struct ImBuf *ibuf, const float texvec[3], const float dxt[2], const float dyt[2], struct TexResult *texres, struct ImagePool *pool); +int imagewrap(struct Tex *tex, struct Image *ima, struct ImBuf *ibuf, const float texvec[3], struct TexResult *texres, struct ImagePool *pool); +void image_sample(struct Image *ima, float fx, float fy, float dx, float dy, float result[4], struct ImagePool *pool); #endif /* __TEXTURE_H__ */ diff --git a/source/blender/render/intern/raytrace/rayobject_octree.cpp b/source/blender/render/intern/raytrace/rayobject_octree.cpp index 658ab9dc091..e4fd5a6d41e 100644 --- a/source/blender/render/intern/raytrace/rayobject_octree.cpp +++ b/source/blender/render/intern/raytrace/rayobject_octree.cpp @@ -667,10 +667,12 @@ static void RE_rayobject_octree_done(RayObject *tree) oc->ocface = NULL; MEM_freeN(oc->ro_nodes); oc->ro_nodes = NULL; - + +#if 0 printf("%f %f - %f\n", oc->min[0], oc->max[0], oc->ocfacx); printf("%f %f - %f\n", oc->min[1], oc->max[1], oc->ocfacy); printf("%f %f - %f\n", oc->min[2], oc->max[2], oc->ocfacz); +#endif } static void RE_rayobject_octree_bb(RayObject *tree, float *min, float *max) diff --git a/source/blender/render/intern/raytrace/rayobject_vbvh.cpp b/source/blender/render/intern/raytrace/rayobject_vbvh.cpp index d03bdb74407..3e80deefecd 100644 --- a/source/blender/render/intern/raytrace/rayobject_vbvh.cpp +++ b/source/blender/render/intern/raytrace/rayobject_vbvh.cpp @@ -38,12 +38,12 @@ int tot_hints = 0; #include "MEM_guardedalloc.h" -#include "BKE_global.h" - #include "BLI_math.h" #include "BLI_memarena.h" #include "BLI_utildefines.h" +#include "BKE_global.h" + #include "rayintersection.h" #include "rayobject.h" #include "rayobject_rtbuild.h" diff --git a/source/blender/render/intern/source/bake.c b/source/blender/render/intern/source/bake.c new file mode 100644 index 00000000000..d4451d570a4 --- /dev/null +++ b/source/blender/render/intern/source/bake.c @@ -0,0 +1,1107 @@ +/* + * ***** 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) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributors: 2004/2005/2006 Blender Foundation, full recode + * Contributors: Vertex color baking, Copyright 2011 AutoCRC + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/source/bake.c + * \ingroup render + */ + + +/* system includes */ +#include <stdio.h> +#include <string.h> + +/* External modules: */ +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_blenlib.h" +#include "BLI_threads.h" +#include "BLI_utildefines.h" + +#include "DNA_image_types.h" +#include "DNA_material_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_customdata.h" +#include "BKE_depsgraph.h" +#include "BKE_global.h" +#include "BKE_image.h" +#include "BKE_main.h" +#include "BKE_node.h" +#include "BKE_scene.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" +#include "IMB_colormanagement.h" + +/* local include */ +#include "rayintersection.h" +#include "rayobject.h" +#include "render_types.h" +#include "renderdatabase.h" +#include "shading.h" +#include "zbuf.h" + +#include "PIL_time.h" + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ +/* only to be used here in this file, it's for speed */ +extern struct Render R; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + + +/* ************************* bake ************************ */ + + +typedef struct BakeShade { + ShadeSample ssamp; + ObjectInstanceRen *obi; + VlakRen *vlr; + + ZSpan *zspan; + Image *ima; + ImBuf *ibuf; + + int rectx, recty, quad, type, vdone; + bool ready; + + float dir[3]; + Object *actob; + + /* Output: vertex color or image data. If vcol is not NULL, rect and + * rect_float should be NULL. */ + MPoly *mpoly; + MLoop *mloop; + MLoopCol *vcol; + + unsigned int *rect; + float *rect_float; + + /* displacement buffer used for normalization with unknown maximal distance */ + bool use_displacement_buffer; + float *displacement_buffer; + float displacement_min, displacement_max; + + bool use_mask; + char *rect_mask; /* bake pixel mask */ + + float dxco[3], dyco[3]; + + short *do_update; + + struct ColorSpace *rect_colorspace; +} BakeShade; + +static void bake_set_shade_input(ObjectInstanceRen *obi, VlakRen *vlr, ShadeInput *shi, int quad, int UNUSED(isect), int x, int y, float u, float v) +{ + if (quad) + shade_input_set_triangle_i(shi, obi, vlr, 0, 2, 3); + else + shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2); + + /* cache for shadow */ + shi->samplenr = R.shadowsamplenr[shi->thread]++; + + shi->mask = 0xFFFF; /* all samples */ + + shi->u = -u; + shi->v = -v; + shi->xs = x; + shi->ys = y; + + shade_input_set_uv(shi); + shade_input_set_normals(shi); + + /* no normal flip */ + if (shi->flippednor) + shade_input_flip_normals(shi); + + /* set up view vector to look right at the surface (note that the normal + * is negated in the renderer so it does not need to be done here) */ + shi->view[0] = shi->vn[0]; + shi->view[1] = shi->vn[1]; + shi->view[2] = shi->vn[2]; +} + +static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int UNUSED(quad), int x, int y, float UNUSED(u), float UNUSED(v), float *tvn, float *ttang) +{ + BakeShade *bs = handle; + ShadeSample *ssamp = &bs->ssamp; + ShadeResult shr; + VlakRen *vlr = shi->vlr; + + shade_input_init_material(shi); + + if (bs->type == RE_BAKE_AO) { + ambient_occlusion(shi); + + if (R.r.bake_flag & R_BAKE_NORMALIZE) { + copy_v3_v3(shr.combined, shi->ao); + } + else { + zero_v3(shr.combined); + environment_lighting_apply(shi, &shr); + } + } + else { + if (bs->type == RE_BAKE_SHADOW) /* Why do shadows set the color anyhow?, ignore material color for baking */ + shi->r = shi->g = shi->b = 1.0f; + + shade_input_set_shade_texco(shi); + + /* only do AO for a full bake (and obviously AO bakes) + * AO for light bakes is a leftover and might not be needed */ + if (ELEM3(bs->type, RE_BAKE_ALL, RE_BAKE_AO, RE_BAKE_LIGHT)) + shade_samples_do_AO(ssamp); + + if (shi->mat->nodetree && shi->mat->use_nodes) { + ntreeShaderExecTree(shi->mat->nodetree, shi, &shr); + shi->mat = vlr->mat; /* shi->mat is being set in nodetree */ + } + else + shade_material_loop(shi, &shr); + + if (bs->type == RE_BAKE_NORMALS) { + float nor[3]; + + copy_v3_v3(nor, shi->vn); + + if (R.r.bake_normal_space == R_BAKE_SPACE_CAMERA) { + /* pass */ + } + else if (R.r.bake_normal_space == R_BAKE_SPACE_TANGENT) { + float mat[3][3], imat[3][3]; + + /* bitangent */ + if (tvn && ttang) { + copy_v3_v3(mat[0], ttang); + cross_v3_v3v3(mat[1], tvn, ttang); + mul_v3_fl(mat[1], ttang[3]); + copy_v3_v3(mat[2], tvn); + } + else { + copy_v3_v3(mat[0], shi->nmaptang); + cross_v3_v3v3(mat[1], shi->nmapnorm, shi->nmaptang); + mul_v3_fl(mat[1], shi->nmaptang[3]); + copy_v3_v3(mat[2], shi->nmapnorm); + } + + invert_m3_m3(imat, mat); + mul_m3_v3(imat, nor); + } + else if (R.r.bake_normal_space == R_BAKE_SPACE_OBJECT) + mul_mat3_m4_v3(ob->imat_ren, nor); /* ob->imat_ren includes viewinv! */ + else if (R.r.bake_normal_space == R_BAKE_SPACE_WORLD) + mul_mat3_m4_v3(R.viewinv, nor); + + normalize_v3(nor); /* in case object has scaling */ + + /* The invert of the red channel is to make + * the normal map compliant with the outside world. + * It needs to be done because in Blender + * the normal used in the renderer points inward. It is generated + * this way in calc_vertexnormals(). Should this ever change + * this negate must be removed. */ + shr.combined[0] = (-nor[0]) / 2.0f + 0.5f; + shr.combined[1] = nor[1] / 2.0f + 0.5f; + shr.combined[2] = nor[2] / 2.0f + 0.5f; + } + else if (bs->type == RE_BAKE_TEXTURE) { + copy_v3_v3(shr.combined, &shi->r); + shr.alpha = shi->alpha; + } + else if (bs->type == RE_BAKE_SHADOW) { + copy_v3_v3(shr.combined, shr.shad); + shr.alpha = shi->alpha; + } + else if (bs->type == RE_BAKE_SPEC_COLOR) { + copy_v3_v3(shr.combined, &shi->specr); + shr.alpha = 1.0f; + } + else if (bs->type == RE_BAKE_SPEC_INTENSITY) { + copy_v3_fl(shr.combined, shi->spec); + shr.alpha = 1.0f; + } + else if (bs->type == RE_BAKE_MIRROR_COLOR) { + copy_v3_v3(shr.combined, &shi->mirr); + shr.alpha = 1.0f; + } + else if (bs->type == RE_BAKE_MIRROR_INTENSITY) { + copy_v3_fl(shr.combined, shi->ray_mirror); + shr.alpha = 1.0f; + } + else if (bs->type == RE_BAKE_ALPHA) { + copy_v3_fl(shr.combined, shi->alpha); + shr.alpha = 1.0f; + } + else if (bs->type == RE_BAKE_EMIT) { + copy_v3_fl(shr.combined, shi->emit); + shr.alpha = 1.0f; + } + } + + if (bs->rect_float && !bs->vcol) { + float *col = bs->rect_float + 4 * (bs->rectx * y + x); + copy_v3_v3(col, shr.combined); + if (bs->type == RE_BAKE_ALL || bs->type == RE_BAKE_TEXTURE) { + col[3] = shr.alpha; + } + else { + col[3] = 1.0; + } + } + else { + /* Target is char (LDR). */ + unsigned char col[4]; + + if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE)) { + float rgb[3]; + + copy_v3_v3(rgb, shr.combined); + if (R.scene_color_manage) { + /* Vertex colors have no way to specify color space, so they + * default to sRGB. */ + if (!bs->vcol) + IMB_colormanagement_scene_linear_to_colorspace_v3(rgb, bs->rect_colorspace); + else + linearrgb_to_srgb_v3_v3(rgb, rgb); + } + rgb_float_to_uchar(col, rgb); + } + else { + rgb_float_to_uchar(col, shr.combined); + } + + if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE)) { + col[3] = FTOCHAR(shr.alpha); + } + else { + col[3] = 255; + } + + if (bs->vcol) { + /* Vertex color baking. Vcol has no useful alpha channel (it exists + * but is used only for vertex painting). */ + bs->vcol->r = col[0]; + bs->vcol->g = col[1]; + bs->vcol->b = col[2]; + } + else { + unsigned char *imcol = (unsigned char *)(bs->rect + bs->rectx * y + x); + copy_v4_v4_char((char *)imcol, (char *)col); + } + + } + + if (bs->rect_mask) { + bs->rect_mask[bs->rectx * y + x] = FILTER_MASK_USED; + } +} + +static void bake_displacement(void *handle, ShadeInput *UNUSED(shi), float dist, int x, int y) +{ + BakeShade *bs = handle; + float disp; + + if (R.r.bake_flag & R_BAKE_NORMALIZE) { + if (R.r.bake_maxdist) + disp = (dist + R.r.bake_maxdist) / (R.r.bake_maxdist * 2); /* alter the range from [-bake_maxdist, bake_maxdist] to [0, 1]*/ + else + disp = dist; + } + else { + disp = 0.5f + dist; /* alter the range from [-0.5,0.5] to [0,1]*/ + } + + if (bs->displacement_buffer) { + float *displacement = bs->displacement_buffer + (bs->rectx * y + x); + *displacement = disp; + bs->displacement_min = min_ff(bs->displacement_min, disp); + bs->displacement_max = max_ff(bs->displacement_max, disp); + } + + if (bs->rect_float && !bs->vcol) { + float *col = bs->rect_float + 4 * (bs->rectx * y + x); + col[0] = col[1] = col[2] = disp; + col[3] = 1.0f; + } + else { + /* Target is char (LDR). */ + unsigned char col[4]; + col[0] = col[1] = col[2] = FTOCHAR(disp); + col[3] = 255; + + if (bs->vcol) { + /* Vertex color baking. Vcol has no useful alpha channel (it exists + * but is used only for vertex painting). */ + bs->vcol->r = col[0]; + bs->vcol->g = col[1]; + bs->vcol->b = col[2]; + } + else { + char *imcol = (char *)(bs->rect + bs->rectx * y + x); + copy_v4_v4_char((char *)imcol, (char *)col); + } + } + if (bs->rect_mask) { + bs->rect_mask[bs->rectx * y + x] = FILTER_MASK_USED; + } +} + +static int bake_intersect_tree(RayObject *raytree, Isect *isect, float *start, float *dir, float sign, float *hitco, float *dist) +{ + float maxdist; + int hit; + + /* might be useful to make a user setting for maxsize*/ + if (R.r.bake_maxdist > 0.0f) + maxdist = R.r.bake_maxdist; + else + maxdist = RE_RAYTRACE_MAXDIST + R.r.bake_biasdist; + + /* 'dir' is always normalized */ + madd_v3_v3v3fl(isect->start, start, dir, -R.r.bake_biasdist); + + mul_v3_v3fl(isect->dir, dir, sign); + + isect->dist = maxdist; + + hit = RE_rayobject_raycast(raytree, isect); + if (hit) { + madd_v3_v3v3fl(hitco, isect->start, isect->dir, isect->dist); + + *dist = isect->dist; + } + + return hit; +} + +static void bake_set_vlr_dxyco(BakeShade *bs, float *uv1, float *uv2, float *uv3) +{ + VlakRen *vlr = bs->vlr; + float A, d1, d2, d3, *v1, *v2, *v3; + + if (bs->quad) { + v1 = vlr->v1->co; + v2 = vlr->v3->co; + v3 = vlr->v4->co; + } + else { + v1 = vlr->v1->co; + v2 = vlr->v2->co; + v3 = vlr->v3->co; + } + + /* formula derived from barycentric coordinates: + * (uvArea1*v1 + uvArea2*v2 + uvArea3*v3)/uvArea + * then taking u and v partial derivatives to get dxco and dyco */ + A = (uv2[0] - uv1[0]) * (uv3[1] - uv1[1]) - (uv3[0] - uv1[0]) * (uv2[1] - uv1[1]); + + if (fabsf(A) > FLT_EPSILON) { + A = 0.5f / A; + + d1 = uv2[1] - uv3[1]; + d2 = uv3[1] - uv1[1]; + d3 = uv1[1] - uv2[1]; + bs->dxco[0] = (v1[0] * d1 + v2[0] * d2 + v3[0] * d3) * A; + bs->dxco[1] = (v1[1] * d1 + v2[1] * d2 + v3[1] * d3) * A; + bs->dxco[2] = (v1[2] * d1 + v2[2] * d2 + v3[2] * d3) * A; + + d1 = uv3[0] - uv2[0]; + d2 = uv1[0] - uv3[0]; + d3 = uv2[0] - uv1[0]; + bs->dyco[0] = (v1[0] * d1 + v2[0] * d2 + v3[0] * d3) * A; + bs->dyco[1] = (v1[1] * d1 + v2[1] * d2 + v3[1] * d3) * A; + bs->dyco[2] = (v1[2] * d1 + v2[2] * d2 + v3[2] * d3) * A; + } + else { + bs->dxco[0] = bs->dxco[1] = bs->dxco[2] = 0.0f; + bs->dyco[0] = bs->dyco[1] = bs->dyco[2] = 0.0f; + } + + if (bs->obi->flag & R_TRANSFORMED) { + mul_m3_v3(bs->obi->nmat, bs->dxco); + mul_m3_v3(bs->obi->nmat, bs->dyco); + } +} + +static void do_bake_shade(void *handle, int x, int y, float u, float v) +{ + BakeShade *bs = handle; + VlakRen *vlr = bs->vlr; + ObjectInstanceRen *obi = bs->obi; + Object *ob = obi->obr->ob; + float l, *v1, *v2, *v3, tvn[3], ttang[4]; + int quad; + ShadeSample *ssamp = &bs->ssamp; + ShadeInput *shi = ssamp->shi; + + /* fast threadsafe break test */ + if (R.test_break(R.tbh)) + return; + + /* setup render coordinates */ + if (bs->quad) { + v1 = vlr->v1->co; + v2 = vlr->v3->co; + v3 = vlr->v4->co; + } + else { + v1 = vlr->v1->co; + v2 = vlr->v2->co; + v3 = vlr->v3->co; + } + + l = 1.0f - u - v; + + /* shrink barycentric coordinates inwards slightly to avoid some issues + * where baking selected to active might just miss the other face at the + * near the edge of a face */ + if (bs->actob) { + const float eps = 1.0f - 1e-4f; + float invsum; + + u = (u - 0.5f) * eps + 0.5f; + v = (v - 0.5f) * eps + 0.5f; + l = (l - 0.5f) * eps + 0.5f; + + invsum = 1.0f / (u + v + l); + + u *= invsum; + v *= invsum; + l *= invsum; + } + + /* renderco */ + shi->co[0] = l * v3[0] + u * v1[0] + v * v2[0]; + shi->co[1] = l * v3[1] + u * v1[1] + v * v2[1]; + shi->co[2] = l * v3[2] + u * v1[2] + v * v2[2]; + + /* avoid self shadow with vertex bake from adjacent faces [#33729] */ + if ((bs->vcol != NULL) && (bs->actob == NULL)) { + madd_v3_v3fl(shi->co, vlr->n, 0.0001f); + } + + if (obi->flag & R_TRANSFORMED) + mul_m4_v3(obi->mat, shi->co); + + copy_v3_v3(shi->dxco, bs->dxco); + copy_v3_v3(shi->dyco, bs->dyco); + + quad = bs->quad; + bake_set_shade_input(obi, vlr, shi, quad, 0, x, y, u, v); + + if (bs->type == RE_BAKE_NORMALS && R.r.bake_normal_space == R_BAKE_SPACE_TANGENT) { + shade_input_set_shade_texco(shi); + copy_v3_v3(tvn, shi->nmapnorm); + copy_v4_v4(ttang, shi->nmaptang); + } + + /* if we are doing selected to active baking, find point on other face */ + if (bs->actob) { + Isect isec, minisec; + float co[3], minco[3], dist, mindist = 0.0f; + int hit, sign, dir = 1; + + /* intersect with ray going forward and backward*/ + hit = 0; + memset(&minisec, 0, sizeof(minisec)); + minco[0] = minco[1] = minco[2] = 0.0f; + + copy_v3_v3(bs->dir, shi->vn); + + for (sign = -1; sign <= 1; sign += 2) { + memset(&isec, 0, sizeof(isec)); + isec.mode = RE_RAY_MIRROR; + + isec.orig.ob = obi; + isec.orig.face = vlr; + isec.userdata = bs->actob; + isec.check = RE_CHECK_VLR_BAKE; + isec.skip = RE_SKIP_VLR_NEIGHBOUR; + + if (bake_intersect_tree(R.raytree, &isec, shi->co, shi->vn, sign, co, &dist)) { + if (!hit || len_squared_v3v3(shi->co, co) < len_squared_v3v3(shi->co, minco)) { + minisec = isec; + mindist = dist; + copy_v3_v3(minco, co); + hit = 1; + dir = sign; + } + } + } + + if (bs->type == RE_BAKE_DISPLACEMENT) { + if (hit) + bake_displacement(handle, shi, (dir == -1) ? mindist : -mindist, x, y); + else + bake_displacement(handle, shi, 0.0f, x, y); + return; + } + + /* if hit, we shade from the new point, otherwise from point one starting face */ + if (hit) { + obi = (ObjectInstanceRen *)minisec.hit.ob; + vlr = (VlakRen *)minisec.hit.face; + quad = (minisec.isect == 2); + copy_v3_v3(shi->co, minco); + + u = -minisec.u; + v = -minisec.v; + bake_set_shade_input(obi, vlr, shi, quad, 1, x, y, u, v); + } + } + + if (bs->type == RE_BAKE_NORMALS && R.r.bake_normal_space == R_BAKE_SPACE_TANGENT) + bake_shade(handle, ob, shi, quad, x, y, u, v, tvn, ttang); + else + bake_shade(handle, ob, shi, quad, x, y, u, v, 0, 0); +} + +static int get_next_bake_face(BakeShade *bs) +{ + ObjectRen *obr; + VlakRen *vlr; + MTFace *tface; + static int v = 0, vdone = false; + static ObjectInstanceRen *obi = NULL; + + if (bs == NULL) { + vlr = NULL; + v = vdone = false; + obi = R.instancetable.first; + return 0; + } + + BLI_lock_thread(LOCK_CUSTOM1); + + for (; obi; obi = obi->next, v = 0) { + obr = obi->obr; + + for (; v < obr->totvlak; v++) { + vlr = RE_findOrAddVlak(obr, v); + + if ((bs->actob && bs->actob == obr->ob) || (!bs->actob && (obr->ob->flag & SELECT))) { + if (R.r.bake_flag & R_BAKE_VCOL) { + /* Gather face data for vertex color bake */ + Mesh *me; + int *origindex, vcollayer; + CustomDataLayer *cdl; + + if (obr->ob->type != OB_MESH) + continue; + me = obr->ob->data; + + origindex = RE_vlakren_get_origindex(obr, vlr, 0); + if (origindex == NULL) + continue; + if (*origindex >= me->totpoly) { + /* Small hack for Array modifier, which gives false + original indices - z0r */ + continue; + } +#if 0 + /* Only shade selected faces. */ + if ((me->mface[*origindex].flag & ME_FACE_SEL) == 0) + continue; +#endif + + vcollayer = CustomData_get_render_layer_index(&me->ldata, CD_MLOOPCOL); + if (vcollayer == -1) + continue; + + cdl = &me->ldata.layers[vcollayer]; + bs->mpoly = me->mpoly + *origindex; + bs->vcol = ((MLoopCol *)cdl->data) + bs->mpoly->loopstart; + bs->mloop = me->mloop + bs->mpoly->loopstart; + + /* Tag mesh for reevaluation. */ + DAG_id_tag_update(&me->id, 0); + } + else { + Image *ima = NULL; + ImBuf *ibuf = NULL; + const float vec_alpha[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + const float vec_solid[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + + tface = RE_vlakren_get_tface(obr, vlr, obr->bakemtface, NULL, 0); + + if (!tface || !tface->tpage) + continue; + + ima = tface->tpage; + ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + + if (ibuf == NULL) + continue; + + if (ibuf->rect == NULL && ibuf->rect_float == NULL) { + BKE_image_release_ibuf(ima, ibuf, NULL); + continue; + } + + if (ibuf->rect_float && !(ibuf->channels == 0 || ibuf->channels == 4)) { + BKE_image_release_ibuf(ima, ibuf, NULL); + continue; + } + + if (ima->flag & IMA_USED_FOR_RENDER) { + ima->id.flag &= ~LIB_DOIT; + BKE_image_release_ibuf(ima, ibuf, NULL); + continue; + } + + /* find the image for the first time? */ + if (ima->id.flag & LIB_DOIT) { + ima->id.flag &= ~LIB_DOIT; + + /* we either fill in float or char, this ensures things go fine */ + if (ibuf->rect_float) + imb_freerectImBuf(ibuf); + /* clear image */ + if (R.r.bake_flag & R_BAKE_CLEAR) + IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? vec_alpha : vec_solid); + + /* might be read by UI to set active image for display */ + R.bakebuf = ima; + } + + /* Tag image for redraw. */ + ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; + BKE_image_release_ibuf(ima, ibuf, NULL); + } + + bs->obi = obi; + bs->vlr = vlr; + bs->vdone++; /* only for error message if nothing was rendered */ + v++; + BLI_unlock_thread(LOCK_CUSTOM1); + return 1; + } + } + } + + BLI_unlock_thread(LOCK_CUSTOM1); + return 0; +} + +static void bake_single_vertex(BakeShade *bs, VertRen *vert, float u, float v) +{ + int *origindex, i; + MLoopCol *basevcol; + MLoop *mloop; + + origindex = RE_vertren_get_origindex(bs->obi->obr, vert, 0); + if (!origindex || *origindex == ORIGINDEX_NONE) + return; + + /* Search for matching vertex index and apply shading. */ + for (i = 0; i < bs->mpoly->totloop; i++) { + mloop = bs->mloop + i; + if (mloop->v != *origindex) + continue; + basevcol = bs->vcol; + bs->vcol = basevcol + i; + do_bake_shade(bs, 0, 0, u, v); + bs->vcol = basevcol; + break; + } +} + +/* Bake all vertices of a face. Actually, this still works on a face-by-face + basis, and each vertex on each face is shaded. Vertex colors are a property + of loops, not vertices. */ +static void shade_verts(BakeShade *bs) +{ + VlakRen *vlr = bs->vlr; + + /* Disable baking to image; write to vcol instead. vcol pointer is set in + * bake_single_vertex. */ + bs->ima = NULL; + bs->rect = NULL; + bs->rect_float = NULL; + bs->displacement_buffer = NULL; + bs->displacement_min = FLT_MAX; + bs->displacement_max = -FLT_MAX; + + bs->quad = 0; + + /* No anti-aliasing for vertices. */ + zero_v3(bs->dxco); + zero_v3(bs->dyco); + + /* Shade each vertex of the face. u and v are barycentric coordinates; since + we're only interested in vertices, these will be 0 or 1. */ + if ((vlr->flag & R_FACE_SPLIT) == 0) { + /* Processing triangle face, whole quad, or first half of split quad. */ + + bake_single_vertex(bs, bs->vlr->v1, 1.0f, 0.0f); + bake_single_vertex(bs, bs->vlr->v2, 0.0f, 1.0f); + bake_single_vertex(bs, bs->vlr->v3, 0.0f, 0.0f); + + if (vlr->v4) { + bs->quad = 1; + bake_single_vertex(bs, bs->vlr->v4, 0.0f, 0.0f); + } + } + else { + /* Processing second half of split quad. Only one vertex to go. */ + if (vlr->flag & R_DIVIDE_24) { + bake_single_vertex(bs, bs->vlr->v2, 0.0f, 1.0f); + } + else { + bake_single_vertex(bs, bs->vlr->v3, 0.0f, 0.0f); + } + } +} + +/* already have tested for tface and ima and zspan */ +static void shade_tface(BakeShade *bs) +{ + VlakRen *vlr = bs->vlr; + ObjectInstanceRen *obi = bs->obi; + ObjectRen *obr = obi->obr; + MTFace *tface = RE_vlakren_get_tface(obr, vlr, obr->bakemtface, NULL, 0); + Image *ima = tface->tpage; + float vec[4][2]; + int a, i1, i2, i3; + + /* check valid zspan */ + if (ima != bs->ima) { + BKE_image_release_ibuf(bs->ima, bs->ibuf, NULL); + + bs->ima = ima; + bs->ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + /* note, these calls only free/fill contents of zspan struct, not zspan itself */ + zbuf_free_span(bs->zspan); + zbuf_alloc_span(bs->zspan, bs->ibuf->x, bs->ibuf->y, R.clipcrop); + } + + bs->rectx = bs->ibuf->x; + bs->recty = bs->ibuf->y; + bs->rect = bs->ibuf->rect; + bs->rect_colorspace = bs->ibuf->rect_colorspace; + bs->rect_float = bs->ibuf->rect_float; + bs->vcol = NULL; + bs->quad = 0; + bs->rect_mask = NULL; + bs->displacement_buffer = NULL; + + if (bs->use_mask || bs->use_displacement_buffer) { + BakeImBufuserData *userdata = bs->ibuf->userdata; + if (userdata == NULL) { + BLI_lock_thread(LOCK_CUSTOM1); + userdata = bs->ibuf->userdata; + if (userdata == NULL) /* since the thread was locked, its possible another thread alloced the value */ + userdata = MEM_callocN(sizeof(BakeImBufuserData), "BakeMask"); + + if (bs->use_mask) + userdata->mask_buffer = MEM_callocN(sizeof(char) * bs->rectx * bs->recty, "BakeMask"); + + if (bs->use_displacement_buffer) + userdata->displacement_buffer = MEM_callocN(sizeof(float) * bs->rectx * bs->recty, "BakeDisp"); + + bs->ibuf->userdata = userdata; + + BLI_unlock_thread(LOCK_CUSTOM1); + } + + bs->rect_mask = userdata->mask_buffer; + bs->displacement_buffer = userdata->displacement_buffer; + } + + /* get pixel level vertex coordinates */ + for (a = 0; a < 4; a++) { + /* Note, workaround for pixel aligned UVs which are common and can screw up our intersection tests + * where a pixel gets in between 2 faces or the middle of a quad, + * camera aligned quads also have this problem but they are less common. + * Add a small offset to the UVs, fixes bug #18685 - Campbell */ + vec[a][0] = tface->uv[a][0] * (float)bs->rectx - (0.5f + 0.001f); + vec[a][1] = tface->uv[a][1] * (float)bs->recty - (0.5f + 0.002f); + } + + /* UV indices have to be corrected for possible quad->tria splits */ + i1 = 0; i2 = 1; i3 = 2; + vlr_set_uv_indices(vlr, &i1, &i2, &i3); + bake_set_vlr_dxyco(bs, vec[i1], vec[i2], vec[i3]); + zspan_scanconvert(bs->zspan, bs, vec[i1], vec[i2], vec[i3], do_bake_shade); + + if (vlr->v4) { + bs->quad = 1; + bake_set_vlr_dxyco(bs, vec[0], vec[2], vec[3]); + zspan_scanconvert(bs->zspan, bs, vec[0], vec[2], vec[3], do_bake_shade); + } +} + +static void *do_bake_thread(void *bs_v) +{ + BakeShade *bs = bs_v; + + while (get_next_bake_face(bs)) { + if (R.r.bake_flag & R_BAKE_VCOL) { + shade_verts(bs); + } + else { + shade_tface(bs); + } + + /* fast threadsafe break test */ + if (R.test_break(R.tbh)) + break; + + /* access is not threadsafe but since its just true/false probably ok + * only used for interactive baking */ + if (bs->do_update) { + *bs->do_update = true; + } + } + bs->ready = true; + + BKE_image_release_ibuf(bs->ima, bs->ibuf, NULL); + + return NULL; +} + +void RE_bake_ibuf_filter(ImBuf *ibuf, char *mask, const int filter) +{ + /* must check before filtering */ + const short is_new_alpha = (ibuf->planes != R_IMF_PLANES_RGBA) && BKE_imbuf_alpha_test(ibuf); + + /* Margin */ + if (filter) { + IMB_filter_extend(ibuf, mask, filter); + } + + /* if the bake results in new alpha then change the image setting */ + if (is_new_alpha) { + ibuf->planes = R_IMF_PLANES_RGBA; + } + else { + if (filter && ibuf->planes != R_IMF_PLANES_RGBA) { + /* clear alpha added by filtering */ + IMB_rectfill_alpha(ibuf, 1.0f); + } + } +} + +void RE_bake_ibuf_normalize_displacement(ImBuf *ibuf, float *displacement, char *mask, float displacement_min, float displacement_max) +{ + int i; + float *current_displacement = displacement; + char *current_mask = mask; + float max_distance; + + max_distance = max_ff(fabsf(displacement_min), fabsf(displacement_max)); + + for (i = 0; i < ibuf->x * ibuf->y; i++) { + if (*current_mask == FILTER_MASK_USED) { + float normalized_displacement; + + if (max_distance > 1e-5f) + normalized_displacement = (*current_displacement + max_distance) / (max_distance * 2); + else + normalized_displacement = 0.5f; + + if (ibuf->rect_float) { + /* currently baking happens to RGBA only */ + float *fp = ibuf->rect_float + i * 4; + fp[0] = fp[1] = fp[2] = normalized_displacement; + fp[3] = 1.0f; + } + + if (ibuf->rect) { + unsigned char *cp = (unsigned char *) (ibuf->rect + i); + cp[0] = cp[1] = cp[2] = FTOCHAR(normalized_displacement); + cp[3] = 255; + } + } + + current_displacement++; + current_mask++; + } +} + +/* using object selection tags, the faces with UV maps get baked */ +/* render should have been setup */ +/* returns 0 if nothing was handled */ +int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_update, float *progress) +{ + BakeShade *handles; + ListBase threads; + Image *ima; + int a, vdone = false, result = BAKE_RESULT_OK; + bool use_mask = false; + bool use_displacement_buffer = false; + + re->scene_color_manage = BKE_scene_check_color_management_enabled(re->scene); + + /* initialize render global */ + R = *re; + R.bakebuf = NULL; + + /* initialize static vars */ + get_next_bake_face(NULL); + + /* do we need a mask? */ + if (re->r.bake_filter) + use_mask = true; + + /* do we need buffer to store displacements */ + if (type == RE_BAKE_DISPLACEMENT) { + if ((R.r.bake_flag & R_BAKE_NORMALIZE) && R.r.bake_maxdist == 0.0f) { + use_displacement_buffer = true; + use_mask = true; + } + } + + /* baker uses this flag to detect if image was initialized */ + if ((R.r.bake_flag & R_BAKE_VCOL) == 0) { + for (ima = G.main->image.first; ima; ima = ima->id.next) { + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + ima->id.flag |= LIB_DOIT; + ima->flag &= ~IMA_USED_FOR_RENDER; + if (ibuf) { + ibuf->userdata = NULL; /* use for masking if needed */ + } + BKE_image_release_ibuf(ima, ibuf, NULL); + } + } + + BLI_init_threads(&threads, do_bake_thread, re->r.threads); + + handles = MEM_callocN(sizeof(BakeShade) * re->r.threads, "BakeShade"); + + /* get the threads running */ + for (a = 0; a < re->r.threads; a++) { + /* set defaults in handles */ + handles[a].ssamp.shi[0].lay = re->lay; + + if (type == RE_BAKE_SHADOW) { + handles[a].ssamp.shi[0].passflag = SCE_PASS_SHADOW; + } + else { + handles[a].ssamp.shi[0].passflag = SCE_PASS_COMBINED; + } + handles[a].ssamp.shi[0].combinedflag = ~(SCE_PASS_SPEC); + handles[a].ssamp.shi[0].thread = a; + handles[a].ssamp.tot = 1; + + handles[a].type = type; + handles[a].actob = actob; + if (R.r.bake_flag & R_BAKE_VCOL) + handles[a].zspan = NULL; + else + handles[a].zspan = MEM_callocN(sizeof(ZSpan), "zspan for bake"); + + handles[a].use_mask = use_mask; + handles[a].use_displacement_buffer = use_displacement_buffer; + + handles[a].do_update = do_update; /* use to tell the view to update */ + + handles[a].displacement_min = FLT_MAX; + handles[a].displacement_max = -FLT_MAX; + + BLI_insert_thread(&threads, &handles[a]); + } + + /* wait for everything to be done */ + a = 0; + while (a != re->r.threads) { + PIL_sleep_ms(50); + + /* calculate progress */ + for (vdone = false, a = 0; a < re->r.threads; a++) + vdone += handles[a].vdone; + if (progress) + *progress = (float)(vdone / (float)re->totvlak); + + for (a = 0; a < re->r.threads; a++) { + if (handles[a].ready == false) { + break; + } + } + } + + /* filter and refresh images */ + if ((R.r.bake_flag & R_BAKE_VCOL) == 0) { + float displacement_min = FLT_MAX, displacement_max = -FLT_MAX; + + if (use_displacement_buffer) { + for (a = 0; a < re->r.threads; a++) { + displacement_min = min_ff(displacement_min, handles[a].displacement_min); + displacement_max = max_ff(displacement_max, handles[a].displacement_max); + } + } + + for (ima = G.main->image.first; ima; ima = ima->id.next) { + if ((ima->id.flag & LIB_DOIT) == 0) { + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + BakeImBufuserData *userdata; + + if (ima->flag & IMA_USED_FOR_RENDER) + result = BAKE_RESULT_FEEDBACK_LOOP; + + if (!ibuf) + continue; + + userdata = (BakeImBufuserData *) ibuf->userdata; + RE_bake_ibuf_filter(ibuf, userdata->mask_buffer, re->r.bake_filter); + + if (use_displacement_buffer) { + RE_bake_ibuf_normalize_displacement(ibuf, userdata->displacement_buffer, userdata->mask_buffer, + displacement_min, displacement_max); + } + + ibuf->userflags |= IB_BITMAPDIRTY; + BKE_image_release_ibuf(ima, ibuf, NULL); + } + } + + /* calculate return value */ + for (a = 0; a < re->r.threads; a++) { + zbuf_free_span(handles[a].zspan); + MEM_freeN(handles[a].zspan); + } + } + + MEM_freeN(handles); + + BLI_end_threads(&threads); + + if (vdone == 0) { + result = BAKE_RESULT_NO_OBJECTS; + } + + return result; +} + +struct Image *RE_bake_shade_get_image(void) +{ + return R.bakebuf; +} + diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 74aab678ea8..9e9dff63c04 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -153,6 +153,7 @@ static HaloRen *initstar(Render *re, ObjectRen *obr, const float vec[3], float h har->hasize= hasize; har->zd= 0.0; + har->pool = re->pool; return har; } @@ -4853,7 +4854,7 @@ static int allow_render_dupli_instance(Render *UNUSED(re), DupliObject *dob, Obj if (totmaterial) { for (a= 0; a<*totmaterial; a++) { - ma= give_current_material(obd, a); + ma= give_current_material(obd, a + 1); if (ma && (ma->material_type == MA_TYPE_HALO)) return 0; } @@ -5165,8 +5166,8 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l * following calls don't depend on 'RE_SetCamera' */ RE_SetCamera(re, camera); - normalize_m4(camera->obmat); - invert_m4_m4(mat, camera->obmat); + normalize_m4_m4(mat, camera->obmat); + invert_m4(mat); RE_SetView(re, mat); camera->recalc= OB_RECALC_OB; /* force correct matrix for scaled cameras */ } @@ -5315,8 +5316,8 @@ static void database_fromscene_vectors(Render *re, Scene *scene, unsigned int la /* if no camera, viewmat should have been set! */ if (camera) { - normalize_m4(camera->obmat); - invert_m4_m4(mat, camera->obmat); + normalize_m4_m4(mat, camera->obmat); + invert_m4(mat); RE_SetView(re, mat); } @@ -5855,8 +5856,8 @@ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay, /* if no camera, set unit */ if (camera) { - normalize_m4(camera->obmat); - invert_m4_m4(mat, camera->obmat); + normalize_m4_m4(mat, camera->obmat); + invert_m4(mat); RE_SetView(re, mat); } else { diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c index be8b7f6c357..9adae6f49ba 100644 --- a/source/blender/render/intern/source/envmap.c +++ b/source/blender/render/intern/source/envmap.c @@ -668,7 +668,7 @@ static void set_dxtdyt(float r_dxt[3], float r_dyt[3], const float dxt[3], const /* ------------------------------------------------------------------------- */ -int envmaptex(Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres) +int envmaptex(Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres, struct ImagePool *pool) { extern Render R; /* only in this call */ /* texvec should be the already reflected normal */ @@ -687,12 +687,12 @@ int envmaptex(Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int o env->ima = tex->ima; if (env->ima && env->ima->ok) { if (env->cube[1] == NULL) { - ImBuf *ibuf_ima = BKE_image_acquire_ibuf(env->ima, NULL, NULL); + ImBuf *ibuf_ima = BKE_image_pool_acquire_ibuf(env->ima, NULL, pool); if (ibuf_ima) envmap_split_ima(env, ibuf_ima); else env->ok = 0; - BKE_image_release_ibuf(env->ima, ibuf_ima, NULL); + BKE_image_pool_release_ibuf(env->ima, ibuf_ima, pool); } } } @@ -720,7 +720,7 @@ int envmaptex(Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int o mul_mat3_m4_v3(R.viewinv, dyt); } set_dxtdyt(dxts, dyts, dxt, dyt, face); - imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, texres); + imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, texres, pool); /* edges? */ @@ -737,7 +737,7 @@ int envmaptex(Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int o if (face != face1) { ibuf = env->cube[face1]; set_dxtdyt(dxts, dyts, dxt, dyt, face1); - imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, &texr1); + imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, &texr1, pool); } else texr1.tr = texr1.tg = texr1.tb = texr1.ta = 0.0; @@ -750,7 +750,7 @@ int envmaptex(Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int o if (face != face1) { ibuf = env->cube[face1]; set_dxtdyt(dxts, dyts, dxt, dyt, face1); - imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, &texr2); + imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, &texr2, pool); } else texr2.tr = texr2.tg = texr2.tb = texr2.ta = 0.0; @@ -766,7 +766,7 @@ int envmaptex(Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int o } } else { - imagewrap(tex, NULL, ibuf, sco, texres); + imagewrap(tex, NULL, ibuf, sco, texres, pool); } return 1; diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c index 296c8b6eba8..22a49bcbbc3 100644 --- a/source/blender/render/intern/source/external_engine.c +++ b/source/blender/render/intern/source/external_engine.c @@ -1,4 +1,5 @@ /* + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or @@ -128,9 +129,20 @@ int RE_engine_is_external(Render *re) RenderEngine *RE_engine_create(RenderEngineType *type) { + return RE_engine_create_ex(type, FALSE); +} + +RenderEngine *RE_engine_create_ex(RenderEngineType *type, int use_for_viewport) +{ RenderEngine *engine = MEM_callocN(sizeof(RenderEngine), "RenderEngine"); engine->type = type; + if (use_for_viewport) { + engine->flag |= RE_ENGINE_USED_FOR_VIEWPORT; + + BLI_begin_threaded_malloc(); + } + return engine; } @@ -142,6 +154,10 @@ void RE_engine_free(RenderEngine *engine) } #endif + if (engine->flag & RE_ENGINE_USED_FOR_VIEWPORT) { + BLI_end_threaded_malloc(); + } + if (engine->text) MEM_freeN(engine->text); diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c index 4aaa6247478..0a427d57ebc 100644 --- a/source/blender/render/intern/source/imagetexture.c +++ b/source/blender/render/intern/source/imagetexture.c @@ -110,7 +110,7 @@ static void ibuf_get_color(float col[4], struct ImBuf *ibuf, int x, int y) } } -int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResult *texres) +int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResult *texres, struct ImagePool *pool) { float fx, fy, val1, val2, val3; int x, y, retval; @@ -130,13 +130,13 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul if (ima->ibufs.first==NULL && (R.r.scemode & R_NO_IMAGE_LOAD)) return retval; - ibuf= BKE_image_acquire_ibuf(ima, &tex->iuser, NULL); + ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, pool); ima->flag|= IMA_USED_FOR_RENDER; } if (ibuf==NULL || (ibuf->rect==NULL && ibuf->rect_float==NULL)) { if (ima) - BKE_image_release_ibuf(ima, ibuf, NULL); + BKE_image_pool_release_ibuf(ima, ibuf, pool); return retval; } @@ -164,14 +164,14 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul } else { if (ima) - BKE_image_release_ibuf(ima, ibuf, NULL); + BKE_image_pool_release_ibuf(ima, ibuf, pool); return retval; } } if ( (tex->flag & TEX_CHECKER_EVEN)==0) { if ((xs+ys) & 1) { if (ima) - BKE_image_release_ibuf(ima, ibuf, NULL); + BKE_image_pool_release_ibuf(ima, ibuf, pool); return retval; } } @@ -188,14 +188,14 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul if (tex->extend == TEX_CLIPCUBE) { if (x<0 || y<0 || x>=ibuf->x || y>=ibuf->y || texvec[2]<-1.0f || texvec[2]>1.0f) { if (ima) - BKE_image_release_ibuf(ima, ibuf, NULL); + BKE_image_pool_release_ibuf(ima, ibuf, pool); return retval; } } else if ( tex->extend==TEX_CLIP || tex->extend==TEX_CHECKER) { if (x<0 || y<0 || x>=ibuf->x || y>=ibuf->y) { if (ima) - BKE_image_release_ibuf(ima, ibuf, NULL); + BKE_image_pool_release_ibuf(ima, ibuf, pool); return retval; } } @@ -302,10 +302,10 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul texres->tg*= fx; texres->tb*= fx; } - + if (ima) - BKE_image_release_ibuf(ima, ibuf, NULL); - + BKE_image_pool_release_ibuf(ima, ibuf, pool); + BRICONTRGB; return retval; @@ -1045,7 +1045,7 @@ static void image_mipmap_test(Tex *tex, ImBuf *ibuf) } -static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], float dxt[2], float dyt[2], TexResult *texres) +static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], float dxt[2], float dyt[2], TexResult *texres, struct ImagePool *pool) { TexResult texr; float fx, fy, minx, maxx, miny, maxy; @@ -1076,12 +1076,12 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex if (ima) { /* hack for icon render */ if ((ima->ibufs.first == NULL) && (R.r.scemode & R_NO_IMAGE_LOAD)) return retval; - ibuf = BKE_image_acquire_ibuf(ima, &tex->iuser, NULL); + ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, pool); } if ((ibuf == NULL) || ((ibuf->rect == NULL) && (ibuf->rect_float == NULL))) { if (ima) - BKE_image_release_ibuf(ima, ibuf, NULL); + BKE_image_pool_release_ibuf(ima, ibuf, pool); return retval; } @@ -1199,12 +1199,12 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex else { if ((tex->flag & TEX_CHECKER_ODD) == 0 && ((xs + ys) & 1) == 0) { if (ima) - BKE_image_release_ibuf(ima, ibuf, NULL); + BKE_image_pool_release_ibuf(ima, ibuf, pool); return retval; } if ((tex->flag & TEX_CHECKER_EVEN) == 0 && (xs + ys) & 1) { if (ima) - BKE_image_release_ibuf(ima, ibuf, NULL); + BKE_image_pool_release_ibuf(ima, ibuf, pool); return retval; } fx -= xs; @@ -1224,14 +1224,14 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex if (tex->extend == TEX_CLIPCUBE) { if ((fx + minx) < 0.f || (fy + miny) < 0.f || (fx - minx) > 1.f || (fy - miny) > 1.f || texvec[2] < -1.f || texvec[2] > 1.f) { if (ima) - BKE_image_release_ibuf(ima, ibuf, NULL); + BKE_image_pool_release_ibuf(ima, ibuf, pool); return retval; } } else if (tex->extend == TEX_CLIP || tex->extend == TEX_CHECKER) { if ((fx + minx) < 0.f || (fy + miny) < 0.f || (fx - minx) > 1.f || (fy - miny) > 1.f) { if (ima) - BKE_image_release_ibuf(ima, ibuf, NULL); + BKE_image_pool_release_ibuf(ima, ibuf, pool); return retval; } } @@ -1455,7 +1455,7 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex } if (ima) - BKE_image_release_ibuf(ima, ibuf, NULL); + BKE_image_pool_release_ibuf(ima, ibuf, pool); BRICONTRGB; @@ -1463,7 +1463,7 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex } -int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const float DXT[2], const float DYT[2], TexResult *texres) +int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const float DXT[2], const float DYT[2], TexResult *texres, struct ImagePool *pool) { TexResult texr; float fx, fy, minx, maxx, miny, maxy, dx, dy, dxt[2], dyt[2]; @@ -1477,7 +1477,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const /* anisotropic filtering */ if (tex->texfilter != TXF_BOX) - return imagewraposa_aniso(tex, ima, ibuf, texvec, dxt, dyt, texres); + return imagewraposa_aniso(tex, ima, ibuf, texvec, dxt, dyt, texres, pool); texres->tin= texres->ta= texres->tr= texres->tg= texres->tb= 0.0f; @@ -1493,13 +1493,13 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const if (ima->ibufs.first==NULL && (R.r.scemode & R_NO_IMAGE_LOAD)) return retval; - ibuf= BKE_image_acquire_ibuf(ima, &tex->iuser, NULL); + ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, pool); ima->flag|= IMA_USED_FOR_RENDER; } if (ibuf==NULL || (ibuf->rect==NULL && ibuf->rect_float==NULL)) { if (ima) - BKE_image_release_ibuf(ima, ibuf, NULL); + BKE_image_pool_release_ibuf(ima, ibuf, pool); return retval; } @@ -1608,14 +1608,14 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const } else { if (ima) - BKE_image_release_ibuf(ima, ibuf, NULL); + BKE_image_pool_release_ibuf(ima, ibuf, pool); return retval; } } if ( (tex->flag & TEX_CHECKER_EVEN)==0) { if ((xs + ys) & 1) { if (ima) - BKE_image_release_ibuf(ima, ibuf, NULL); + BKE_image_pool_release_ibuf(ima, ibuf, pool); return retval; } } @@ -1652,14 +1652,14 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const if (tex->extend == TEX_CLIPCUBE) { if (fx+minx<0.0f || fy+miny<0.0f || fx-minx>1.0f || fy-miny>1.0f || texvec[2]<-1.0f || texvec[2]>1.0f) { if (ima) - BKE_image_release_ibuf(ima, ibuf, NULL); + BKE_image_pool_release_ibuf(ima, ibuf, pool); return retval; } } else if (tex->extend==TEX_CLIP || tex->extend==TEX_CHECKER) { if (fx+minx<0.0f || fy+miny<0.0f || fx-minx>1.0f || fy-miny>1.0f) { if (ima) - BKE_image_release_ibuf(ima, ibuf, NULL); + BKE_image_pool_release_ibuf(ima, ibuf, pool); return retval; } } @@ -1855,17 +1855,17 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const } if (ima) - BKE_image_release_ibuf(ima, ibuf, NULL); + BKE_image_pool_release_ibuf(ima, ibuf, pool); BRICONTRGB; return retval; } -void image_sample(Image *ima, float fx, float fy, float dx, float dy, float result[4]) +void image_sample(Image *ima, float fx, float fy, float dx, float dy, float result[4], struct ImagePool *pool) { TexResult texres; - ImBuf *ibuf= BKE_image_acquire_ibuf(ima, NULL, NULL); + ImBuf *ibuf = BKE_image_pool_acquire_ibuf(ima, NULL, pool); if (UNLIKELY(ibuf == NULL)) { zero_v4(result); @@ -1884,7 +1884,7 @@ void image_sample(Image *ima, float fx, float fy, float dx, float dy, float resu ima->flag|= IMA_USED_FOR_RENDER; - BKE_image_release_ibuf(ima, ibuf, NULL); + BKE_image_pool_release_ibuf(ima, ibuf, pool); } void ibuf_sample(ImBuf *ibuf, float fx, float fy, float dx, float dy, float result[4]) diff --git a/source/blender/render/intern/source/multires_bake.c b/source/blender/render/intern/source/multires_bake.c index 091ba9589d7..89f67335c39 100644 --- a/source/blender/render/intern/source/multires_bake.c +++ b/source/blender/render/intern/source/multires_bake.c @@ -60,14 +60,17 @@ #include "rayobject.h" #include "rendercore.h" -typedef void (*MPassKnownData)(DerivedMesh *lores_dm, DerivedMesh *hires_dm, const void *bake_data, - ImBuf *ibuf, const int face_index, const int lvl, const float st[2], - float tangmat[3][3], const int x, const int y); +typedef void (*MPassKnownData)(DerivedMesh *lores_dm, DerivedMesh *hires_dm, void *thread_data, + void *bake_data, ImBuf *ibuf, const int face_index, const int lvl, + const float st[2], float tangmat[3][3], const int x, const int y); typedef void * (*MInitBakeData)(MultiresBakeRender *bkr, Image *ima); -typedef void (*MApplyBakeData)(void *bake_data); typedef void (*MFreeBakeData)(void *bake_data); +typedef struct MultiresBakeResult { + float height_min, height_max; +} MultiresBakeResult; + typedef struct { MVert *mvert; MFace *mface; @@ -79,6 +82,7 @@ typedef struct { int i0, i1, i2; DerivedMesh *lores_dm, *hires_dm; int lvl; + void *thread_data; void *bake_data; ImBuf *ibuf; MPassKnownData pass_data; @@ -95,7 +99,6 @@ typedef struct { typedef struct { float *heights; - float height_min, height_max; Image *ima; DerivedMesh *ssdm; const int *orig_index_mf_to_mpoly; @@ -161,9 +164,11 @@ static void multiresbake_get_normal(const MResolvePixelData *data, float norm[], static void init_bake_rast(MBakeRast *bake_rast, const ImBuf *ibuf, const MResolvePixelData *data, MFlushPixel flush_pixel) { + BakeImBufuserData *userdata = (BakeImBufuserData *) ibuf->userdata; + memset(bake_rast, 0, sizeof(MBakeRast)); - bake_rast->texels = ibuf->userdata; + bake_rast->texels = userdata->mask_buffer; bake_rast->w = ibuf->x; bake_rast->h = ibuf->y; bake_rast->data = data; @@ -222,7 +227,7 @@ static void flush_pixel(const MResolvePixelData *data, const int x, const int y) zero_m3(to_tang); } - data->pass_data(data->lores_dm, data->hires_dm, data->bake_data, + data->pass_data(data->lores_dm, data->hires_dm, data->thread_data, data->bake_data, data->ibuf, data->face_index, data->lvl, st, to_tang, x, y); } @@ -348,6 +353,9 @@ typedef struct MultiresBakeThread { /* thread-specific data */ MBakeRast bake_rast; MResolvePixelData data; + + /* displacement-specific data */ + float height_min, height_max; } MultiresBakeThread; static int multires_bake_queue_next_face(MultiresBakeQueue *queue) @@ -428,8 +436,29 @@ static void *do_multires_bake_thread(void *data_v) return NULL; } +/* some of arrays inside ccgdm are lazy-initialized, which will generally + * require lock around accessing such data + * this function will ensure all arrays are allocated before threading started + */ +static void init_ccgdm_arrays(DerivedMesh *dm) +{ + CCGElem **grid_data; + CCGKey key; + int grid_size; + int *grid_offset; + + grid_size = dm->getGridSize(dm); + grid_data = dm->getGridData(dm); + grid_offset = dm->getGridOffset(dm); + dm->getGridKey(dm, &key); + + (void) grid_size; + (void) grid_data; + (void) grid_offset; +} + static void do_multires_bake(MultiresBakeRender *bkr, Image *ima, int require_tangent, MPassKnownData passKnownData, - MInitBakeData initBakeData, MApplyBakeData applyBakeData, MFreeBakeData freeBakeData) + MInitBakeData initBakeData, MFreeBakeData freeBakeData, MultiresBakeResult *result) { DerivedMesh *dm = bkr->lores_dm; const int lvl = bkr->lvl; @@ -467,6 +496,8 @@ static void do_multires_bake(MultiresBakeRender *bkr, Image *ima, int require_ta handles = MEM_callocN(tot_thread * sizeof(MultiresBakeThread), "do_multires_bake handles"); + init_ccgdm_arrays(bkr->hires_dm); + /* faces queue */ queue.cur_face = 0; queue.tot_face = tot_face; @@ -491,9 +522,13 @@ static void do_multires_bake(MultiresBakeRender *bkr, Image *ima, int require_ta handle->data.hires_dm = bkr->hires_dm; handle->data.lvl = lvl; handle->data.pass_data = passKnownData; + handle->data.thread_data = handle; handle->data.bake_data = bake_data; handle->data.ibuf = ibuf; + handle->height_min = FLT_MAX; + handle->height_max = -FLT_MAX; + init_bake_rast(&handle->bake_rast, ibuf, &handle->data, flush_pixel); if (tot_thread > 1) @@ -506,15 +541,23 @@ static void do_multires_bake(MultiresBakeRender *bkr, Image *ima, int require_ta else do_multires_bake_thread(&handles[0]); + /* construct bake result */ + result->height_min = handles[0].height_min; + result->height_max = handles[0].height_max; + + for (i = 1; i < tot_thread; i++) { + result->height_min = min_ff(result->height_min, handles[i].height_min); + result->height_max = max_ff(result->height_max, handles[i].height_max); + } + BLI_spin_end(&queue.spin); /* finalize baking */ - if (applyBakeData) - applyBakeData(bake_data); - if (freeBakeData) freeBakeData(bake_data); + MEM_freeN(handles); + BKE_image_release_ibuf(ima, ibuf, NULL); } } @@ -651,13 +694,15 @@ static void *init_heights_data(MultiresBakeRender *bkr, Image *ima) MHeightBakeData *height_data; ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); DerivedMesh *lodm = bkr->lores_dm; + BakeImBufuserData *userdata = ibuf->userdata; + + if (userdata->displacement_buffer == NULL) + userdata->displacement_buffer = MEM_callocN(sizeof(float) * ibuf->x * ibuf->y, "MultiresBake heights"); height_data = MEM_callocN(sizeof(MHeightBakeData), "MultiresBake heightData"); height_data->ima = ima; - height_data->heights = MEM_callocN(sizeof(float) * ibuf->x * ibuf->y, "MultiresBake heights"); - height_data->height_max = -FLT_MAX; - height_data->height_min = FLT_MAX; + height_data->heights = userdata->displacement_buffer; if (!bkr->use_lores_mesh) { SubsurfModifierData smd = {{NULL}}; @@ -673,6 +718,7 @@ static void *init_heights_data(MultiresBakeRender *bkr, Image *ima) smd.subdivType = ME_SIMPLE_SUBSURF; height_data->ssdm = subsurf_make_derived_from_derived(bkr->lores_dm, &smd, NULL, 0); + init_ccgdm_arrays(height_data->ssdm); } } @@ -684,48 +730,6 @@ static void *init_heights_data(MultiresBakeRender *bkr, Image *ima) return (void *)height_data; } -static void apply_heights_data(void *bake_data) -{ - MHeightBakeData *height_data = (MHeightBakeData *)bake_data; - ImBuf *ibuf = BKE_image_acquire_ibuf(height_data->ima, NULL, NULL); - int x, y, i; - float height, *heights = height_data->heights; - float min = height_data->height_min, max = height_data->height_max; - - for (x = 0; x < ibuf->x; x++) { - for (y = 0; y < ibuf->y; y++) { - i = ibuf->x * y + x; - - if (((char *)ibuf->userdata)[i] != FILTER_MASK_USED) - continue; - - if (ibuf->rect_float) { - float *rrgbf = ibuf->rect_float + i * 4; - - if (max - min > 1e-5f) height = (heights[i] - min) / (max - min); - else height = 0; - - rrgbf[0] = rrgbf[1] = rrgbf[2] = height; - } - else { - char *rrgb = (char *)ibuf->rect + i * 4; - - if (max - min > 1e-5f) height = (heights[i] - min) / (max - min); - else height = 0; - - rrgb[0] = rrgb[1] = rrgb[2] = FTOCHAR(height); - } - } - } - - if (ibuf->rect_float) - ibuf->userflags |= IB_RECT_INVALID; - - ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; - - BKE_image_release_ibuf(height_data->ima, ibuf, NULL); -} - static void free_heights_data(void *bake_data) { MHeightBakeData *height_data = (MHeightBakeData *)bake_data; @@ -733,7 +737,6 @@ static void free_heights_data(void *bake_data) if (height_data->ssdm) height_data->ssdm->release(height_data->ssdm); - MEM_freeN(height_data->heights); MEM_freeN(height_data); } @@ -743,13 +746,14 @@ static void free_heights_data(void *bake_data) * - find coord of point and normal with specified UV in lo-res mesh (or subdivided lo-res * mesh to make texture smoother) let's call this point p0 and n. * - height wound be dot(n, p1-p0) */ -static void apply_heights_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, const void *bake_data, +static void apply_heights_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, void *thread_data_v, void *bake_data, ImBuf *ibuf, const int face_index, const int lvl, const float st[2], float UNUSED(tangmat[3][3]), const int x, const int y) { MTFace *mtface = CustomData_get_layer(&lores_dm->faceData, CD_MTFACE); MFace mface; MHeightBakeData *height_data = (MHeightBakeData *)bake_data; + MultiresBakeThread *thread_data = (MultiresBakeThread *) thread_data_v; float uv[2], *st0, *st1, *st2, *st3; int pixel = ibuf->x * y + x; float vec[3], p0[3], p1[3], n[3], len; @@ -771,12 +775,12 @@ static void apply_heights_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, CLAMP(uv[1], 0.0f, 1.0f); get_ccgdm_data(lores_dm, hires_dm, - height_data->orig_index_mf_to_mpoly, height_data->orig_index_mf_to_mpoly, + height_data->orig_index_mf_to_mpoly, height_data->orig_index_mp_to_orig, lvl, face_index, uv[0], uv[1], p1, 0); if (height_data->ssdm) { get_ccgdm_data(lores_dm, height_data->ssdm, - height_data->orig_index_mf_to_mpoly, height_data->orig_index_mf_to_mpoly, + height_data->orig_index_mf_to_mpoly, height_data->orig_index_mp_to_orig, 0, face_index, uv[0], uv[1], p0, n); } else { @@ -796,15 +800,18 @@ static void apply_heights_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, len = dot_v3v3(n, vec); height_data->heights[pixel] = len; - if (len < height_data->height_min) height_data->height_min = len; - if (len > height_data->height_max) height_data->height_max = len; + + thread_data->height_min = min_ff(thread_data->height_min, len); + thread_data->height_max = max_ff(thread_data->height_max, len); if (ibuf->rect_float) { float *rrgbf = ibuf->rect_float + pixel * 4; + rrgbf[0] = rrgbf[1] = rrgbf[2] = len; rrgbf[3] = 1.0f; } else { char *rrgb = (char *)ibuf->rect + pixel * 4; + rrgb[0] = rrgb[1] = rrgb[2] = FTOCHAR(len); rrgb[3] = 255; } } @@ -836,9 +843,9 @@ static void free_normal_data(void *bake_data) * - find coord and normal of point with specified UV in hi-res mesh * - multiply it by tangmat * - vector in color space would be norm(vec) /2 + (0.5, 0.5, 0.5) */ -static void apply_tangmat_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, const void *bake_data, - ImBuf *ibuf, const int face_index, const int lvl, const float st[2], - float tangmat[3][3], const int x, const int y) +static void apply_tangmat_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, void *UNUSED(thread_data), + void *bake_data, ImBuf *ibuf, const int face_index, const int lvl, + const float st[2], float tangmat[3][3], const int x, const int y) { MTFace *mtface = CustomData_get_layer(&lores_dm->faceData, CD_MTFACE); MFace mface; @@ -1073,9 +1080,9 @@ static int trace_ao_ray(MAOBakeData *ao_data, float ray_start[3], float ray_dire return RE_rayobject_raycast(ao_data->raytree, &isect); } -static void apply_ao_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, const void *bake_data, - ImBuf *ibuf, const int face_index, const int lvl, const float st[2], - float UNUSED(tangmat[3][3]), const int x, const int y) +static void apply_ao_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, void *UNUSED(thread_data), + void *bake_data, ImBuf *ibuf, const int face_index, const int lvl, + const float st[2], float UNUSED(tangmat[3][3]), const int x, const int y) { MAOBakeData *ao_data = (MAOBakeData *) bake_data; MTFace *mtface = CustomData_get_layer(&lores_dm->faceData, CD_MTFACE); @@ -1205,7 +1212,7 @@ static void count_images(MultiresBakeRender *bkr) mtface[a].tpage->id.flag &= ~LIB_DOIT; } -static void bake_images(MultiresBakeRender *bkr) +static void bake_images(MultiresBakeRender *bkr, MultiresBakeResult *result) { LinkData *link; @@ -1214,18 +1221,19 @@ static void bake_images(MultiresBakeRender *bkr) ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); if (ibuf->x > 0 && ibuf->y > 0) { - ibuf->userdata = MEM_callocN(ibuf->y * ibuf->x, "MultiresBake imbuf mask"); + BakeImBufuserData *userdata = MEM_callocN(sizeof(BakeImBufuserData), "MultiresBake userdata"); + userdata->mask_buffer = MEM_callocN(ibuf->y * ibuf->x, "MultiresBake imbuf mask"); + ibuf->userdata = userdata; switch (bkr->mode) { case RE_BAKE_NORMALS: - do_multires_bake(bkr, ima, TRUE, apply_tangmat_callback, init_normal_data, NULL, free_normal_data); + do_multires_bake(bkr, ima, TRUE, apply_tangmat_callback, init_normal_data, free_normal_data, result); break; case RE_BAKE_DISPLACEMENT: - do_multires_bake(bkr, ima, FALSE, apply_heights_callback, init_heights_data, - apply_heights_data, free_heights_data); + do_multires_bake(bkr, ima, FALSE, apply_heights_callback, init_heights_data, free_heights_data, result); break; case RE_BAKE_AO: - do_multires_bake(bkr, ima, FALSE, apply_ao_callback, init_ao_data, NULL, free_ao_data); + do_multires_bake(bkr, ima, FALSE, apply_ao_callback, init_ao_data, free_ao_data, result); break; } } @@ -1236,18 +1244,25 @@ static void bake_images(MultiresBakeRender *bkr) } } -static void finish_images(MultiresBakeRender *bkr) +static void finish_images(MultiresBakeRender *bkr, MultiresBakeResult *result) { LinkData *link; + int use_displacement_buffer = bkr->mode == RE_BAKE_DISPLACEMENT; for (link = bkr->image.first; link; link = link->next) { Image *ima = (Image *)link->data; ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + BakeImBufuserData *userdata = (BakeImBufuserData *) ibuf->userdata; if (ibuf->x <= 0 || ibuf->y <= 0) continue; - RE_bake_ibuf_filter(ibuf, (char *)ibuf->userdata, bkr->bake_filter); + RE_bake_ibuf_filter(ibuf, userdata->mask_buffer, bkr->bake_filter); + + if (use_displacement_buffer) { + RE_bake_ibuf_normalize_displacement(ibuf, userdata->displacement_buffer, userdata->mask_buffer, + result->height_min, result->height_max); + } ibuf->userflags |= IB_BITMAPDIRTY | IB_DISPLAY_BUFFER_INVALID; @@ -1260,7 +1275,11 @@ static void finish_images(MultiresBakeRender *bkr) } if (ibuf->userdata) { - MEM_freeN(ibuf->userdata); + if (userdata->displacement_buffer) + MEM_freeN(userdata->displacement_buffer); + + MEM_freeN(userdata->mask_buffer); + MEM_freeN(userdata); ibuf->userdata = NULL; } @@ -1270,7 +1289,9 @@ static void finish_images(MultiresBakeRender *bkr) void RE_multires_bake_images(MultiresBakeRender *bkr) { + MultiresBakeResult result; + count_images(bkr); - bake_images(bkr); - finish_images(bkr); + bake_images(bkr, &result); + finish_images(bkr, &result); } diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index e37b24b13a4..866932632c2 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -474,7 +474,7 @@ void RE_InitState(Render *re, Render *source, RenderData *rd, SceneRenderLayer * re->recty = winy; } - if (re->rectx < 2 || re->recty < 2 || (BKE_imtype_is_movie(rd->im_format.imtype) && + if (re->rectx < 1 || re->recty < 1 || (BKE_imtype_is_movie(rd->im_format.imtype) && (re->rectx < 16 || re->recty < 16) )) { BKE_report(re->reports, RPT_ERROR, "Image too small"); @@ -1879,6 +1879,8 @@ static void do_render_all_options(Render *re) /* ensure no images are in memory from previous animated sequences */ BKE_image_all_free_anim_ibufs(re->r.cfra); + re->pool = BKE_image_pool_new(); + if (RE_engine_render(re, 1)) { /* in this case external render overrides all */ } @@ -1903,6 +1905,9 @@ static void do_render_all_options(Render *re) renderresult_stampinfo(re); re->display_draw(re->ddh, re->result, NULL); } + + BKE_image_pool_free(re->pool); + re->pool = NULL; } static int check_valid_camera(Scene *scene, Object *camera_override) @@ -2488,6 +2493,8 @@ void RE_PreviewRender(Render *re, Main *bmain, Scene *sce) RE_InitState(re, NULL, &sce->r, NULL, winx, winy, NULL); + re->pool = BKE_image_pool_new(); + re->main = bmain; re->scene = sce; re->scene_color_manage = BKE_scene_check_color_management_enabled(sce); @@ -2497,6 +2504,9 @@ void RE_PreviewRender(Render *re, Main *bmain, Scene *sce) RE_SetCamera(re, camera); do_render_3d(re); + + BKE_image_pool_free(re->pool); + re->pool = NULL; } /* note; repeated win/disprect calc... solve that nicer, also in compo */ diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c index e3bfd535f11..3ea94981cac 100644 --- a/source/blender/render/intern/source/render_texture.c +++ b/source/blender/render/intern/source/render_texture.c @@ -1099,7 +1099,7 @@ static void do_2d_mapping(MTex *mtex, float texvec[3], VlakRen *vlr, const float /* ************************************** */ -static int multitex(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres, const short thread, short which_output) +static int multitex(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres, const short thread, short which_output, struct ImagePool *pool) { float tmpvec[3]; int retval = 0; /* return value, int:0, col:1, nor:2, everything:3 */ @@ -1137,12 +1137,12 @@ static int multitex(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int o retval = texnoise(tex, texres); break; case TEX_IMAGE: - if (osatex) retval = imagewraposa(tex, tex->ima, NULL, texvec, dxt, dyt, texres); - else retval = imagewrap(tex, tex->ima, NULL, texvec, texres); + if (osatex) retval = imagewraposa(tex, tex->ima, NULL, texvec, dxt, dyt, texres, pool); + else retval = imagewrap(tex, tex->ima, NULL, texvec, texres, pool); BKE_image_tag_time(tex->ima); /* tag image as having being used */ break; case TEX_ENVMAP: - retval = envmaptex(tex, texvec, dxt, dyt, osatex, texres); + retval = envmaptex(tex, texvec, dxt, dyt, osatex, texres, pool); break; case TEX_MUSGRAVE: /* newnoise: musgrave types */ @@ -1214,7 +1214,7 @@ static int multitex(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int o /* this is called from the shader and texture nodes */ int multitex_nodes(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres, - const short thread, short which_output, ShadeInput *shi, MTex *mtex) + const short thread, short which_output, ShadeInput *shi, MTex *mtex, struct ImagePool *pool) { if (tex==NULL) { memset(texres, 0, sizeof(TexResult)); @@ -1230,16 +1230,16 @@ int multitex_nodes(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int os if (mtex) { /* we have mtex, use it for 2d mapping images only */ do_2d_mapping(mtex, texvec, shi->vlr, shi->facenor, dxt, dyt); - rgbnor = multitex(tex, texvec, dxt, dyt, osatex, texres, thread, which_output); + rgbnor = multitex(tex, texvec, dxt, dyt, osatex, texres, thread, which_output, pool); if (mtex->mapto & (MAP_COL+MAP_COLSPEC+MAP_COLMIR)) { - ImBuf *ibuf = BKE_image_acquire_ibuf(tex->ima, &tex->iuser, NULL); + ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool); /* don't linearize float buffers, assumed to be linear */ if (ibuf && !(ibuf->rect_float) && R.scene_color_manage) IMB_colormanagement_colorspace_to_scene_linear_v3(&texres->tr, ibuf->rect_colorspace); - BKE_image_release_ibuf(tex->ima, ibuf, NULL); + BKE_image_pool_release_ibuf(tex->ima, ibuf, pool); } } else { @@ -1263,28 +1263,28 @@ int multitex_nodes(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int os } do_2d_mapping(&localmtex, texvec_l, NULL, NULL, dxt_l, dyt_l); - rgbnor= multitex(tex, texvec_l, dxt_l, dyt_l, osatex, texres, thread, which_output); + rgbnor = multitex(tex, texvec_l, dxt_l, dyt_l, osatex, texres, thread, which_output, pool); { - ImBuf *ibuf = BKE_image_acquire_ibuf(tex->ima, &tex->iuser, NULL); + ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool); /* don't linearize float buffers, assumed to be linear */ if (ibuf && !(ibuf->rect_float) && R.scene_color_manage) IMB_colormanagement_colorspace_to_scene_linear_v3(&texres->tr, ibuf->rect_colorspace); - BKE_image_release_ibuf(tex->ima, ibuf, NULL); + BKE_image_pool_release_ibuf(tex->ima, ibuf, pool); } } return rgbnor; } else { - return multitex(tex, texvec, dxt, dyt, osatex, texres, thread, which_output); + return multitex(tex, texvec, dxt, dyt, osatex, texres, thread, which_output, pool); } } /* this is called for surface shading */ -static int multitex_mtex(ShadeInput *shi, MTex *mtex, float texvec[3], float dxt[3], float dyt[3], TexResult *texres) +static int multitex_mtex(ShadeInput *shi, MTex *mtex, float texvec[3], float dxt[3], float dyt[3], TexResult *texres, struct ImagePool *pool) { Tex *tex = mtex->tex; @@ -1295,24 +1295,24 @@ static int multitex_mtex(ShadeInput *shi, MTex *mtex, float texvec[3], float dxt tex, mtex->which_output, R.r.cfra, (R.r.scemode & R_TEXNODE_PREVIEW) != 0, shi, mtex); } else { - return multitex(mtex->tex, texvec, dxt, dyt, shi->osatex, texres, shi->thread, mtex->which_output); + return multitex(mtex->tex, texvec, dxt, dyt, shi->osatex, texres, shi->thread, mtex->which_output, pool); } } /* Warning, if the texres's values are not declared zero, check the return value to be sure * the color values are set before using the r/g/b values, otherwise you may use uninitialized values - Campbell */ -int multitex_ext(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres) +int multitex_ext(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres, struct ImagePool *pool) { - return multitex_nodes(tex, texvec, dxt, dyt, osatex, texres, 0, 0, NULL, NULL); + return multitex_nodes(tex, texvec, dxt, dyt, osatex, texres, 0, 0, NULL, NULL, pool); } /* extern-tex doesn't support nodes (ntreeBeginExec() can't be called when rendering is going on) */ -int multitex_ext_safe(Tex *tex, float texvec[3], TexResult *texres) +int multitex_ext_safe(Tex *tex, float texvec[3], TexResult *texres, struct ImagePool *pool) { int use_nodes= tex->use_nodes, retval; tex->use_nodes = FALSE; - retval= multitex_nodes(tex, texvec, NULL, NULL, 0, texres, 0, 0, NULL, NULL); + retval= multitex_nodes(tex, texvec, NULL, NULL, 0, texres, 0, 0, NULL, NULL, pool); tex->use_nodes= use_nodes; return retval; @@ -1699,7 +1699,8 @@ static void compatible_bump_uv_derivs(CompatibleBump *compat_bump, ShadeInput *s } static int compatible_bump_compute(CompatibleBump *compat_bump, ShadeInput *shi, MTex *mtex, Tex *tex, TexResult *texres, - float Tnor, const float co[3], const float dx[3], const float dy[3], float texvec[3], float dxt[3], float dyt[3]) + float Tnor, const float co[3], const float dx[3], const float dy[3], float texvec[3], float dxt[3], float dyt[3], + struct ImagePool *pool) { TexResult ttexr = {0, 0, 0, 0, 0, texres->talpha, NULL}; /* temp TexResult */ float tco[3], texv[3], cd, ud, vd, du, dv, idu, idv; @@ -1727,12 +1728,12 @@ static int compatible_bump_compute(CompatibleBump *compat_bump, ShadeInput *shi, if (!shi->osatex && (tex->type == TEX_IMAGE) && tex->ima) { /* in case we have no proper derivatives, fall back to * computing du/dv it based on image size */ - ImBuf *ibuf = BKE_image_acquire_ibuf(tex->ima, &tex->iuser, NULL); + ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool); if (ibuf) { du = 1.f/(float)ibuf->x; dv = 1.f/(float)ibuf->y; } - BKE_image_release_ibuf(tex->ima, ibuf, NULL); + BKE_image_pool_release_ibuf(tex->ima, ibuf, pool); } else if (shi->osatex) { /* we have derivatives, can compute proper du/dv */ @@ -1752,7 +1753,7 @@ static int compatible_bump_compute(CompatibleBump *compat_bump, ShadeInput *shi, /* center, main return value */ texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt); - rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, texres); + rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, texres, pool); cd = fromrgb ? (texres->tr + texres->tg + texres->tb)*0.33333333f : texres->tin; if (mtex->texco == TEXCO_UV) { @@ -1766,7 +1767,7 @@ static int compatible_bump_compute(CompatibleBump *compat_bump, ShadeInput *shi, tco[1] = co[1] + compat_bump->dvdnu*du; tco[2] = 0.f; texco_mapping(shi, tex, mtex, tco, dx, dy, texv, dxt, dyt); - multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr); + multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr, pool); ud = idu*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb)*0.33333333f : ttexr.tin)); /* +v val */ @@ -1774,7 +1775,7 @@ static int compatible_bump_compute(CompatibleBump *compat_bump, ShadeInput *shi, tco[1] = co[1] + compat_bump->dvdnv*du; tco[2] = 0.f; texco_mapping(shi, tex, mtex, tco, dx, dy, texv, dxt, dyt); - multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr); + multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr, pool); vd = idu*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb)*0.33333333f : ttexr.tin)); } else { @@ -1808,7 +1809,7 @@ static int compatible_bump_compute(CompatibleBump *compat_bump, ShadeInput *shi, tco[1] = co[1] + tu[1]*du; tco[2] = co[2] + tu[2]*du; texco_mapping(shi, tex, mtex, tco, dx, dy, texv, dxt, dyt); - multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr); + multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr, pool); ud = idu*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb)*0.33333333f : ttexr.tin)); /* +v val */ @@ -1816,7 +1817,7 @@ static int compatible_bump_compute(CompatibleBump *compat_bump, ShadeInput *shi, tco[1] = co[1] + tv[1]*dv; tco[2] = co[2] + tv[2]*dv; texco_mapping(shi, tex, mtex, tco, dx, dy, texv, dxt, dyt); - multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr); + multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr, pool); vd = idv*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb)*0.33333333f : ttexr.tin)); } @@ -1858,7 +1859,7 @@ static void ntap_bump_init(NTapBump *ntap_bump) static int ntap_bump_compute(NTapBump *ntap_bump, ShadeInput *shi, MTex *mtex, Tex *tex, TexResult *texres, float Tnor, const float co[3], const float dx[3], const float dy[3], - float texvec[3], float dxt[3], float dyt[3]) + float texvec[3], float dxt[3], float dyt[3], struct ImagePool *pool) { TexResult ttexr = {0, 0, 0, 0, 0, texres->talpha, NULL}; /* temp TexResult */ @@ -1905,20 +1906,20 @@ static int ntap_bump_compute(NTapBump *ntap_bump, ShadeInput *shi, MTex *mtex, T /* resolve image dimensions */ if (found_deriv_map || (mtex->texflag&MTEX_BUMP_TEXTURESPACE)!=0) { - ImBuf *ibuf = BKE_image_acquire_ibuf(tex->ima, &tex->iuser, NULL); + ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool); if (ibuf) { dimx = ibuf->x; dimy = ibuf->y; aspect = ((float) dimy) / dimx; } - BKE_image_release_ibuf(tex->ima, ibuf, NULL); + BKE_image_pool_release_ibuf(tex->ima, ibuf, pool); } if (found_deriv_map) { float dBdu, dBdv, auto_bump = 1.0f; float s = 1; /* negate this if flipped texture coordinate */ texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt); - rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, texres); + rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, texres, pool); if (shi->obr->ob->derivedFinal) { auto_bump = shi->obr->ob->derivedFinal->auto_bump_scale; @@ -1960,14 +1961,14 @@ static int ntap_bump_compute(NTapBump *ntap_bump, ShadeInput *shi, MTex *mtex, T } /* use texres for the center sample, set rgbnor */ - rgbnor = multitex_mtex(shi, mtex, STll, dxt, dyt, texres); + rgbnor = multitex_mtex(shi, mtex, STll, dxt, dyt, texres, pool); Hll = (fromrgb) ? rgb_to_grayscale(&texres->tr) : texres->tin; /* use ttexr for the other 2 taps */ - multitex_mtex(shi, mtex, STlr, dxt, dyt, &ttexr); + multitex_mtex(shi, mtex, STlr, dxt, dyt, &ttexr, pool); Hlr = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin; - multitex_mtex(shi, mtex, STul, dxt, dyt, &ttexr); + multitex_mtex(shi, mtex, STul, dxt, dyt, &ttexr, pool); Hul = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin; dHdx = Hscale*(Hlr - Hll); @@ -1998,17 +1999,17 @@ static int ntap_bump_compute(NTapBump *ntap_bump, ShadeInput *shi, MTex *mtex, T } /* use texres for the center sample, set rgbnor */ - rgbnor = multitex_mtex(shi, mtex, STc, dxt, dyt, texres); + rgbnor = multitex_mtex(shi, mtex, STc, dxt, dyt, texres, pool); /* Hc = (fromrgb) ? rgb_to_grayscale(&texres->tr) : texres->tin; */ /* UNUSED */ /* use ttexr for the other taps */ - multitex_mtex(shi, mtex, STl, dxt, dyt, &ttexr); + multitex_mtex(shi, mtex, STl, dxt, dyt, &ttexr, pool); Hl = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin; - multitex_mtex(shi, mtex, STr, dxt, dyt, &ttexr); + multitex_mtex(shi, mtex, STr, dxt, dyt, &ttexr, pool); Hr = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin; - multitex_mtex(shi, mtex, STd, dxt, dyt, &ttexr); + multitex_mtex(shi, mtex, STd, dxt, dyt, &ttexr, pool); Hd = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin; - multitex_mtex(shi, mtex, STu, dxt, dyt, &ttexr); + multitex_mtex(shi, mtex, STu, dxt, dyt, &ttexr, pool); Hu = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin; dHdx = Hscale*(Hr - Hl); @@ -2285,20 +2286,22 @@ void do_material_tex(ShadeInput *shi, Render *re) if (texres.nor && !((tex->type==TEX_IMAGE) && (tex->imaflag & TEX_NORMALMAP))) { if (use_compat_bump) { rgbnor = compatible_bump_compute(&compat_bump, shi, mtex, tex, - &texres, Tnor*stencilTin, co, dx, dy, texvec, dxt, dyt); + &texres, Tnor*stencilTin, co, dx, dy, texvec, dxt, dyt, + re->pool); } else if (use_ntap_bump) { rgbnor = ntap_bump_compute(&ntap_bump, shi, mtex, tex, - &texres, Tnor*stencilTin, co, dx, dy, texvec, dxt, dyt); + &texres, Tnor*stencilTin, co, dx, dy, texvec, dxt, dyt, + re->pool); } else { texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt); - rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, &texres); + rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, &texres, re->pool); } } else { texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt); - rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, &texres); + rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, &texres, re->pool); } /* texture output */ @@ -2402,13 +2405,13 @@ void do_material_tex(ShadeInput *shi, Render *re) /* inverse gamma correction */ if (tex->type==TEX_IMAGE) { Image *ima = tex->ima; - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &tex->iuser, NULL); + ImBuf *ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, re->pool); /* don't linearize float buffers, assumed to be linear */ if (ibuf && !(ibuf->rect_float) && R.scene_color_manage) IMB_colormanagement_colorspace_to_scene_linear_v3(tcol, ibuf->rect_colorspace); - BKE_image_release_ibuf(ima, ibuf, NULL); + BKE_image_pool_release_ibuf(ima, ibuf, re->pool); } if (mtex->mapto & MAP_COL) { @@ -2737,7 +2740,7 @@ void do_volume_tex(ShadeInput *shi, const float *xyz, int mapto_flag, float col_ else texvec[2]= mtex->size[2]*(mtex->ofs[2]); } - rgbnor= multitex(tex, texvec, NULL, NULL, 0, &texres, 0, mtex->which_output); /* NULL = dxt/dyt, 0 = shi->osatex - not supported */ + rgbnor = multitex(tex, texvec, NULL, NULL, 0, &texres, 0, mtex->which_output, re->pool); /* NULL = dxt/dyt, 0 = shi->osatex - not supported */ /* texture output */ @@ -2904,7 +2907,7 @@ void do_halo_tex(HaloRen *har, float xn, float yn, float col_r[4]) if (mtex->tex->type==TEX_IMAGE) do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt); - rgb= multitex(mtex->tex, texvec, dxt, dyt, osatex, &texres, 0, mtex->which_output); + rgb = multitex(mtex->tex, texvec, dxt, dyt, osatex, &texres, 0, mtex->which_output, har->pool); /* texture output */ if (rgb && (mtex->texflag & MTEX_RGBTOINT)) { @@ -2936,13 +2939,13 @@ void do_halo_tex(HaloRen *har, float xn, float yn, float col_r[4]) /* inverse gamma correction */ if (mtex->tex->type==TEX_IMAGE) { Image *ima = mtex->tex->ima; - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &mtex->tex->iuser, NULL); + ImBuf *ibuf = BKE_image_pool_acquire_ibuf(ima, &mtex->tex->iuser, har->pool); /* don't linearize float buffers, assumed to be linear */ if (ibuf && !(ibuf->rect_float) && R.scene_color_manage) IMB_colormanagement_colorspace_to_scene_linear_v3(&texres.tr, ibuf->rect_colorspace); - BKE_image_release_ibuf(ima, ibuf, NULL); + BKE_image_pool_release_ibuf(ima, ibuf, har->pool); } fact= texres.tin*mtex->colfac; @@ -3109,7 +3112,7 @@ void do_sky_tex(const float rco[3], float lo[3], const float dxyview[2], float h /* texture */ if (tex->type==TEX_IMAGE) do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt); - rgb= multitex(mtex->tex, texvec, dxt, dyt, R.osa, &texres, thread, mtex->which_output); + rgb = multitex(mtex->tex, texvec, dxt, dyt, R.osa, &texres, thread, mtex->which_output, R.pool); /* texture output */ if (rgb && (mtex->texflag & MTEX_RGBTOINT)) { @@ -3157,13 +3160,13 @@ void do_sky_tex(const float rco[3], float lo[3], const float dxyview[2], float h /* inverse gamma correction */ if (tex->type==TEX_IMAGE) { Image *ima = tex->ima; - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &tex->iuser, NULL); + ImBuf *ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, R.pool); /* don't linearize float buffers, assumed to be linear */ if (ibuf && !(ibuf->rect_float) && R.scene_color_manage) IMB_colormanagement_colorspace_to_scene_linear_v3(tcol, ibuf->rect_colorspace); - BKE_image_release_ibuf(ima, ibuf, NULL); + BKE_image_pool_release_ibuf(ima, ibuf, R.pool); } if (mtex->mapto & WOMAP_HORIZ) { @@ -3324,7 +3327,7 @@ void do_lamp_tex(LampRen *la, const float lavec[3], ShadeInput *shi, float col_r do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt); } - rgb= multitex(tex, texvec, dxt, dyt, shi->osatex, &texres, shi->thread, mtex->which_output); + rgb = multitex(tex, texvec, dxt, dyt, shi->osatex, &texres, shi->thread, mtex->which_output, R.pool); /* texture output */ if (rgb && (mtex->texflag & MTEX_RGBTOINT)) { @@ -3373,13 +3376,13 @@ void do_lamp_tex(LampRen *la, const float lavec[3], ShadeInput *shi, float col_r /* inverse gamma correction */ if (tex->type==TEX_IMAGE) { Image *ima = tex->ima; - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &tex->iuser, NULL); + ImBuf *ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, R.pool); /* don't linearize float buffers, assumed to be linear */ if (ibuf && !(ibuf->rect_float) && R.scene_color_manage) IMB_colormanagement_colorspace_to_scene_linear_v3(&texres.tr, ibuf->rect_colorspace); - BKE_image_release_ibuf(ima, ibuf, NULL); + BKE_image_pool_release_ibuf(ima, ibuf, R.pool); } /* lamp colors were premultiplied with this */ @@ -3395,7 +3398,7 @@ void do_lamp_tex(LampRen *la, const float lavec[3], ShadeInput *shi, float col_r /* ------------------------------------------------------------------------- */ -int externtex(MTex *mtex, const float vec[3], float *tin, float *tr, float *tg, float *tb, float *ta, const int thread) +int externtex(MTex *mtex, const float vec[3], float *tin, float *tr, float *tg, float *tb, float *ta, const int thread, struct ImagePool *pool) { Tex *tex; TexResult texr; @@ -3421,7 +3424,7 @@ int externtex(MTex *mtex, const float vec[3], float *tin, float *tr, float *tg, do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt); } - rgb= multitex(tex, texvec, dxt, dyt, 0, &texr, thread, mtex->which_output); + rgb = multitex(tex, texvec, dxt, dyt, 0, &texr, thread, mtex->which_output, pool); if (rgb) { texr.tin = rgb_to_bw(&texr.tr); @@ -3485,8 +3488,8 @@ void render_realtime_texture(ShadeInput *shi, Image *ima) texr.nor= NULL; - if (shi->osatex) imagewraposa(tex, ima, NULL, texvec, dx, dy, &texr); - else imagewrap(tex, ima, NULL, texvec, &texr); + if (shi->osatex) imagewraposa(tex, ima, NULL, texvec, dx, dy, &texr, R.pool); + else imagewrap(tex, ima, NULL, texvec, &texr, R.pool); shi->vcol[0]*= texr.tr; shi->vcol[1]*= texr.tg; diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c index 14586f16478..2d0f575b3e3 100644 --- a/source/blender/render/intern/source/rendercore.c +++ b/source/blender/render/intern/source/rendercore.c @@ -20,7 +20,6 @@ * * Contributors: Hos, Robert Wenzlaff. * Contributors: 2004/2005/2006 Blender Foundation, full recode - * Contributors: Vertex color baking, Copyright 2011 AutoCRC * * ***** END GPL LICENSE BLOCK ***** */ @@ -1139,7 +1138,7 @@ static void addAlphaOverFloatMask(float *dest, float *source, unsigned short dma dest[3]+= source[3]; return; - } + } dest[0]= (mul*dest[0]) + source[0]; dest[1]= (mul*dest[1]) + source[1]; @@ -1991,932 +1990,3 @@ void add_halo_flare(Render *re) R.r.mode= mode; } -/* ************************* bake ************************ */ - - -typedef struct BakeShade { - ShadeSample ssamp; - ObjectInstanceRen *obi; - VlakRen *vlr; - - ZSpan *zspan; - Image *ima; - ImBuf *ibuf; - - int rectx, recty, quad, type, vdone, ready; - - float dir[3]; - Object *actob; - - /* Output: vertex color or image data. If vcol is not NULL, rect and - * rect_float should be NULL. */ - MPoly *mpoly; - MLoop *mloop; - MLoopCol *vcol; - - unsigned int *rect; - float *rect_float; - - int use_mask; - char *rect_mask; /* bake pixel mask */ - - float dxco[3], dyco[3]; - - short *do_update; - - struct ColorSpace *rect_colorspace; -} BakeShade; - -static void bake_set_shade_input(ObjectInstanceRen *obi, VlakRen *vlr, ShadeInput *shi, int quad, int UNUSED(isect), int x, int y, float u, float v) -{ - if (quad) - shade_input_set_triangle_i(shi, obi, vlr, 0, 2, 3); - else - shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2); - - /* cache for shadow */ - shi->samplenr= R.shadowsamplenr[shi->thread]++; - - shi->mask= 0xFFFF; /* all samples */ - - shi->u= -u; - shi->v= -v; - shi->xs= x; - shi->ys= y; - - shade_input_set_uv(shi); - shade_input_set_normals(shi); - - /* no normal flip */ - if (shi->flippednor) - shade_input_flip_normals(shi); - - /* set up view vector to look right at the surface (note that the normal - * is negated in the renderer so it does not need to be done here) */ - shi->view[0]= shi->vn[0]; - shi->view[1]= shi->vn[1]; - shi->view[2]= shi->vn[2]; -} - -static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int UNUSED(quad), int x, int y, float UNUSED(u), float UNUSED(v), float *tvn, float *ttang) -{ - BakeShade *bs= handle; - ShadeSample *ssamp= &bs->ssamp; - ShadeResult shr; - VlakRen *vlr= shi->vlr; - - shade_input_init_material(shi); - - if (bs->type==RE_BAKE_AO) { - ambient_occlusion(shi); - - if (R.r.bake_flag & R_BAKE_NORMALIZE) { - copy_v3_v3(shr.combined, shi->ao); - } - else { - zero_v3(shr.combined); - environment_lighting_apply(shi, &shr); - } - } - else { - if (bs->type==RE_BAKE_SHADOW) /* Why do shadows set the color anyhow?, ignore material color for baking */ - shi->r = shi->g = shi->b = 1.0f; - - shade_input_set_shade_texco(shi); - - /* only do AO for a full bake (and obviously AO bakes) - * AO for light bakes is a leftover and might not be needed */ - if ( ELEM3(bs->type, RE_BAKE_ALL, RE_BAKE_AO, RE_BAKE_LIGHT)) - shade_samples_do_AO(ssamp); - - if (shi->mat->nodetree && shi->mat->use_nodes) { - ntreeShaderExecTree(shi->mat->nodetree, shi, &shr); - shi->mat= vlr->mat; /* shi->mat is being set in nodetree */ - } - else - shade_material_loop(shi, &shr); - - if (bs->type==RE_BAKE_NORMALS) { - float nor[3]; - - copy_v3_v3(nor, shi->vn); - - if (R.r.bake_normal_space == R_BAKE_SPACE_CAMERA) { - /* pass */ - } - else if (R.r.bake_normal_space == R_BAKE_SPACE_TANGENT) { - float mat[3][3], imat[3][3]; - - /* bitangent */ - if (tvn && ttang) { - copy_v3_v3(mat[0], ttang); - cross_v3_v3v3(mat[1], tvn, ttang); - mul_v3_fl(mat[1], ttang[3]); - copy_v3_v3(mat[2], tvn); - } - else { - copy_v3_v3(mat[0], shi->nmaptang); - cross_v3_v3v3(mat[1], shi->nmapnorm, shi->nmaptang); - mul_v3_fl(mat[1], shi->nmaptang[3]); - copy_v3_v3(mat[2], shi->nmapnorm); - } - - invert_m3_m3(imat, mat); - mul_m3_v3(imat, nor); - } - else if (R.r.bake_normal_space == R_BAKE_SPACE_OBJECT) - mul_mat3_m4_v3(ob->imat_ren, nor); /* ob->imat_ren includes viewinv! */ - else if (R.r.bake_normal_space == R_BAKE_SPACE_WORLD) - mul_mat3_m4_v3(R.viewinv, nor); - - normalize_v3(nor); /* in case object has scaling */ - - /* The invert of the red channel is to make - * the normal map compliant with the outside world. - * It needs to be done because in Blender - * the normal used in the renderer points inward. It is generated - * this way in calc_vertexnormals(). Should this ever change - * this negate must be removed. */ - shr.combined[0]= (-nor[0])/2.0f + 0.5f; - shr.combined[1]= nor[1]/2.0f + 0.5f; - shr.combined[2]= nor[2]/2.0f + 0.5f; - } - else if (bs->type==RE_BAKE_TEXTURE) { - shr.combined[0]= shi->r; - shr.combined[1]= shi->g; - shr.combined[2]= shi->b; - shr.alpha = shi->alpha; - } - else if (bs->type==RE_BAKE_SHADOW) { - copy_v3_v3(shr.combined, shr.shad); - shr.alpha = shi->alpha; - } - else if (bs->type==RE_BAKE_SPEC_COLOR) { - shr.combined[0]= shi->specr; - shr.combined[1]= shi->specg; - shr.combined[2]= shi->specb; - shr.alpha = 1.0f; - } - else if (bs->type==RE_BAKE_SPEC_INTENSITY) { - shr.combined[0]= - shr.combined[1]= - shr.combined[2]= shi->spec; - shr.alpha = 1.0f; - } - else if (bs->type==RE_BAKE_MIRROR_COLOR) { - shr.combined[0]= shi->mirr; - shr.combined[1]= shi->mirg; - shr.combined[2]= shi->mirb; - shr.alpha = 1.0f; - } - else if (bs->type==RE_BAKE_MIRROR_INTENSITY) { - shr.combined[0]= - shr.combined[1]= - shr.combined[2]= shi->ray_mirror; - shr.alpha = 1.0f; - } - else if (bs->type==RE_BAKE_ALPHA) { - shr.combined[0]= - shr.combined[1]= - shr.combined[2]= shi->alpha; - shr.alpha = 1.0f; - } - else if (bs->type==RE_BAKE_EMIT) { - shr.combined[0]= - shr.combined[1]= - shr.combined[2]= shi->emit; - shr.alpha = 1.0f; - } - } - - if (bs->rect_float && !bs->vcol) { - float *col= bs->rect_float + 4*(bs->rectx*y + x); - copy_v3_v3(col, shr.combined); - if (bs->type==RE_BAKE_ALL || bs->type==RE_BAKE_TEXTURE) { - col[3]= shr.alpha; - } - else { - col[3]= 1.0; - } - } - else { - /* Target is char (LDR). */ - unsigned char col[4]; - - if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE)) { - float rgb[3]; - - copy_v3_v3(rgb, shr.combined); - if (R.scene_color_manage) - IMB_colormanagement_scene_linear_to_colorspace_v3(rgb, bs->rect_colorspace); - rgb_float_to_uchar(col, rgb); - } - else { - rgb_float_to_uchar(col, shr.combined); - } - - if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE)) { - col[3]= FTOCHAR(shr.alpha); - } - else { - col[3]= 255; - } - - if (bs->vcol) { - /* Vertex colour baking. Vcol has no useful alpha channel (it exists - * but is used only for vertex painting). */ - bs->vcol->r = col[0]; - bs->vcol->g = col[1]; - bs->vcol->b = col[2]; - } - else { - unsigned char *imcol= (unsigned char *)(bs->rect + bs->rectx*y + x); - copy_v4_v4_char((char *)imcol, (char *)col); - } - - } - - if (bs->rect_mask) { - bs->rect_mask[bs->rectx*y + x] = FILTER_MASK_USED; - } -} - -static void bake_displacement(void *handle, ShadeInput *UNUSED(shi), float dist, int x, int y) -{ - BakeShade *bs= handle; - float disp; - - if (R.r.bake_flag & R_BAKE_NORMALIZE && R.r.bake_maxdist) { - disp = (dist+R.r.bake_maxdist) / (R.r.bake_maxdist*2); /* alter the range from [-bake_maxdist, bake_maxdist] to [0, 1]*/ - } - else { - disp = 0.5f + dist; /* alter the range from [-0.5,0.5] to [0,1]*/ - } - - if (bs->rect_float && !bs->vcol) { - float *col= bs->rect_float + 4*(bs->rectx*y + x); - col[0] = col[1] = col[2] = disp; - col[3]= 1.0f; - } - else { - /* Target is char (LDR). */ - unsigned char col[4]; - col[0] = col[1] = col[2] = FTOCHAR(disp); - col[3] = 255; - - if(bs->vcol) { - /* Vertex colour baking. Vcol has no useful alpha channel (it exists - * but is used only for vertex painting). */ - bs->vcol->r = col[0]; - bs->vcol->g = col[1]; - bs->vcol->b = col[2]; - } - else { - char *imcol= (char *)(bs->rect + bs->rectx*y + x); - copy_v4_v4_char((char *)imcol, (char *)col); - } - } - if (bs->rect_mask) { - bs->rect_mask[bs->rectx*y + x] = FILTER_MASK_USED; - } -} - -static int bake_intersect_tree(RayObject* raytree, Isect* isect, float *start, float *dir, float sign, float *hitco, float *dist) -{ - float maxdist; - int hit; - - /* might be useful to make a user setting for maxsize*/ - if (R.r.bake_maxdist > 0.0f) - maxdist= R.r.bake_maxdist; - else - maxdist= RE_RAYTRACE_MAXDIST + R.r.bake_biasdist; - - /* 'dir' is always normalized */ - madd_v3_v3v3fl(isect->start, start, dir, -R.r.bake_biasdist); - - mul_v3_v3fl(isect->dir, dir, sign); - - isect->dist = maxdist; - - hit = RE_rayobject_raycast(raytree, isect); - if (hit) { - madd_v3_v3v3fl(hitco, isect->start, isect->dir, isect->dist); - - *dist= isect->dist; - } - - return hit; -} - -static void bake_set_vlr_dxyco(BakeShade *bs, float *uv1, float *uv2, float *uv3) -{ - VlakRen *vlr= bs->vlr; - float A, d1, d2, d3, *v1, *v2, *v3; - - if (bs->quad) { - v1= vlr->v1->co; - v2= vlr->v3->co; - v3= vlr->v4->co; - } - else { - v1= vlr->v1->co; - v2= vlr->v2->co; - v3= vlr->v3->co; - } - - /* formula derived from barycentric coordinates: - * (uvArea1*v1 + uvArea2*v2 + uvArea3*v3)/uvArea - * then taking u and v partial derivatives to get dxco and dyco */ - A= (uv2[0] - uv1[0])*(uv3[1] - uv1[1]) - (uv3[0] - uv1[0])*(uv2[1] - uv1[1]); - - if (fabsf(A) > FLT_EPSILON) { - A= 0.5f/A; - - d1= uv2[1] - uv3[1]; - d2= uv3[1] - uv1[1]; - d3= uv1[1] - uv2[1]; - bs->dxco[0]= (v1[0]*d1 + v2[0]*d2 + v3[0]*d3)*A; - bs->dxco[1]= (v1[1]*d1 + v2[1]*d2 + v3[1]*d3)*A; - bs->dxco[2]= (v1[2]*d1 + v2[2]*d2 + v3[2]*d3)*A; - - d1= uv3[0] - uv2[0]; - d2= uv1[0] - uv3[0]; - d3= uv2[0] - uv1[0]; - bs->dyco[0]= (v1[0]*d1 + v2[0]*d2 + v3[0]*d3)*A; - bs->dyco[1]= (v1[1]*d1 + v2[1]*d2 + v3[1]*d3)*A; - bs->dyco[2]= (v1[2]*d1 + v2[2]*d2 + v3[2]*d3)*A; - } - else { - bs->dxco[0]= bs->dxco[1]= bs->dxco[2]= 0.0f; - bs->dyco[0]= bs->dyco[1]= bs->dyco[2]= 0.0f; - } - - if (bs->obi->flag & R_TRANSFORMED) { - mul_m3_v3(bs->obi->nmat, bs->dxco); - mul_m3_v3(bs->obi->nmat, bs->dyco); - } -} - -static void do_bake_shade(void *handle, int x, int y, float u, float v) -{ - BakeShade *bs= handle; - VlakRen *vlr= bs->vlr; - ObjectInstanceRen *obi= bs->obi; - Object *ob= obi->obr->ob; - float l, *v1, *v2, *v3, tvn[3], ttang[4]; - int quad; - ShadeSample *ssamp= &bs->ssamp; - ShadeInput *shi= ssamp->shi; - - /* fast threadsafe break test */ - if (R.test_break(R.tbh)) - return; - - /* setup render coordinates */ - if (bs->quad) { - v1= vlr->v1->co; - v2= vlr->v3->co; - v3= vlr->v4->co; - } - else { - v1= vlr->v1->co; - v2= vlr->v2->co; - v3= vlr->v3->co; - } - - l= 1.0f-u-v; - - /* shrink barycentric coordinates inwards slightly to avoid some issues - * where baking selected to active might just miss the other face at the - * near the edge of a face */ - if (bs->actob) { - const float eps = 1.0f - 1e-4f; - float invsum; - - u = (u - 0.5f)*eps + 0.5f; - v = (v - 0.5f)*eps + 0.5f; - l = (l - 0.5f)*eps + 0.5f; - - invsum = 1.0f/(u + v + l); - - u *= invsum; - v *= invsum; - l *= invsum; - } - - /* renderco */ - shi->co[0]= l*v3[0]+u*v1[0]+v*v2[0]; - shi->co[1]= l*v3[1]+u*v1[1]+v*v2[1]; - shi->co[2]= l*v3[2]+u*v1[2]+v*v2[2]; - - if (obi->flag & R_TRANSFORMED) - mul_m4_v3(obi->mat, shi->co); - - copy_v3_v3(shi->dxco, bs->dxco); - copy_v3_v3(shi->dyco, bs->dyco); - - quad= bs->quad; - bake_set_shade_input(obi, vlr, shi, quad, 0, x, y, u, v); - - if (bs->type==RE_BAKE_NORMALS && R.r.bake_normal_space==R_BAKE_SPACE_TANGENT) { - shade_input_set_shade_texco(shi); - copy_v3_v3(tvn, shi->nmapnorm); - copy_v4_v4(ttang, shi->nmaptang); - } - - /* if we are doing selected to active baking, find point on other face */ - if (bs->actob) { - Isect isec, minisec; - float co[3], minco[3], dist, mindist=0.0f; - int hit, sign, dir=1; - - /* intersect with ray going forward and backward*/ - hit= 0; - memset(&minisec, 0, sizeof(minisec)); - minco[0]= minco[1]= minco[2]= 0.0f; - - copy_v3_v3(bs->dir, shi->vn); - - for (sign=-1; sign<=1; sign+=2) { - memset(&isec, 0, sizeof(isec)); - isec.mode= RE_RAY_MIRROR; - - isec.orig.ob = obi; - isec.orig.face = vlr; - isec.userdata= bs->actob; - isec.check = RE_CHECK_VLR_BAKE; - isec.skip = RE_SKIP_VLR_NEIGHBOUR; - - if (bake_intersect_tree(R.raytree, &isec, shi->co, shi->vn, sign, co, &dist)) { - if (!hit || len_squared_v3v3(shi->co, co) < len_squared_v3v3(shi->co, minco)) { - minisec= isec; - mindist= dist; - copy_v3_v3(minco, co); - hit= 1; - dir = sign; - } - } - } - - if (bs->type==RE_BAKE_DISPLACEMENT) { - if (hit) - bake_displacement(handle, shi, (dir==-1)? mindist:-mindist, x, y); - else - bake_displacement(handle, shi, 0.0f, x, y); - return; - } - - /* if hit, we shade from the new point, otherwise from point one starting face */ - if (hit) { - obi = (ObjectInstanceRen *)minisec.hit.ob; - vlr = (VlakRen *)minisec.hit.face; - quad= (minisec.isect == 2); - copy_v3_v3(shi->co, minco); - - u= -minisec.u; - v= -minisec.v; - bake_set_shade_input(obi, vlr, shi, quad, 1, x, y, u, v); - } - } - - if (bs->type==RE_BAKE_NORMALS && R.r.bake_normal_space==R_BAKE_SPACE_TANGENT) - bake_shade(handle, ob, shi, quad, x, y, u, v, tvn, ttang); - else - bake_shade(handle, ob, shi, quad, x, y, u, v, 0, 0); -} - -static int get_next_bake_face(BakeShade *bs) -{ - ObjectRen *obr; - VlakRen *vlr; - MTFace *tface; - static int v= 0, vdone = FALSE; - static ObjectInstanceRen *obi= NULL; - - if (bs==NULL) { - vlr= NULL; - v= vdone = FALSE; - obi= R.instancetable.first; - return 0; - } - - BLI_lock_thread(LOCK_CUSTOM1); - - for (; obi; obi=obi->next, v=0) { - obr= obi->obr; - - for (; v<obr->totvlak; v++) { - vlr= RE_findOrAddVlak(obr, v); - - if ((bs->actob && bs->actob == obr->ob) || (!bs->actob && (obr->ob->flag & SELECT))) { - if(R.r.bake_flag & R_BAKE_VCOL) { - /* Gather face data for vertex colour bake */ - Mesh *me; - int *origindex, vcollayer; - CustomDataLayer *cdl; - - if(obr->ob->type != OB_MESH) - continue; - me = obr->ob->data; - - origindex = RE_vlakren_get_origindex(obr, vlr, 0); - if(origindex == NULL) - continue; - if (*origindex >= me->totpoly) { - /* Small hack for Array modifier, which gives false - original indices - z0r */ - continue; - } -#if 0 - /* Only shade selected faces. */ - if((me->mface[*origindex].flag & ME_FACE_SEL) == 0) - continue; -#endif - - vcollayer = CustomData_get_render_layer_index(&me->ldata, CD_MLOOPCOL); - if(vcollayer == -1) - continue; - - cdl = &me->ldata.layers[vcollayer]; - bs->mpoly = me->mpoly + *origindex; - bs->vcol = ((MLoopCol*)cdl->data) + bs->mpoly->loopstart; - bs->mloop = me->mloop + bs->mpoly->loopstart; - - /* Tag mesh for reevaluation. */ - DAG_id_tag_update(&me->id, 0); - } - else { - Image *ima = NULL; - ImBuf *ibuf = NULL; - const float vec_alpha[4]= {0.0f, 0.0f, 0.0f, 0.0f}; - const float vec_solid[4]= {0.0f, 0.0f, 0.0f, 1.0f}; - - tface= RE_vlakren_get_tface(obr, vlr, obr->bakemtface, NULL, 0); - - if (!tface || !tface->tpage) - continue; - - ima = tface->tpage; - ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); - - if (ibuf==NULL) - continue; - - if (ibuf->rect==NULL && ibuf->rect_float==NULL) { - BKE_image_release_ibuf(ima, ibuf, NULL); - continue; - } - - if (ibuf->rect_float && !(ibuf->channels==0 || ibuf->channels==4)) { - BKE_image_release_ibuf(ima, ibuf, NULL); - continue; - } - - if (ima->flag & IMA_USED_FOR_RENDER) { - ima->id.flag &= ~LIB_DOIT; - BKE_image_release_ibuf(ima, ibuf, NULL); - continue; - } - - /* find the image for the first time? */ - if (ima->id.flag & LIB_DOIT) { - ima->id.flag &= ~LIB_DOIT; - - /* we either fill in float or char, this ensures things go fine */ - if (ibuf->rect_float) - imb_freerectImBuf(ibuf); - /* clear image */ - if (R.r.bake_flag & R_BAKE_CLEAR) - IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? vec_alpha : vec_solid); - - /* might be read by UI to set active image for display */ - R.bakebuf= ima; - } - - /* Tag image for redraw. */ - ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; - BKE_image_release_ibuf(ima, ibuf, NULL); - } - - bs->obi = obi; - bs->vlr = vlr; - bs->vdone++; /* only for error message if nothing was rendered */ - v++; - BLI_unlock_thread(LOCK_CUSTOM1); - return 1; - } - } - } - - BLI_unlock_thread(LOCK_CUSTOM1); - return 0; -} - -static void bake_single_vertex(BakeShade *bs, VertRen *vert, float u, float v) -{ - int *origindex, i; - MLoopCol *basevcol; - MLoop *mloop; - - origindex = RE_vertren_get_origindex(bs->obi->obr, vert, 0); - if (!origindex || *origindex == ORIGINDEX_NONE) - return; - - /* Search for matching vertex index and apply shading. */ - for (i = 0; i < bs->mpoly->totloop; i++) { - mloop = bs->mloop + i; - if (mloop->v != *origindex) - continue; - basevcol = bs->vcol; - bs->vcol = basevcol + i; - do_bake_shade(bs, 0, 0, u, v); - bs->vcol = basevcol; - break; - } -} - -/* Bake all vertices of a face. Actually, this still works on a face-by-face - basis, and each vertex on each face is shaded. Vertex colors are a property - of loops, not vertices. */ -static void shade_verts(BakeShade *bs) -{ - VlakRen *vlr = bs->vlr; - - /* Disable baking to image; write to vcol instead. vcol pointer is set in - * bake_single_vertex. */ - bs->ima = NULL; - bs->rect = NULL; - bs->rect_float = NULL; - - bs->quad = 0; - - /* No anti-aliasing for vertices. */ - zero_v3(bs->dxco); - zero_v3(bs->dyco); - - /* Shade each vertex of the face. u and v are barycentric coordinates; since - we're only interested in vertices, these will be 0 or 1. */ - if ((vlr->flag & R_FACE_SPLIT) == 0) { - /* Processing triangle face, whole quad, or first half of split quad. */ - - bake_single_vertex(bs, bs->vlr->v1, 1.0f, 0.0f); - bake_single_vertex(bs, bs->vlr->v2, 0.0f, 1.0f); - bake_single_vertex(bs, bs->vlr->v3, 0.0f, 0.0f); - - if (vlr->v4) { - bs->quad = 1; - bake_single_vertex(bs, bs->vlr->v4, 0.0f, 0.0f); - } - } - else { - /* Processing second half of split quad. Only one vertex to go. */ - if (vlr->flag & R_DIVIDE_24) { - bake_single_vertex(bs, bs->vlr->v2, 0.0f, 1.0f); - } - else { - bake_single_vertex(bs, bs->vlr->v3, 0.0f, 0.0f); - } - } -} - -/* already have tested for tface and ima and zspan */ -static void shade_tface(BakeShade *bs) -{ - VlakRen *vlr= bs->vlr; - ObjectInstanceRen *obi= bs->obi; - ObjectRen *obr= obi->obr; - MTFace *tface= RE_vlakren_get_tface(obr, vlr, obr->bakemtface, NULL, 0); - Image *ima= tface->tpage; - float vec[4][2]; - int a, i1, i2, i3; - - /* check valid zspan */ - if (ima!=bs->ima) { - BKE_image_release_ibuf(bs->ima, bs->ibuf, NULL); - - bs->ima= ima; - bs->ibuf= BKE_image_acquire_ibuf(ima, NULL, NULL); - /* note, these calls only free/fill contents of zspan struct, not zspan itself */ - zbuf_free_span(bs->zspan); - zbuf_alloc_span(bs->zspan, bs->ibuf->x, bs->ibuf->y, R.clipcrop); - } - - bs->rectx= bs->ibuf->x; - bs->recty= bs->ibuf->y; - bs->rect= bs->ibuf->rect; - bs->rect_colorspace= bs->ibuf->rect_colorspace; - bs->rect_float= bs->ibuf->rect_float; - bs->vcol = NULL; - bs->quad= 0; - - if (bs->use_mask) { - if (bs->ibuf->userdata==NULL) { - BLI_lock_thread(LOCK_CUSTOM1); - if (bs->ibuf->userdata==NULL) /* since the thread was locked, its possible another thread alloced the value */ - bs->ibuf->userdata = (void *)MEM_callocN(sizeof(char)*bs->rectx*bs->recty, "BakeMask"); - bs->rect_mask= (char *)bs->ibuf->userdata; - BLI_unlock_thread(LOCK_CUSTOM1); - } - else { - bs->rect_mask= (char *)bs->ibuf->userdata; - } - } - - /* get pixel level vertex coordinates */ - for (a=0; a<4; a++) { - /* Note, workaround for pixel aligned UVs which are common and can screw up our intersection tests - * where a pixel gets in between 2 faces or the middle of a quad, - * camera aligned quads also have this problem but they are less common. - * Add a small offset to the UVs, fixes bug #18685 - Campbell */ - vec[a][0]= tface->uv[a][0]*(float)bs->rectx - (0.5f + 0.001f); - vec[a][1]= tface->uv[a][1]*(float)bs->recty - (0.5f + 0.002f); - } - - /* UV indices have to be corrected for possible quad->tria splits */ - i1= 0; i2= 1; i3= 2; - vlr_set_uv_indices(vlr, &i1, &i2, &i3); - bake_set_vlr_dxyco(bs, vec[i1], vec[i2], vec[i3]); - zspan_scanconvert(bs->zspan, bs, vec[i1], vec[i2], vec[i3], do_bake_shade); - - if (vlr->v4) { - bs->quad= 1; - bake_set_vlr_dxyco(bs, vec[0], vec[2], vec[3]); - zspan_scanconvert(bs->zspan, bs, vec[0], vec[2], vec[3], do_bake_shade); - } -} - -static void *do_bake_thread(void *bs_v) -{ - BakeShade *bs= bs_v; - - while (get_next_bake_face(bs)) { - if (R.r.bake_flag & R_BAKE_VCOL) - shade_verts(bs); - else - shade_tface(bs); - - /* fast threadsafe break test */ - if (R.test_break(R.tbh)) - break; - - /* access is not threadsafe but since its just true/false probably ok - * only used for interactive baking */ - if (bs->do_update) - *bs->do_update= TRUE; - } - bs->ready= 1; - - BKE_image_release_ibuf(bs->ima, bs->ibuf, NULL); - - return NULL; -} - -void RE_bake_ibuf_filter(ImBuf *ibuf, char *mask, const int filter) -{ - /* must check before filtering */ - const short is_new_alpha= (ibuf->planes != R_IMF_PLANES_RGBA) && BKE_imbuf_alpha_test(ibuf); - - /* Margin */ - if (filter) { - IMB_filter_extend(ibuf, mask, filter); - } - - /* if the bake results in new alpha then change the image setting */ - if (is_new_alpha) { - ibuf->planes= R_IMF_PLANES_RGBA; - } - else { - if (filter && ibuf->planes != R_IMF_PLANES_RGBA) { - /* clear alpha added by filtering */ - IMB_rectfill_alpha(ibuf, 1.0f); - } - } -} - -/* using object selection tags, the faces with UV maps get baked */ -/* render should have been setup */ -/* returns 0 if nothing was handled */ -int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_update, float *progress) -{ - BakeShade *handles; - ListBase threads; - Image *ima; - int a, vdone = FALSE, use_mask = FALSE, result = BAKE_RESULT_OK; - - re->scene_color_manage = BKE_scene_check_color_management_enabled(re->scene); - - /* initialize render global */ - R= *re; - R.bakebuf= NULL; - - /* initialize static vars */ - get_next_bake_face(NULL); - - /* do we need a mask? */ - if (re->r.bake_filter) - use_mask = TRUE; - - /* baker uses this flag to detect if image was initialized */ - if ((R.r.bake_flag & R_BAKE_VCOL) == 0) { - for (ima = G.main->image.first; ima; ima = ima->id.next) { - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); - ima->id.flag |= LIB_DOIT; - ima->flag &= ~IMA_USED_FOR_RENDER; - if (ibuf) { - ibuf->userdata = NULL; /* use for masking if needed */ - } - BKE_image_release_ibuf(ima, ibuf, NULL); - } - } - - BLI_init_threads(&threads, do_bake_thread, re->r.threads); - - handles= MEM_callocN(sizeof(BakeShade)*re->r.threads, "BakeShade"); - - /* get the threads running */ - for (a=0; a<re->r.threads; a++) { - /* set defaults in handles */ - handles[a].ssamp.shi[0].lay= re->lay; - - if (type==RE_BAKE_SHADOW) { - handles[a].ssamp.shi[0].passflag= SCE_PASS_SHADOW; - } - else { - handles[a].ssamp.shi[0].passflag= SCE_PASS_COMBINED; - } - handles[a].ssamp.shi[0].combinedflag= ~(SCE_PASS_SPEC); - handles[a].ssamp.shi[0].thread= a; - handles[a].ssamp.tot= 1; - - handles[a].type= type; - handles[a].actob= actob; - if (R.r.bake_flag & R_BAKE_VCOL) - handles[a].zspan = NULL; - else - handles[a].zspan = MEM_callocN(sizeof(ZSpan), "zspan for bake"); - - handles[a].use_mask = use_mask; - - handles[a].do_update = do_update; /* use to tell the view to update */ - - BLI_insert_thread(&threads, &handles[a]); - } - - /* wait for everything to be done */ - a= 0; - while (a!=re->r.threads) { - PIL_sleep_ms(50); - - /* calculate progress */ - for (vdone = FALSE, a=0; a<re->r.threads; a++) - vdone+= handles[a].vdone; - if (progress) - *progress = (float)(vdone / (float)re->totvlak); - - for (a=0; a<re->r.threads; a++) { - if (handles[a].ready==0) - break; - } - } - - /* filter and refresh images */ - if ((R.r.bake_flag & R_BAKE_VCOL) == 0) { - for (ima = G.main->image.first; ima; ima = ima->id.next) { - if ((ima->id.flag & LIB_DOIT)==0) { - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); - - if (ima->flag & IMA_USED_FOR_RENDER) - result = BAKE_RESULT_FEEDBACK_LOOP; - - if (!ibuf) - continue; - - RE_bake_ibuf_filter(ibuf, (char *)ibuf->userdata, re->r.bake_filter); - - ibuf->userflags |= IB_BITMAPDIRTY; - BKE_image_release_ibuf(ima, ibuf, NULL); - } - } - - /* calculate return value */ - for (a = 0; a < re->r.threads; a++) { - zbuf_free_span(handles[a].zspan); - MEM_freeN(handles[a].zspan); - } - } - - MEM_freeN(handles); - - BLI_end_threads(&threads); - - if (vdone==0) - result= BAKE_RESULT_NO_OBJECTS; - - return result; -} - -struct Image *RE_bake_shade_get_image(void) -{ - return R.bakebuf; -} diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c index 7ca4f01ae47..b25f2f4201a 100644 --- a/source/blender/render/intern/source/renderdatabase.c +++ b/source/blender/render/intern/source/renderdatabase.c @@ -1051,7 +1051,7 @@ HaloRen *RE_inithalo(Render *re, ObjectRen *obr, Material *ma, } } - externtex(mtex, texvec, &tin, &tr, &tg, &tb, &ta, 0); + externtex(mtex, texvec, &tin, &tr, &tg, &tb, &ta, 0, re->pool); yn= tin*mtex->colfac; //zn= tin*mtex->alphafac; @@ -1070,6 +1070,8 @@ HaloRen *RE_inithalo(Render *re, ObjectRen *obr, Material *ma, } } + har->pool = re->pool; + return har; } @@ -1180,7 +1182,7 @@ HaloRen *RE_inithalo_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Mater copy_v3_v3(texvec, orco); } - hasrgb = externtex(mtex, texvec, &tin, &tr, &tg, &tb, &ta, 0); + hasrgb = externtex(mtex, texvec, &tin, &tr, &tg, &tb, &ta, 0, re->pool); //yn= tin*mtex->colfac; //zn= tin*mtex->alphafac; @@ -1223,6 +1225,8 @@ HaloRen *RE_inithalo_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Mater //} } + har->pool = re->pool; + return har; } diff --git a/source/blender/render/intern/source/shadbuf.c b/source/blender/render/intern/source/shadbuf.c index 87912f546e8..1a24055c7f4 100644 --- a/source/blender/render/intern/source/shadbuf.c +++ b/source/blender/render/intern/source/shadbuf.c @@ -38,10 +38,6 @@ #include "DNA_lamp_types.h" #include "DNA_material_types.h" -#include "BKE_global.h" -#include "BKE_scene.h" - - #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_jitter.h" @@ -49,6 +45,9 @@ #include "BLI_rand.h" #include "BLI_utildefines.h" +#include "BKE_global.h" +#include "BKE_scene.h" + #include "PIL_time.h" #include "renderpipeline.h" diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c index db93a21de2d..bf0087d0292 100644 --- a/source/blender/render/intern/source/shadeinput.c +++ b/source/blender/render/intern/source/shadeinput.c @@ -151,6 +151,7 @@ void shade_material_loop(ShadeInput *shi, ShadeResult *shr) /* do a shade, finish up some passes, apply mist */ void shade_input_do_shade(ShadeInput *shi, ShadeResult *shr) { + bool compat = false; float alpha; /* ------ main shading loop -------- */ @@ -158,10 +159,11 @@ void shade_input_do_shade(ShadeInput *shi, ShadeResult *shr) memset(&shi->raycounter, 0, sizeof(shi->raycounter)); #endif - if (shi->mat->nodetree && shi->mat->use_nodes) { - ntreeShaderExecTree(shi->mat->nodetree, shi, shr); - } - else { + if (shi->mat->nodetree && shi->mat->use_nodes) + compat = ntreeShaderExecTree(shi->mat->nodetree, shi, shr); + + /* also run this when node shaders fail, due to incompatible shader nodes */ + if (compat == false) { /* copy all relevant material vars, note, keep this synced with render_types.h */ shade_input_init_material(shi); |