doxygen: prevent GPL license block from being parsed as doxygen comment.
[blender.git] / source / blender / render / intern / source / rendercore.c
index 6c18592..2901573 100644 (file)
@@ -1,4 +1,4 @@
-/**
+/*
  * $Id$
  *
  * ***** BEGIN GPL LICENSE BLOCK *****
@@ -15,7 +15,7 @@
  *
  * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * 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.
 /* External modules: */
 #include "MEM_guardedalloc.h"
 
-#include "BLI_arithb.h"
+#include "BLI_math.h"
 #include "BLI_blenlib.h"
 #include "BLI_jitter.h"
 #include "BLI_rand.h"
 #include "BLI_threads.h"
+#include "BLI_utildefines.h"
+
 
-#include "BKE_utildefines.h"
 
 #include "DNA_image_types.h"
 #include "DNA_lamp_types.h"
@@ -60,6 +61,8 @@
 #include "IMB_imbuf.h"
 
 /* local include */
+#include "rayintersection.h"
+#include "rayobject.h"
 #include "renderpipeline.h"
 #include "render_types.h"
 #include "renderdatabase.h"
@@ -70,7 +73,6 @@
 #include "shading.h"
 #include "sss.h"
 #include "zbuf.h"
-#include "RE_raytrace.h"
 
 #include "PIL_time.h"
 
@@ -96,8 +98,9 @@ void calc_view_vector(float *view, float x, float y)
        }
        else {
                
-               if(R.r.mode & R_PANORAMA)
+               if(R.r.mode & R_PANORAMA) {
                        x-= R.panodxp;
+               }
                
                /* move x and y to real viewplane coords */
                x= (x/(float)R.winx);
@@ -459,6 +462,9 @@ static void add_filt_passes(RenderLayer *rl, int curmask, int rectx, int offset,
                                col= shr->col;
                                pixsize= 4;
                                break;
+                       case SCE_PASS_EMIT:
+                               col= shr->emit;
+                               break;
                        case SCE_PASS_DIFFUSE:
                                col= shr->diff;
                                break;
@@ -471,15 +477,18 @@ static void add_filt_passes(RenderLayer *rl, int curmask, int rectx, int offset,
                        case SCE_PASS_AO:
                                col= shr->ao;
                                break;
+                       case SCE_PASS_ENVIRONMENT:
+                               col= shr->env;
+                               break;
+                       case SCE_PASS_INDIRECT:
+                               col= shr->indirect;
+                               break;
                        case SCE_PASS_REFLECT:
                                col= shr->refl;
                                break;
                        case SCE_PASS_REFRACT:
                                col= shr->refr;
                                break;
-                       case SCE_PASS_RADIO:
-                               col= NULL; // removed shr->rad;
-                               break;
                        case SCE_PASS_NORMAL:
                                col= shr->nor;
                                break;
@@ -557,6 +566,9 @@ static void add_passes(RenderLayer *rl, int offset, ShadeInput *shi, ShadeResult
                                col= shr->col;
                                pixsize= 4;
                                break;
+                       case SCE_PASS_EMIT:
+                               col= shr->emit;
+                               break;
                        case SCE_PASS_DIFFUSE:
                                col= shr->diff;
                                break;
@@ -569,15 +581,18 @@ static void add_passes(RenderLayer *rl, int offset, ShadeInput *shi, ShadeResult
                        case SCE_PASS_AO:
                                col= shr->ao;
                                break;
+                       case SCE_PASS_ENVIRONMENT:
+                               col= shr->env;
+                               break;
+                       case SCE_PASS_INDIRECT:
+                               col= shr->indirect;
+                               break;
                        case SCE_PASS_REFLECT:
                                col= shr->refl;
                                break;
                        case SCE_PASS_REFRACT:
                                col= shr->refr;
                                break;
-                       case SCE_PASS_RADIO:
-                               col= NULL; // removed shr->rad;
-                               break;
                        case SCE_PASS_NORMAL:
                                col= shr->nor;
                                break;
@@ -727,10 +742,15 @@ static void atm_tile(RenderPart *pa, RenderLayer *rl)
                                                if(*zrect >= 9.9e10 || rgbrect[3]==0.0f) {
                                                        continue;
                                                }
-                                               
+                                                                                               
                                                if((lar->sunsky->effect_type & LA_SUN_EFFECT_AP)) {     
                                                        float tmp_rgb[3];
                                                        
+                                                       /* skip if worldspace lamp vector is below horizon */
+                                                       if(go->ob->obmat[2][2] < 0.f) {
+                                                               continue;
+                                                       }
+                                                       
                                                        VECCOPY(tmp_rgb, rgbrect);
                                                        if(rgbrect[3]!=1.0f) {  /* de-premul */
                                                                float div= 1.0f/rgbrect[3];
@@ -1016,7 +1036,7 @@ void edge_enhance_tile(RenderPart *pa, float *rectf, int *rectz)
 static void reset_sky_speed(RenderPart *pa, RenderLayer *rl)
 {
        /* for all pixels with max speed, set to zero */
-    RenderLayer *rlpp[RE_MAX_OSA];
+       RenderLayer *rlpp[RE_MAX_OSA];
        float *fp;
        int a, sample, totsample;
        
@@ -1033,9 +1053,9 @@ static void reset_sky_speed(RenderPart *pa, RenderLayer *rl)
 
 static unsigned short *make_solid_mask(RenderPart *pa)
 { 
-       intptr_t *rd= pa->rectdaps;
-       unsigned short *solidmask, *sp;
-       int x;
+        intptr_t *rd= pa->rectdaps;
+        unsigned short *solidmask, *sp;
+        int x;
        
        if(rd==NULL) return NULL;
        
@@ -1080,7 +1100,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];
@@ -1291,7 +1311,7 @@ void zbufshade_tile(RenderPart *pa)
                
                zbuffer_solid(pa, rl, NULL, NULL);
                
-               if(!R.test_break(R.tbh)) {      /* NOTE: this if() is not consistant */
+               if(!R.test_break(R.tbh)) {      /* NOTE: this if() is not consistent */
                        
                        /* edges only for solid part, ztransp doesn't support it yet anti-aliased */
                        if(rl->layflag & SCE_LAY_EDGE) {
@@ -1498,13 +1518,13 @@ static void shade_sample_sss(ShadeSample *ssamp, Material *mat, ObjectInstanceRe
 
        VECCOPY(nor, shi->facenor);
        calc_view_vector(shi->facenor, sx, sy);
-       Normalize(shi->facenor);
+       normalize_v3(shi->facenor);
        shade_input_set_viewco(shi, x, y, sx, sy, z);
-       orthoarea= VecLength(shi->dxco)*VecLength(shi->dyco);
+       orthoarea= len_v3(shi->dxco)*len_v3(shi->dyco);
 
        VECCOPY(shi->facenor, nor);
        shade_input_set_viewco(shi, x, y, sx, sy, z);
-       *area= VecLength(shi->dxco)*VecLength(shi->dyco);
+       *area= len_v3(shi->dxco)*len_v3(shi->dyco);
        *area= MIN2(*area, 2.0f*orthoarea);
 
        shade_input_set_uv(shi);
@@ -1516,8 +1536,8 @@ static void shade_sample_sss(ShadeSample *ssamp, Material *mat, ObjectInstanceRe
 
        /* not a pretty solution, but fixes common cases */
        if(shi->obr->ob && shi->obr->ob->transflag & OB_NEG_SCALE) {
-               VecNegf(shi->vn);
-               VecNegf(shi->vno);
+               negate_v3(shi->vn);
+               negate_v3(shi->vno);
        }
 
        /* if nodetree, use the material that we are currently preprocessing
@@ -1988,6 +2008,8 @@ typedef struct BakeShade {
        char *rect_mask; /* bake pixel mask */
 
        float dxco[3], dyco[3];
+
+       short *do_update;
 } BakeShade;
 
 /* bake uses a char mask to know what has been baked */
@@ -2060,24 +2082,10 @@ static void bake_mask_clear( ImBuf *ibuf, char *mask, char val )
 
 static void bake_set_shade_input(ObjectInstanceRen *obi, VlakRen *vlr, ShadeInput *shi, int quad, int isect, int x, int y, float u, float v)
 {
-       if(isect) {
-               /* raytrace intersection with different u,v than scanconvert */
-               if(vlr->v4) {
-                       if(quad)
-                               shade_input_set_triangle_i(shi, obi, vlr, 2, 1, 3);
-                       else
-                               shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 3);
-               }
-               else
-                       shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2);
-       }
-       else {
-               /* regular scanconvert */
-               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);
-       }
+       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]++;
@@ -2115,10 +2123,13 @@ static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int quad, int
        if(bs->type==RE_BAKE_AO) {
                ambient_occlusion(shi);
 
-               if(R.r.bake_flag & R_BAKE_NORMALIZE)
-                       VECCOPY(shr.combined, shi->ao)
-               else
-                       ambient_occlusion_to_diffuse(shi, shr.combined);
+               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 */
@@ -2148,24 +2159,26 @@ static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int quad, int
                                /* bitangent */
                                if(tvn && ttang) {
                                        VECCOPY(mat[0], ttang);
-                                       Crossf(mat[1], tvn, ttang);
+                                       cross_v3_v3v3(mat[1], tvn, ttang);
+                                       mul_v3_fl(mat[1], ttang[3]);
                                        VECCOPY(mat[2], tvn);
                                }
                                else {
                                        VECCOPY(mat[0], shi->nmaptang);
-                                       Crossf(mat[1], shi->vn, shi->nmaptang);
-                                       VECCOPY(mat[2], shi->vn);
+                                       cross_v3_v3v3(mat[1], shi->nmapnorm, shi->nmaptang);
+                                       mul_v3_fl(mat[1], shi->nmaptang[3]);
+                                       VECCOPY(mat[2], shi->nmapnorm);
                                }
 
-                               Mat3Inv(imat, mat);
-                               Mat3MulVecfl(imat, nor);
+                               invert_m3_m3(imat, mat);
+                               mul_m3_v3(imat, nor);
                        }
                        else if(R.r.bake_normal_space == R_BAKE_SPACE_OBJECT)
-                               Mat4Mul3Vecfl(ob->imat, nor); /* ob->imat includes viewinv! */
+                               mul_mat3_m4_v3(ob->imat, nor); /* ob->imat includes viewinv! */
                        else if(R.r.bake_normal_space == R_BAKE_SPACE_WORLD)
-                               Mat4Mul3Vecfl(R.viewinv, nor);
+                               mul_mat3_m4_v3(R.viewinv, nor);
 
-                       Normalize(nor); /* in case object has scaling */
+                       normalize_v3(nor); /* in case object has scaling */
 
                        shr.combined[0]= nor[0]/2.0f + 0.5f;
                        shr.combined[1]= 0.5f - nor[1]/2.0f;
@@ -2194,12 +2207,23 @@ static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int quad, int
        }
        else {
                char *col= (char *)(bs->rect + bs->rectx*y + x);
-               col[0]= FTOCHAR(shr.combined[0]);
-               col[1]= FTOCHAR(shr.combined[1]);
-               col[2]= FTOCHAR(shr.combined[2]);
-               
+
+               if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE) &&     (R.r.color_mgt_flag & R_COLOR_MANAGEMENT)) {
+                       float srgb[3];
+                       srgb[0]= linearrgb_to_srgb(shr.combined[0]);
+                       srgb[1]= linearrgb_to_srgb(shr.combined[1]);
+                       srgb[2]= linearrgb_to_srgb(shr.combined[2]);
+                       
+                       col[0]= FTOCHAR(srgb[0]);
+                       col[1]= FTOCHAR(srgb[1]);
+                       col[2]= FTOCHAR(srgb[2]);
+               } else {
+                       col[0]= FTOCHAR(shr.combined[0]);
+                       col[1]= FTOCHAR(shr.combined[1]);
+                       col[2]= FTOCHAR(shr.combined[2]);
+               }
                
-               if (bs->type==RE_BAKE_ALL || bs->type==RE_BAKE_TEXTURE) {
+               if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE)) {
                        col[3]= FTOCHAR(shr.alpha);
                } else {
                        col[3]= 255;
@@ -2238,23 +2262,8 @@ static void bake_displacement(void *handle, ShadeInput *shi, float dist, int x,
        }
 }
 
-#if 0
-static int bake_check_intersect(Isect *is, int ob, RayFace *face)
-{
-       BakeShade *bs = (BakeShade*)is->userdata;
-       
-       /* no direction checking for now, doesn't always improve the result
-        * (INPR(shi->facenor, bs->dir) > 0.0f); */
-
-       return (R.objectinstance[ob & ~RE_RAY_TRANSFORM_OFFS].obr->ob != bs->actob);
-}
-#endif
-
 static int bake_intersect_tree(RayObject* raytree, Isect* isect, float *start, float *dir, float sign, float *hitco, float *dist)
 {
-       //TODO
-       assert( 0 );
-#if 0
        float maxdist;
        int hit;
 
@@ -2262,28 +2271,27 @@ static int bake_intersect_tree(RayObject* raytree, Isect* isect, float *start, f
        if(R.r.bake_maxdist > 0.0f)
                maxdist= R.r.bake_maxdist;
        else
-               maxdist= FLT_MAX + R.r.bake_biasdist;
+               maxdist= RE_RAYTRACE_MAXDIST + R.r.bake_biasdist;
        
-       //TODO normalized direction?
-       VECADDFAC(isect->start, start, dir, -R.r.bake_biasdist);
+       /* 'dir' is always normalized */
+       VECADDFAC(isect->start, start, dir, -R.r.bake_biasdist);                                        
+
        isect->dir[0] = dir[0]*sign;
        isect->dir[1] = dir[1]*sign;
        isect->dir[2] = dir[2]*sign;
-       isect->labda = maxdist;
+
+       isect->dist = maxdist;
 
        hit = RE_rayobject_raycast(raytree, isect);
-       //TODO bake_check_intersect
        if(hit) {
-               hitco[0] = isect->start[0] + isect->labda*isect->vec[0];
-               hitco[1] = isect->start[1] + isect->labda*isect->vec[1];
-               hitco[2] = isect->start[2] + isect->labda*isect->vec[2];
+               hitco[0] = isect->start[0] + isect->dist*isect->dir[0];
+               hitco[1] = isect->start[1] + isect->dist*isect->dir[1];
+               hitco[2] = isect->start[2] + isect->dist*isect->dir[2];
 
-               *dist= VecLenf(start, hitco);
+               *dist= isect->dist;
        }
 
        return hit;
-#endif
-       return 0;
 }
 
 static void bake_set_vlr_dxyco(BakeShade *bs, float *uv1, float *uv2, float *uv3)
@@ -2330,8 +2338,8 @@ static void bake_set_vlr_dxyco(BakeShade *bs, float *uv1, float *uv2, float *uv3
        }
 
        if(bs->obi->flag & R_TRANSFORMED) {
-               Mat3MulVecfl(bs->obi->nmat, bs->dxco);
-               Mat3MulVecfl(bs->obi->nmat, bs->dyco);
+               mul_m3_v3(bs->obi->nmat, bs->dxco);
+               mul_m3_v3(bs->obi->nmat, bs->dyco);
        }
 }
 
@@ -2341,7 +2349,7 @@ static void do_bake_shade(void *handle, int x, int y, float u, float v)
        VlakRen *vlr= bs->vlr;
        ObjectInstanceRen *obi= bs->obi;
        Object *ob= obi->obr->ob;
-       float l, *v1, *v2, *v3, tvn[3], ttang[3];
+       float l, *v1, *v2, *v3, tvn[3], ttang[4];
        int quad;
        ShadeSample *ssamp= &bs->ssamp;
        ShadeInput *shi= ssamp->shi;
@@ -2370,7 +2378,7 @@ static void do_bake_shade(void *handle, int x, int y, float u, float v)
        shi->co[2]= l*v3[2]+u*v1[2]+v*v2[2];
        
        if(obi->flag & R_TRANSFORMED)
-               Mat4MulVecfl(obi->mat, shi->co);
+               mul_m4_v3(obi->mat, shi->co);
        
        VECCOPY(shi->dxco, bs->dxco);
        VECCOPY(shi->dyco, bs->dyco);
@@ -2380,8 +2388,8 @@ static void do_bake_shade(void *handle, int x, int y, float u, float v)
 
        if(bs->type==RE_BAKE_NORMALS && R.r.bake_normal_space==R_BAKE_SPACE_TANGENT) {
                shade_input_set_shade_texco(shi);
-               VECCOPY(tvn, shi->vn);
-               VECCOPY(ttang, shi->nmaptang);
+               VECCOPY(tvn, shi->nmapnorm);
+               QUATCOPY(ttang, shi->nmaptang);
        }
 
        /* if we are doing selected to active baking, find point on other face */
@@ -2403,10 +2411,12 @@ static void do_bake_shade(void *handle, int x, int y, float u, float v)
 
                        isec.orig.ob   = obi;
                        isec.orig.face = vlr;
-                       isec.userdata= bs;
+                       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 || VecLenf(shi->co, co) < VecLenf(shi->co, minco)) {
+                               if(!hit || len_v3v3(shi->co, co) < len_v3v3(shi->co, minco)) {
                                        minisec= isec;
                                        mindist= dist;
                                        VECCOPY(minco, co);
@@ -2544,10 +2554,9 @@ static void shade_tface(BakeShade *bs)
        if (bs->usemask) {
                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 */
+                       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;
-                       }
+                       bs->rect_mask= (char *)bs->ibuf->userdata;
                        BLI_unlock_thread(LOCK_CUSTOM1);
                } else {
                        bs->rect_mask= (char *)bs->ibuf->userdata;
@@ -2557,7 +2566,7 @@ static void shade_tface(BakeShade *bs)
        /* 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 inbetween 2 faces or the middle of a quad,
+                * 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.001);
@@ -2587,6 +2596,11 @@ static void *do_bake_thread(void *bs_v)
                /* 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;
        
@@ -2596,9 +2610,9 @@ static void *do_bake_thread(void *bs_v)
 /* 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)
+int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_update, float *progress)
 {
-       BakeShade handles[BLENDER_MAX_THREADS];
+       BakeShade *handles;
        ListBase threads;
        Image *ima;
        int a, vdone=0, usemask=0;
@@ -2611,25 +2625,28 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob)
        get_next_bake_face(NULL);
        
        /* do we need a mask? */
-       if (re->r.bake_filter && (re->r.bake_flag & R_BAKE_CLEAR)==0)
+       if (re->r.bake_filter)
                usemask = 1;
        
        /* baker uses this flag to detect if image was initialized */
        for(ima= G.main->image.first; ima; ima= ima->id.next) {
                ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
                ima->id.flag |= LIB_DOIT;
-               if (ibuf)
+               if(ibuf) {
                        ibuf->userdata = NULL; /* use for masking if needed */
+                       if(ibuf->rect_float)
+                               ibuf->profile = IB_PROFILE_LINEAR_RGB;
+               }
        }
        
        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 */
-               memset(&handles[a], 0, sizeof(BakeShade));
-               
-               handles[a].ssamp.shi[0].lay= re->scene->lay;
+               handles[a].ssamp.shi[0].lay= re->lay;
                
                if (type==RE_BAKE_SHADOW) {
                        handles[a].ssamp.shi[0].passflag= SCE_PASS_SHADOW;
@@ -2645,6 +2662,8 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob)
                handles[a].zspan= MEM_callocN(sizeof(ZSpan), "zspan for bake");
                
                handles[a].usemask = usemask;
+
+               handles[a].do_update = do_update; /* use to tell the view to update */
                
                BLI_insert_thread(&threads, &handles[a]);
        }
@@ -2652,19 +2671,29 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob)
        /* wait for everything to be done */
        a= 0;
        while(a!=re->r.threads) {
-               
                PIL_sleep_ms(50);
 
-               for(a=0; a<re->r.threads; a++)
+               /* calculate progress */
+               for(vdone=0, 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 */
        for(ima= G.main->image.first; ima; ima= ima->id.next) {
                if((ima->id.flag & LIB_DOIT)==0) {
                        ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
-                       if (re->r.bake_filter) {
+
+                       if(!ibuf)
+                               continue;
+
+                       if(re->r.bake_filter) {
                                if (usemask) {
                                        /* extend the mask +2 pixels from the image,
                                         * this is so colors dont blend in from outside */
@@ -2694,20 +2723,22 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob)
                                        ibuf->userdata= NULL;
                                }
                        }
+
                        ibuf->userflags |= IB_BITMAPDIRTY;
                        if (ibuf->rect_float) IMB_rect_from_float(ibuf);
                }
        }
        
        /* calculate return value */
-       for(a=0; a<re->r.threads; a++) {
-               vdone+= handles[a].vdone;
-               
+       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);
+
        return vdone;
 }