* First commit merging 2.4-based sim_physics in to volume25 branch.
[blender-staging.git] / source / blender / render / intern / source / texture.c
index 5df814358d571a3bd3906dcaa0285298595afaaf..27cf698aabe25083957b2ea60e3b8051ca3ee25a 100644 (file)
@@ -48,6 +48,7 @@
 #include "IMB_imbuf_types.h"
 #include "IMB_imbuf.h"
 
+#include "BKE_colortools.h"
 #include "BKE_image.h"
 #include "BKE_node.h"
 #include "BKE_plugin_types.h"
@@ -72,6 +73,8 @@
 #include "shading.h"
 #include "texture.h"
 
+#include "renderdatabase.h" /* needed for UV */
+
 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 /* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
 /* only to be used here in this file, it's for speed */
@@ -81,11 +84,9 @@ extern struct Render R;
 
 
 
-/* note; this is called WITH RENDER IS NULL in src/drawview.c for animated 
-   background image, option should move to kernel */
 void init_render_texture(Render *re, Tex *tex)
 {
-       int cfra= G.scene->r.cfra;
+       int cfra= re->scene->r.cfra;
        
        if(re) cfra= re->r.cfra;
        
@@ -97,7 +98,7 @@ void init_render_texture(Render *re, Tex *tex)
        if(tex->type==TEX_PLUGIN) {
                if(tex->plugin && tex->plugin->doit) {
                        if(tex->plugin->cfra) {
-                               *(tex->plugin->cfra)= frame_to_float(cfra); 
+                               *(tex->plugin->cfra)= (float)cfra; //frame_to_float(re->scene, cfra); // XXX old animsys - timing stuff to be fixed 
                        }
                }
        }
@@ -197,23 +198,6 @@ static int blend(Tex *tex, float *texvec, TexResult *texres)
                y= texvec[1];
        }
 
-       if (tex->extend == TEX_REPEAT) {
-               if (x < -1.0 || x > 1.0) {
-                       const float x2 = (x + 1.0)* 0.5;                        /* to 0.0, 1.0 */
-                       x = (x2 - floor(x2) - 0.5) * 2.0;       /* to -1.0, 1.0 */
-               }
-               if (y < -1.0 || y > 1.0) {
-                       const float y2 = (y + 1.0)* 0.5;                        /* to 0.0, 1.0 */
-                       y = (y2 - floor(y2) - 0.5) * 2.0;       /* to -1.0, 1.0 */
-               }
-       } else if (tex->extend == TEX_CLIP) {
-               if (x < -1.0 || x > 1.0 || y < -1.0 || y > 1.0) {
-                       texres->tin = 0.f;
-                       BRICONT;
-                       return TEX_INT;
-               }
-       }
-
        if(tex->stype==TEX_LIN) {       /* lin */
                texres->tin= (1.0+x)/2.0;
        }
@@ -737,7 +721,7 @@ static int evalnodes(Tex *tex, float *texvec, TexResult *texres, short thread, s
        short rv = TEX_INT;
        bNodeTree *nodes = tex->nodetree;
        
-       ntreeTexExecTree(nodes, texres, texvec, 0, thread, tex, which_output);
+       ntreeTexExecTree(nodes, texres, texvec, 0, thread, tex, which_output, R.r.cfra);
        
        if(texres->nor) rv |= TEX_NOR;
        rv |= TEX_RGB;
@@ -1004,7 +988,7 @@ static void do_2d_mapping(MTex *mtex, float *t, VlakRen *vlr, float *n, float *d
                                
                                if(tex->flag & TEX_REPEAT_XMIR) {
                                        int orig= (int)floor(origf);
-                                       if(orig & 1) 
+                                       if(orig & 1)
                                                fx= 1.0-fx;
                                }
                        }
@@ -1097,13 +1081,15 @@ static void do_2d_mapping(MTex *mtex, float *t, VlakRen *vlr, float *n, float *d
                                dxt[2]= f1;
                                dyt[2]= f2;
                        }
-                       dxt[0]/= 2.0; 
-                       dxt[1]/= 2.0;
-                       dxt[2]/= 2.0;
-                       
-                       dyt[0]/= 2.0; 
-                       dyt[1]/= 2.0;
-                       dyt[2]/= 2.0;
+
+                       dxt[0] *= 0.5f;
+                       dxt[1] *= 0.5f;
+                       dxt[2] *= 0.5f;
+
+                       dyt[0] *= 0.5f;
+                       dyt[1] *= 0.5f;
+                       dyt[2] *= 0.5f;
+
                }
                
                /* if area, then reacalculate dxt[] and dyt[] */
@@ -1122,13 +1108,16 @@ static void do_2d_mapping(MTex *mtex, float *t, VlakRen *vlr, float *n, float *d
                        if(tex->xrepeat>1) {
                                float origf= fx *= tex->xrepeat;
                                
-                               if(fx>1.0f) fx -= (int)(fx);
-                               else if(fx<0.0f) fx+= 1-(int)(fx);
+                               // TXF: omit mirror here, see comments in do_material_tex() after do_2d_mapping() call
+                               if (tex->texfilter == TXF_BOX) {
+                                       if(fx>1.0f) fx -= (int)(fx);
+                                       else if(fx<0.0f) fx+= 1-(int)(fx);
                                
-                               if(tex->flag & TEX_REPEAT_XMIR) {
-                                       int orig= (int)floor(origf);
-                                       if(orig & 1) 
-                                               fx= 1.0f-fx;
+                                       if(tex->flag & TEX_REPEAT_XMIR) {
+                                               int orig= (int)floor(origf);
+                                               if(orig & 1) 
+                                                       fx= 1.0f-fx;
+                                       }
                                }
                                
                                max= tex->xrepeat;
@@ -1139,13 +1128,16 @@ static void do_2d_mapping(MTex *mtex, float *t, VlakRen *vlr, float *n, float *d
                        if(tex->yrepeat>1) {
                                float origf= fy *= tex->yrepeat;
                                
-                               if(fy>1.0f) fy -= (int)(fy);
-                               else if(fy<0.0f) fy+= 1-(int)(fy);
+                               // TXF: omit mirror here, see comments in do_material_tex() after do_2d_mapping() call
+                               if (tex->texfilter == TXF_BOX) {
+                                       if(fy>1.0f) fy -= (int)(fy);
+                                       else if(fy<0.0f) fy+= 1-(int)(fy);
                                
-                               if(tex->flag & TEX_REPEAT_YMIR) {
-                                       int orig= (int)floor(origf);
-                                       if(orig & 1) 
-                                               fy= 1.0f-fy;
+                                       if(tex->flag & TEX_REPEAT_YMIR) {
+                                               int orig= (int)floor(origf);
+                                               if(orig & 1) 
+                                                       fy= 1.0f-fy;
+                                       }
                                }
                                
                                if(max<tex->yrepeat)
@@ -1220,7 +1212,7 @@ static int multitex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex,
                retval= texnoise(tex, texres); 
                break;
        case TEX_IMAGE:
-               if(osatex) retval= imagewraposa(tex, tex->ima, NULL, texvec, dxt, dyt, texres); 
+               if(osatex) retval= imagewraposa(tex, tex->ima, NULL, texvec, dxt, dyt, texres);
                else retval= imagewrap(tex, tex->ima, NULL, texvec, texres); 
                tag_image_time(tex->ima); /* tag image as having being used */
                break;
@@ -1518,164 +1510,91 @@ float texture_value_blend(float tex, float out, float fact, float facg, int blen
        return in;
 }
 
-void do_volume_tex(ShadeInput *shi, float *xyz, int mapto_flag, float *col, float *val)
+static void texco_mapping(ShadeInput* shi, Tex* tex, MTex* mtex, float* co, float* dx, float* dy, float* texvec, float* dxt, float* dyt)
 {
-       MTex *mtex;
-       Tex *tex;
-       TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
-       int tex_nr, rgbnor= 0;
-       float co[3], texvec[3];
-       float fact, stencilTin=1.0;
-       
-       if (R.r.scemode & R_NO_TEX) return;
-       /* here: test flag if there's a tex (todo) */
-       
-       for(tex_nr=0; tex_nr<MAX_MTEX; tex_nr++) {
-               /* separate tex switching */
-               if(shi->mat->septex & (1<<tex_nr)) continue;
+       // new: first swap coords, then map, then trans/scale
+       if (tex->type == TEX_IMAGE) {
+               // placement
+               texvec[0] = mtex->projx ? co[mtex->projx - 1] : 0.f;
+               texvec[1] = mtex->projy ? co[mtex->projy - 1] : 0.f;
+               texvec[2] = mtex->projz ? co[mtex->projz - 1] : 0.f;
+
+               if (shi->osatex) {
+                       if (mtex->projx) {
+                               dxt[0] = dx[mtex->projx - 1];
+                               dyt[0] = dy[mtex->projx - 1];
+                       }
+                       else dxt[0] = dyt[0] = 0.f;
+                       if (mtex->projy) {
+                               dxt[1] = dx[mtex->projy - 1];
+                               dyt[1] = dy[mtex->projy - 1];
+                       }
+                       else dxt[1] = dyt[1] = 0.f;
+                       if (mtex->projz) {
+                               dxt[2] = dx[mtex->projz - 1];
+                               dyt[2] = dy[mtex->projz - 1];
+                       }
+                       else dxt[2] = dyt[2] = 0.f;
+               }
+               do_2d_mapping(mtex, texvec, shi->vlr, shi->facenor, dxt, dyt);
+
+               // translate and scale
+               texvec[0] = mtex->size[0]*(texvec[0] - 0.5f) + mtex->ofs[0] + 0.5f;
+               texvec[1] = mtex->size[1]*(texvec[1] - 0.5f) + mtex->ofs[1] + 0.5f;
+               if (shi->osatex) {
+                       dxt[0] = mtex->size[0]*dxt[0];
+                       dxt[1] = mtex->size[1]*dxt[1];
+                       dyt[0] = mtex->size[0]*dyt[0];
+                       dyt[1] = mtex->size[1]*dyt[1];
+               }
                
-               if(shi->mat->mtex[tex_nr]) {
-                       mtex= shi->mat->mtex[tex_nr];
-                       tex= mtex->tex;
-                       if(tex==0) continue;
-                       
-                       /* only process if this texture is mapped 
-                        * to one that we're interested in */
-                       if (!(mtex->mapto & mapto_flag)) continue;
-                       
-                       /* which coords */
-                       if(mtex->texco==TEXCO_OBJECT) { 
-                               Object *ob= mtex->object;
-                               ob= mtex->object;
-                               if(ob) {                                                
-                                       VECCOPY(co, xyz);       
-                                       if(mtex->texflag & MTEX_OB_DUPLI_ORIG) {
-                                               if(shi->obi && shi->obi->duplitexmat)
-                                                       MTC_Mat4MulVecfl(shi->obi->duplitexmat, co);                                    
-                                       } 
-                                       MTC_Mat4MulVecfl(ob->imat, co);
-                               }
-                       }
-                       /* not really orco, but 'local' */
-                       else if(mtex->texco==TEXCO_ORCO) {
-                               
-                               if(mtex->texflag & MTEX_DUPLI_MAPTO) {
-                                       VECCOPY(co, shi->duplilo);
-                               }
-                               else {
-                                       Object *ob= shi->obi->ob;
-                                       VECCOPY(co, xyz);
-                                       MTC_Mat4MulVecfl(ob->imat, co);
-                               }
-                       }
-                       else if(mtex->texco==TEXCO_GLOB) {                                                      
-                          VECCOPY(co, xyz);
-                          MTC_Mat4MulVecfl(R.viewinv, co);
+               /* problem: repeat-mirror is not a 'repeat' but 'extend' in imagetexture.c */
+               // TXF: bug was here, only modify texvec when repeat mode set, old code affected other modes too.
+               // New texfilters solve mirroring differently so that it also works correctly when
+               // textures are scaled (sizeXYZ) as well as repeated. See also modification in do_2d_mapping().
+               // (since currently only done in osa mode, results will look incorrect without osa TODO) 
+               if (tex->extend == TEX_REPEAT && (tex->flag & TEX_REPEAT_XMIR)) {
+                       if (tex->texfilter == TXF_BOX)
+                               texvec[0] -= floorf(texvec[0]); // this line equivalent to old code, same below
+                       else if (texvec[0] < 0.f || texvec[0] > 1.f) {
+                               const float tx = 0.5f*texvec[0];
+                               texvec[0] = 2.f*(tx - floorf(tx));
+                               if (texvec[0] > 1.f) texvec[0] = 2.f - texvec[0];
                        }
-                       else continue;  // can happen when texco defines disappear and it renders old files
-
-                       texres.nor= NULL;
-                       
-                       if(tex->type==TEX_IMAGE) {
-                               continue;       /* not supported yet */
+               }
+               if (tex->extend == TEX_REPEAT && (tex->flag & TEX_REPEAT_YMIR)) {
+                       if  (tex->texfilter == TXF_BOX)
+                               texvec[1] -= floorf(texvec[1]);
+                       else if (texvec[1] < 0.f || texvec[1] > 1.f) {
+                               const float ty = 0.5f*texvec[1];
+                               texvec[1] = 2.f*(ty - floorf(ty));
+                               if (texvec[1] > 1.f) texvec[1] = 2.f - texvec[1];
                        }
-                       else {
-                               /* placement */
-                               if(mtex->projx) texvec[0]= mtex->size[0]*(co[mtex->projx-1]+mtex->ofs[0]);
-                               else texvec[0]= mtex->size[0]*(mtex->ofs[0]);
-
-                               if(mtex->projy) texvec[1]= mtex->size[1]*(co[mtex->projy-1]+mtex->ofs[1]);
-                               else texvec[1]= mtex->size[1]*(mtex->ofs[1]);
+               }
+               
+       }
+       else {  // procedural
+               // placement
+               texvec[0] = mtex->size[0]*(mtex->projx ? (co[mtex->projx - 1] + mtex->ofs[0]) : mtex->ofs[0]);
+               texvec[1] = mtex->size[1]*(mtex->projy ? (co[mtex->projy - 1] + mtex->ofs[1]) : mtex->ofs[1]);
+               texvec[2] = mtex->size[2]*(mtex->projz ? (co[mtex->projz - 1] + mtex->ofs[2]) : mtex->ofs[2]);
 
-                               if(mtex->projz) texvec[2]= mtex->size[2]*(co[mtex->projz-1]+mtex->ofs[2]);
-                               else texvec[2]= mtex->size[2]*(mtex->ofs[2]);
+               if (shi->osatex) {
+                       if (mtex->projx) {
+                               dxt[0] = mtex->size[0]*dx[mtex->projx - 1];
+                               dyt[0] = mtex->size[0]*dy[mtex->projx - 1];
                        }
-                       
-
-                       rgbnor= multitex(tex, texvec, NULL, NULL, 0, &texres, 0, mtex->which_output);   /* NULL = dxt/dyt, 0 = shi->osatex - not supported */
-                       
-                       /* texture output */
-
-                       if( (rgbnor & TEX_RGB) && (mtex->texflag & MTEX_RGBTOINT)) {
-                               texres.tin= (0.35*texres.tr+0.45*texres.tg+0.2*texres.tb);
-                               rgbnor-= TEX_RGB;
+                       else dxt[0] = 0.f;
+                       if (mtex->projy) {
+                               dxt[1] = mtex->size[1]*dx[mtex->projy - 1];
+                               dyt[1] = mtex->size[1]*dy[mtex->projy - 1];
                        }
-                       if(mtex->texflag & MTEX_NEGATIVE) {
-                               if(rgbnor & TEX_RGB) {
-                                       texres.tr= 1.0-texres.tr;
-                                       texres.tg= 1.0-texres.tg;
-                                       texres.tb= 1.0-texres.tb;
-                               }
-                               texres.tin= 1.0-texres.tin;
-                       }
-                       if(mtex->texflag & MTEX_STENCIL) {
-                               if(rgbnor & TEX_RGB) {
-                                       fact= texres.ta;
-                                       texres.ta*= stencilTin;
-                                       stencilTin*= fact;
-                               }
-                               else {
-                                       fact= texres.tin;
-                                       texres.tin*= stencilTin;
-                                       stencilTin*= fact;
-                               }
-                       }
-                       
-                       
-                       if((mapto_flag & (MAP_COL+MAP_COLMIR)) && (mtex->mapto & (MAP_COL+MAP_COLMIR))) {
-                               float tcol[3], colfac;
-                               
-                               /* stencil maps on the texture control slider, not texture intensity value */
-                               colfac= mtex->colfac*stencilTin;
-                               
-                               if((rgbnor & TEX_RGB)==0) {
-                                       tcol[0]= mtex->r;
-                                       tcol[1]= mtex->g;
-                                       tcol[2]= mtex->b;
-                               } else {
-                                       tcol[0]=texres.tr;
-                                       tcol[1]=texres.tg;
-                                       tcol[2]=texres.tb;
-                                       if(texres.talpha)
-                                               texres.tin= texres.ta;
-                               }
-                               
-                               /* used for emit */
-                               if((mapto_flag & MAP_COL) && (mtex->mapto & MAP_COL)) {
-                                       texture_rgb_blend(col, tcol, col, texres.tin, colfac, mtex->blendtype);
-                               }
-                               
-                               /* MAP_COLMIR is abused for absorption colour at the moment */
-                               if((mapto_flag & MAP_COLMIR) && (mtex->mapto & MAP_COLMIR)) {
-                                       texture_rgb_blend(col, tcol, col, texres.tin, colfac, mtex->blendtype);
-                               }
-                       }
-                       
-                       if((mapto_flag & MAP_VARS) && (mtex->mapto & MAP_VARS)) {
-                               /* stencil maps on the texture control slider, not texture intensity value */
-                               float varfac= mtex->varfac*stencilTin;
-                               
-                               /* convert RGB to intensity if intensity info isn't provided */
-                               if (!(rgbnor & TEX_INT)) {
-                                       if (rgbnor & TEX_RGB) {
-                                               if(texres.talpha) texres.tin= texres.ta;
-                                               else texres.tin= (0.35*texres.tr+0.45*texres.tg+0.2*texres.tb);
-                                       }
-                               }
-                               
-                               if((mapto_flag & MAP_EMIT) && (mtex->mapto & MAP_EMIT)) {
-                                       int flip= mtex->maptoneg & MAP_EMIT;
-
-                                       *val = texture_value_blend(mtex->def_var, *val, texres.tin, varfac, mtex->blendtype, flip);
-                                       if(*val<0.0) *val= 0.0;
-                               }
-                               if((mapto_flag & MAP_ALPHA) && (mtex->mapto & MAP_ALPHA)) {
-                                       int flip= mtex->maptoneg & MAP_ALPHA;
-
-                                       *val = texture_value_blend(mtex->def_var, *val, texres.tin, varfac, mtex->blendtype, flip);
-                                       CLAMP(*val, 0.0, 1.0);
-                               }
+                       else dxt[1] = 0.f;
+                       if (mtex->projz) {
+                               dxt[2] = mtex->size[2]*dx[mtex->projz - 1];
+                               dyt[2] = mtex->size[2]*dy[mtex->projz - 1];
                        }
+                       else dxt[2]= 0.f;
                }
        }
 }
@@ -1689,10 +1608,12 @@ void do_material_tex(ShadeInput *shi)
        float fact, facm, factt, facmm, stencilTin=1.0;
        float texvec[3], dxt[3], dyt[3], tempvec[3], norvec[3], warpvec[3]={0.0f, 0.0f, 0.0f}, Tnor=1.0;
        int tex_nr, rgbnor= 0, warpdone=0;
+       float nu[3], nv[3], nn[3] = {0,0,0}, dudnu = 1.f, dudnv = 0.f, dvdnu = 0.f, dvdnv = 1.f; // bump mapping
+       int nunvdone= 0;
 
        if (R.r.scemode & R_NO_TEX) return;
        /* here: test flag if there's a tex (todo) */
-       
+
        for(tex_nr=0; tex_nr<MAX_MTEX; tex_nr++) {
                
                /* separate tex switching */
@@ -1762,7 +1683,7 @@ void do_material_tex(ShadeInput *shi)
                                }
                                else {
                                        ShadeInputUV *suv= &shi->uv[shi->actuv];
-                                       int i;
+                                       int i = shi->actuv;
 
                                        if(mtex->uvname[0] != 0) {
                                                for(i = 0; i < shi->totuv; i++) {
@@ -1776,6 +1697,47 @@ void do_material_tex(ShadeInput *shi)
                                        co= suv->uv;
                                        dx= suv->dxuv;
                                        dy= suv->dyuv; 
+
+                                       // uvmapping only, calculation of normal tangent u/v partial derivatives
+                                       // (should not be here, dudnu, dudnv, dvdnu & dvdnv should probably be part of ShadeInputUV struct,
+                                       //  nu/nv in ShadeInput and this calculation should then move to shadeinput.c, shade_input_set_shade_texco() func.)
+                                       // NOTE: test for shi->obr->ob here, since vlr/obr/obi can be 'fake' when called from fastshade(), another reason to move it..
+                                       if ((mtex->texflag & MTEX_NEW_BUMP) && shi->obr && shi->obr->ob) {
+                                               if(mtex->mapto & (MAP_NORM|MAP_DISPLACE|MAP_WARP)) {
+                                                       MTFace* tf = RE_vlakren_get_tface(shi->obr, shi->vlr, i, NULL, 0);
+                                                       int j1 = shi->i1, j2 = shi->i2, j3 = shi->i3;
+
+                                                       vlr_set_uv_indices(shi->vlr, &j1, &j2, &j3);
+
+                                                       if (tf) {
+                                                               float *uv1 = tf->uv[j1], *uv2 = tf->uv[j2], *uv3 = tf->uv[j3];
+                                                               const float an[3] = {fabsf(nn[0]), fabsf(nn[1]), fabsf(nn[2])};
+                                                               const int a1 = (an[0] > an[1] && an[0] > an[2]) ? 1 : 0;
+                                                               const int a2 = (an[2] > an[0] && an[2] > an[1]) ? 1 : 2;
+                                                               const float dp1_a1 = shi->v1->co[a1] - shi->v3->co[a1];
+                                                               const float dp1_a2 = shi->v1->co[a2] - shi->v3->co[a2];
+                                                               const float dp2_a1 = shi->v2->co[a1] - shi->v3->co[a1];
+                                                               const float dp2_a2 = shi->v2->co[a2] - shi->v3->co[a2];
+                                                               const float du1 = uv1[0] - uv3[0], du2 = uv2[0] - uv3[0];
+                                                               const float dv1 = uv1[1] - uv3[1], dv2 = uv2[1] - uv3[1];
+                                                               const float dpdu_a1 = dv2*dp1_a1 - dv1*dp2_a1;
+                                                               const float dpdu_a2 = dv2*dp1_a2 - dv1*dp2_a2;
+                                                               const float dpdv_a1 = du1*dp2_a1 - du2*dp1_a1;
+                                                               const float dpdv_a2 = du1*dp2_a2 - du2*dp1_a2;
+                                                               float d = dpdu_a1*dpdv_a2 - dpdv_a1*dpdu_a2;
+                                                               float uvd = du1*dv2 - dv1*du2;
+
+                                                               if (uvd == 0.f) uvd = 1e-5f;
+                                                               if (d == 0.f) d = 1e-5f;
+                                                               d = uvd / d;
+
+                                                               dudnu = (dpdv_a2*nu[a1] - dpdv_a1*nu[a2])*d;
+                                                               dvdnu = (dpdu_a1*nu[a2] - dpdu_a2*nu[a1])*d;
+                                                               dudnv = (dpdv_a2*nv[a1] - dpdv_a1*nv[a2])*d;
+                                                               dvdnv = (dpdu_a1*nv[a2] - dpdu_a2*nv[a1])*d;
+                                                       }
+                                               }
+                                       }
                                }
                        }
                        else if(mtex->texco==TEXCO_WINDOW) {
@@ -1801,7 +1763,7 @@ void do_material_tex(ShadeInput *shi)
                        }
                        else continue;  // can happen when texco defines disappear and it renders old files
 
-                       /* de pointer defines if bumping happens */
+                       /* the pointer defines if bumping happens */
                        if(mtex->mapto & (MAP_NORM|MAP_DISPLACE|MAP_WARP)) {
                                texres.nor= norvec;
                                norvec[0]= norvec[1]= norvec[2]= 0.0;
@@ -1812,94 +1774,149 @@ void do_material_tex(ShadeInput *shi)
                                VECADD(tempvec, co, warpvec);
                                co= tempvec;
                        }
-                       
-                       if(tex->type==TEX_IMAGE) {
-
-                               /* new: first swap coords, then map, then trans/scale */
 
-                               /* placement */
-                               if(mtex->projx) texvec[0]= co[mtex->projx-1];
-                               else texvec[0]= 0.0;
-                               if(mtex->projy) texvec[1]= co[mtex->projy-1];
-                               else texvec[1]= 0.0;
-                               if(mtex->projz) texvec[2]= co[mtex->projz-1];
-                               else texvec[2]= 0.0;
+                       if(mtex->texflag & MTEX_NEW_BUMP) {
+                               // compute ortho basis around normal
+                               if(!nunvdone) {
+                                       // render normal is negated
+                                       nn[0] = -shi->vn[0];
+                                       nn[1] = -shi->vn[1];
+                                       nn[2] = -shi->vn[2];
+                                       VecOrthoBasisf(nn, nu, nv);
+                                       nunvdone= 1;
+                               }
 
-                               if(shi->osatex) {
-                                       
-                                       if(mtex->projx) {
-                                               dxt[0]= dx[mtex->projx-1];
-                                               dyt[0]= dy[mtex->projx-1];
-                                       }
-                                       else dxt[0]= dyt[0]= 0.0f;
-                                       
-                                       if(mtex->projy) {
-                                               dxt[1]= dx[mtex->projy-1];
-                                               dyt[1]= dy[mtex->projy-1];
+                               if(texres.nor) {
+                                       TexResult ttexr = {0, 0, 0, 0, 0, texres.talpha, NULL}; // temp TexResult
+                                       float tco[3], texv[3], cd, ud, vd, du, dv, idu, idv;
+                                       const int fromrgb = ((tex->type == TEX_IMAGE) || ((tex->flag & TEX_COLORBAND)!=0));
+                                       const float bf = 0.04f*Tnor*((mtex->maptoneg & MAP_NORM) ? -mtex->norfac : mtex->norfac);
+                                       // disable internal bump eval
+                                       float* nvec = texres.nor;
+                                       texres.nor = NULL;
+                                       // du & dv estimates, constant value defaults
+                                       du = dv = 0.01f;
+
+                                       // two methods, either constant based on main image resolution,
+                                       // (which also works without osa, though of course not always good (or even very bad) results),
+                                       // or based on tex derivative max values (osa only). Not sure which is best...
+
+                                       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_get_ibuf(tex->ima, &tex->iuser);
+                                               if (ibuf) {
+                                                       du = 1.f/(float)ibuf->x;
+                                                       dv = 1.f/(float)ibuf->y;
+                                               }
                                        }
-                                       else dxt[1]= dyt[1]= 0.0f;
-                                       if(mtex->projz) {
-                                               dxt[2]= dx[mtex->projz-1];
-                                               dyt[2]= dy[mtex->projz-1];
+                                       else if (shi->osatex) {
+                                               // we have derivatives, can compute proper du/dv
+                                               if (tex->type == TEX_IMAGE) {   // 2d image, use u & v max. of dx/dy 2d vecs
+                                                       const float adx[2] = {fabsf(dx[0]), fabsf(dx[1])};
+                                                       const float ady[2] = {fabsf(dy[0]), fabsf(dy[1])};
+                                                       du = MAX2(adx[0], ady[0]);
+                                                       dv = MAX2(adx[1], ady[1]);
+                                               }
+                                               else {  // 3d procedural, estimate from all dx/dy elems
+                                                       const float adx[3] = {fabsf(dx[0]), fabsf(dx[1]), fabsf(dx[2])};
+                                                       const float ady[3] = {fabsf(dy[0]), fabsf(dy[1]), fabsf(dy[2])};
+                                                       du = MAX3(adx[0], adx[1], adx[2]);
+                                                       dv = MAX3(ady[1], ady[1], ady[2]);
+                                               }
                                        }
-                                       else dxt[2]= dyt[2]= 0.0;
-                               }
-                               
-                               do_2d_mapping(mtex, texvec, shi->vlr, shi->facenor, dxt, dyt);
 
-                               /* translate and scale */
-                               texvec[0]= mtex->size[0]*(texvec[0]-0.5) +mtex->ofs[0]+0.5;
-                               texvec[1]= mtex->size[1]*(texvec[1]-0.5) +mtex->ofs[1]+0.5;
-                               if(shi->osatex) {
-                                       dxt[0]= mtex->size[0]*dxt[0];
-                                       dxt[1]= mtex->size[1]*dxt[1];
-                                       dyt[0]= mtex->size[0]*dyt[0];
-                                       dyt[1]= mtex->size[1]*dyt[1];
-                               }
-                               
-                               /* problem: repeat-mirror is not a 'repeat' but 'extend' in imagetexture.c */
-                               if(tex->flag & TEX_REPEAT_XMIR) {
-                                       if(texvec[0]>1.0f) texvec[0] -= (int)(texvec[0]);
-                                       else if(texvec[0]<0.0f) texvec[0]+= 1-(int)(texvec[0]);
-                               }
-                               if(tex->flag & TEX_REPEAT_YMIR) {
-                                       if(texvec[1]>1.0f) texvec[1] -= (int)(texvec[1]);
-                                       else if(texvec[1]<0.0f) texvec[1]+= 1-(int)(texvec[1]);
-                               }
-                               
-                       }
-                       else {
-
-                               /* placement */
-                               if(mtex->projx) texvec[0]= mtex->size[0]*(co[mtex->projx-1]+mtex->ofs[0]);
-                               else texvec[0]= mtex->size[0]*(mtex->ofs[0]);
+                                       // center, main return value
+                                       texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt);
+                                       rgbnor = multitex(tex, texvec, dxt, dyt, shi->osatex, &texres, shi->thread, mtex->which_output);
+                                       cd = fromrgb ? (texres.tr + texres.tg + texres.tb)*0.33333333f : texres.tin;
+
+                                       if (mtex->texco == TEXCO_UV) {
+                                               // for the uv case, use the same value for both du/dv,
+                                               // since individually scaling the normal derivatives makes them useless...
+                                               du = MIN2(du, dv);
+                                               idu = (du < 1e-6f) ? bf : (bf/du);
+
+                                               // +u val
+                                               tco[0] = co[0] + dudnu*du;
+                                               tco[1] = co[1] + dvdnu*du;
+                                               tco[2] = 0.f;
+                                               texco_mapping(shi, tex, mtex, tco, dx, dy, texv, dxt, dyt);
+                                               multitex(tex, texv, dxt, dyt, shi->osatex, &ttexr, shi->thread, mtex->which_output);
+                                               ud = idu*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb)*0.33333333f : ttexr.tin));
+
+                                               // +v val
+                                               tco[0] = co[0] + dudnv*du;
+                                               tco[1] = co[1] + dvdnv*du;
+                                               tco[2] = 0.f;
+                                               texco_mapping(shi, tex, mtex, tco, dx, dy, texv, dxt, dyt);
+                                               multitex(tex, texv, dxt, dyt, shi->osatex, &ttexr, shi->thread, mtex->which_output);
+                                               vd = idu*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb)*0.33333333f : ttexr.tin));
+                                       }
+                                       else {
+                                               float tu[3] = {nu[0], nu[1], nu[2]}, tv[3] = {nv[0], nv[1], nv[2]};
 
-                               if(mtex->projy) texvec[1]= mtex->size[1]*(co[mtex->projy-1]+mtex->ofs[1]);
-                               else texvec[1]= mtex->size[1]*(mtex->ofs[1]);
+                                               idu = (du < 1e-6f) ? bf : (bf/du);
+                                               idv = (dv < 1e-6f) ? bf : (bf/dv);
 
-                               if(mtex->projz) texvec[2]= mtex->size[2]*(co[mtex->projz-1]+mtex->ofs[2]);
-                               else texvec[2]= mtex->size[2]*(mtex->ofs[2]);
+                                               if ((mtex->texco == TEXCO_ORCO) && shi->obr && shi->obr->ob) {
+                                                       Mat4Mul3Vecfl(shi->obr->ob->imat, tu);
+                                                       Mat4Mul3Vecfl(shi->obr->ob->imat, tv);
+                                                       Normalize(tu);
+                                                       Normalize(tv);
+                                               }
+                                               else if (mtex->texco == TEXCO_GLOB) {
+                                                       Mat4Mul3Vecfl(R.viewinv, tu);
+                                                       Mat4Mul3Vecfl(R.viewinv, tv);
+                                               }
+                                               else if (mtex->texco == TEXCO_OBJECT && mtex->object) {
+                                                       Mat4Mul3Vecfl(mtex->object->imat, tu);
+                                                       Mat4Mul3Vecfl(mtex->object->imat, tv);
+                                                       Normalize(tu);
+                                                       Normalize(tv);
+                                               }
 
-                               if(shi->osatex) {
-                                       if(mtex->projx) {
-                                               dxt[0]= mtex->size[0]*dx[mtex->projx-1];
-                                               dyt[0]= mtex->size[0]*dy[mtex->projx-1];
-                                       }
-                                       else dxt[0]= 0.0;
-                                       if(mtex->projy) {
-                                               dxt[1]= mtex->size[1]*dx[mtex->projy-1];
-                                               dyt[1]= mtex->size[1]*dy[mtex->projy-1];
-                                       }
-                                       else dxt[1]= 0.0;
-                                       if(mtex->projz) {
-                                               dxt[2]= mtex->size[2]*dx[mtex->projz-1];
-                                               dyt[2]= mtex->size[2]*dy[mtex->projz-1];
+                                               // +u val
+                                               tco[0] = co[0] + tu[0]*du;
+                                               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(tex, texv, dxt, dyt, shi->osatex, &ttexr, shi->thread, mtex->which_output);
+                                               ud = idu*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb)*0.33333333f : ttexr.tin));
+
+                                               // +v val
+                                               tco[0] = co[0] + tv[0]*dv;
+                                               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(tex, texv, dxt, dyt, shi->osatex, &ttexr, shi->thread, mtex->which_output);
+                                               vd = idv*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb)*0.33333333f : ttexr.tin));
                                        }
-                                       else dxt[2]= 0.0;
+
+                                       // bumped normal
+                                       nu[0] += ud*nn[0];
+                                       nu[1] += ud*nn[1];
+                                       nu[2] += ud*nn[2];
+                                       nv[0] += vd*nn[0];
+                                       nv[1] += vd*nn[1];
+                                       nv[2] += vd*nn[2];
+                                       Crossf(nvec, nu, nv);
+
+                                       nvec[0] = -nvec[0];
+                                       nvec[1] = -nvec[1];
+                                       nvec[2] = -nvec[2];
+                                       texres.nor = nvec;
+                                       rgbnor |= TEX_NOR;
+                               }
+                               else {
+                                       texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt);
+                                       rgbnor = multitex(tex, texvec, dxt, dyt, shi->osatex, &texres, shi->thread, mtex->which_output);
                                }
                        }
-
-                       rgbnor= multitex(tex, texvec, dxt, dyt, shi->osatex, &texres, shi->thread, mtex->which_output);
+                       else {
+                               texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt);
+                               rgbnor = multitex(tex, texvec, dxt, dyt, shi->osatex, &texres, shi->thread, mtex->which_output);
+                       }
 
                        /* texture output */
 
@@ -1965,7 +1982,7 @@ void do_material_tex(ShadeInput *shi)
                                if(mtex->texflag & MTEX_VIEWSPACE) {
                                        // rotate to global coords
                                        if(mtex->texco==TEXCO_ORCO || mtex->texco==TEXCO_UV) {
-                                               if(shi->vlr && shi->obr->ob) {
+                                               if(shi->vlr && shi->obr && shi->obr->ob) {
                                                        float len= Normalize(texres.nor);
                                                        // can be optimized... (ton)
                                                        Mat4Mul3Vecfl(shi->obr->ob->obmat, texres.nor);
@@ -1997,6 +2014,11 @@ void do_material_tex(ShadeInput *shi)
                                }
                                else texres.tin= texres.ta;
                                
+                               /* inverse gamma correction */
+                               if (R.r.color_mgt_flag & R_COLOR_MANAGEMENT) {
+                                       color_manage_linearize(tcol, tcol);
+                               }
+                               
                                if(mtex->mapto & MAP_COL) {
                                        texture_rgb_blend(&shi->r, tcol, &shi->r, texres.tin, colfac, mtex->blendtype);
                                }
@@ -2072,25 +2094,32 @@ void do_material_tex(ShadeInput *shi)
                                                }
                                        }
                                        else {
-                                               float nor[3], dot;
-
-                                               if(shi->mat->mode & MA_TANGENT_V) {
-                                                       shi->tang[0]+= Tnor*tex->norfac*texres.nor[0];
-                                                       shi->tang[1]+= Tnor*tex->norfac*texres.nor[1];
-                                                       shi->tang[2]+= Tnor*tex->norfac*texres.nor[2];
+                                               if (mtex->texflag & MTEX_NEW_BUMP) {
+                                                       shi->vn[0] = texres.nor[0];
+                                                       shi->vn[1] = texres.nor[1];
+                                                       shi->vn[2] = texres.nor[2];
                                                }
-
-                                               /* prevent bump to become negative normal */
-                                               nor[0]= Tnor*tex->norfac*texres.nor[0];
-                                               nor[1]= Tnor*tex->norfac*texres.nor[1];
-                                               nor[2]= Tnor*tex->norfac*texres.nor[2];
-                                               
-                                               dot= 0.5f + 0.5f*INPR(nor, shi->vn);
-                                               
-                                               shi->vn[0]+= dot*nor[0];
-                                               shi->vn[1]+= dot*nor[1];
-                                               shi->vn[2]+= dot*nor[2];
-                                       }                                       
+                                               else {
+                                                       float nor[3], dot;
+       
+                                                       if(shi->mat->mode & MA_TANGENT_V) {
+                                                               shi->tang[0]+= Tnor*tex->norfac*texres.nor[0];
+                                                               shi->tang[1]+= Tnor*tex->norfac*texres.nor[1];
+                                                               shi->tang[2]+= Tnor*tex->norfac*texres.nor[2];
+                                                       }
+       
+                                                       /* prevent bump to become negative normal */
+                                                       nor[0]= Tnor*tex->norfac*texres.nor[0];
+                                                       nor[1]= Tnor*tex->norfac*texres.nor[1];
+                                                       nor[2]= Tnor*tex->norfac*texres.nor[2];
+                                                       
+                                                       dot= 0.5f + 0.5f*INPR(nor, shi->vn);
+                                                       
+                                                       shi->vn[0]+= dot*nor[0];
+                                                       shi->vn[1]+= dot*nor[1];
+                                                       shi->vn[2]+= dot*nor[2];
+                                               }
+                                       }
                                        Normalize(shi->vn);
                                        
                                        /* this makes sure the bump is passed on to the next texture */
@@ -2218,12 +2247,185 @@ void do_material_tex(ShadeInput *shi)
                                        shi->amb= texture_value_blend(mtex->def_var, shi->amb, texres.tin, varfac, mtex->blendtype, flip);
                                        if(shi->amb<0.0) shi->amb= 0.0;
                                        else if(shi->amb>1.0) shi->amb= 1.0;
+                                       
+                                       shi->ambr= shi->amb*R.wrld.ambr;
+                                       shi->ambg= shi->amb*R.wrld.ambg;
+                                       shi->ambb= shi->amb*R.wrld.ambb;
+                               }
+                       }
+               }
+       }
+}
+
+
+void do_volume_tex(ShadeInput *shi, float *xyz, int mapto_flag, float *col, float *val)
+{
+       MTex *mtex;
+       Tex *tex;
+       TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
+       int tex_nr, rgbnor= 0;
+       float co[3], texvec[3];
+       float fact, stencilTin=1.0;
+       
+       if (R.r.scemode & R_NO_TEX) return;
+       /* here: test flag if there's a tex (todo) */
+       
+       for(tex_nr=0; tex_nr<MAX_MTEX; tex_nr++) {
+               /* separate tex switching */
+               if(shi->mat->septex & (1<<tex_nr)) continue;
+               
+               if(shi->mat->mtex[tex_nr]) {
+                       mtex= shi->mat->mtex[tex_nr];
+                       tex= mtex->tex;
+                       if(tex==0) continue;
+                       
+                       /* only process if this texture is mapped 
+                        * to one that we're interested in */
+                       if (!(mtex->mapto & mapto_flag)) continue;
+                       
+                       /* which coords */
+                       if(mtex->texco==TEXCO_OBJECT) { 
+                               Object *ob= mtex->object;
+                               ob= mtex->object;
+                               if(ob) {                                                
+                                       VECCOPY(co, xyz);       
+                                       if(mtex->texflag & MTEX_OB_DUPLI_ORIG) {
+                                               if(shi->obi && shi->obi->duplitexmat)
+                                                       MTC_Mat4MulVecfl(shi->obi->duplitexmat, co);                                    
+                                       } 
+                                       MTC_Mat4MulVecfl(ob->imat, co);
+                               }
+                       }
+                       /* not really orco, but 'local' */
+                       else if(mtex->texco==TEXCO_ORCO) {
+                               
+                               if(mtex->texflag & MTEX_DUPLI_MAPTO) {
+                                       VECCOPY(co, shi->duplilo);
+                               }
+                               else {
+                                       Object *ob= shi->obi->ob;
+                                       VECCOPY(co, xyz);
+                                       MTC_Mat4MulVecfl(ob->imat, co);
+                               }
+                       }
+                       else if(mtex->texco==TEXCO_GLOB) {                                                      
+                          VECCOPY(co, xyz);
+                          MTC_Mat4MulVecfl(R.viewinv, co);
+                       }
+                       else continue;  // can happen when texco defines disappear and it renders old files
+
+                       texres.nor= NULL;
+                       
+                       if(tex->type==TEX_IMAGE) {
+                               continue;       /* not supported yet */                         
+                               //do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt);
+                       }
+                       else {
+                               /* placement */
+                               if(mtex->projx) texvec[0]= mtex->size[0]*(co[mtex->projx-1]+mtex->ofs[0]);
+                               else texvec[0]= mtex->size[0]*(mtex->ofs[0]);
+
+                               if(mtex->projy) texvec[1]= mtex->size[1]*(co[mtex->projy-1]+mtex->ofs[1]);
+                               else texvec[1]= mtex->size[1]*(mtex->ofs[1]);
+
+                               if(mtex->projz) texvec[2]= mtex->size[2]*(co[mtex->projz-1]+mtex->ofs[2]);
+                               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 */
+                       
+                       /* texture output */
+
+                       if( (rgbnor & TEX_RGB) && (mtex->texflag & MTEX_RGBTOINT)) {
+                               texres.tin= (0.35*texres.tr+0.45*texres.tg+0.2*texres.tb);
+                               rgbnor-= TEX_RGB;
+                       }
+                       if(mtex->texflag & MTEX_NEGATIVE) {
+                               if(rgbnor & TEX_RGB) {
+                                       texres.tr= 1.0-texres.tr;
+                                       texres.tg= 1.0-texres.tg;
+                                       texres.tb= 1.0-texres.tb;
+                               }
+                               texres.tin= 1.0-texres.tin;
+                       }
+                       if(mtex->texflag & MTEX_STENCIL) {
+                               if(rgbnor & TEX_RGB) {
+                                       fact= texres.ta;
+                                       texres.ta*= stencilTin;
+                                       stencilTin*= fact;
+                               }
+                               else {
+                                       fact= texres.tin;
+                                       texres.tin*= stencilTin;
+                                       stencilTin*= fact;
+                               }
+                       }
+                       
+                       
+                       if((mapto_flag & (MAP_COL+MAP_COLMIR)) && (mtex->mapto & (MAP_COL+MAP_COLMIR))) {
+                               float tcol[3], colfac;
+                               
+                               /* stencil maps on the texture control slider, not texture intensity value */
+                               colfac= mtex->colfac*stencilTin;
+                               
+                               if((rgbnor & TEX_RGB)==0) {
+                                       tcol[0]= mtex->r;
+                                       tcol[1]= mtex->g;
+                                       tcol[2]= mtex->b;
+                               } else {
+                                       tcol[0]=texres.tr;
+                                       tcol[1]=texres.tg;
+                                       tcol[2]=texres.tb;
+                                       if(texres.talpha)
+                                               texres.tin= texres.ta;
+                               }
+                               
+                               /* inverse gamma correction */
+                               if (R.r.color_mgt_flag & R_COLOR_MANAGEMENT) {
+                                       color_manage_linearize(tcol, tcol);
+                               }
+                               
+                               /* used for emit */
+                               if((mapto_flag & MAP_COL) && (mtex->mapto & MAP_COL)) {
+                                       texture_rgb_blend(col, tcol, col, texres.tin, colfac, mtex->blendtype);
+                               }
+                               
+                               /* MAP_COLMIR is abused for absorption colour at the moment */
+                               if((mapto_flag & MAP_COLMIR) && (mtex->mapto & MAP_COLMIR)) {
+                                       texture_rgb_blend(col, tcol, col, texres.tin, colfac, mtex->blendtype);
+                               }
+                       }
+                       
+                       if((mapto_flag & MAP_VARS) && (mtex->mapto & MAP_VARS)) {
+                               /* stencil maps on the texture control slider, not texture intensity value */
+                               float varfac= mtex->varfac*stencilTin;
+                               
+                               /* convert RGB to intensity if intensity info isn't provided */
+                               if (!(rgbnor & TEX_INT)) {
+                                       if (rgbnor & TEX_RGB) {
+                                               if(texres.talpha) texres.tin= texres.ta;
+                                               else texres.tin= (0.35*texres.tr+0.45*texres.tg+0.2*texres.tb);
+                                       }
+                               }
+                               
+                               if((mapto_flag & MAP_EMIT) && (mtex->mapto & MAP_EMIT)) {
+                                       int flip= mtex->maptoneg & MAP_EMIT;
+
+                                       *val = texture_value_blend(mtex->def_var, *val, texres.tin, varfac, mtex->blendtype, flip);
+                                       if(*val<0.0) *val= 0.0;
+                               }
+                               if((mapto_flag & MAP_ALPHA) && (mtex->mapto & MAP_ALPHA)) {
+                                       int flip= mtex->maptoneg & MAP_ALPHA;
+
+                                       *val = texture_value_blend(mtex->def_var, *val, texres.tin, varfac, mtex->blendtype, flip);
+                                       CLAMP(*val, 0.0, 1.0);
                                }
                        }
                }
        }
 }
 
+
 /* ------------------------------------------------------------------------- */
 
 void do_halo_tex(HaloRen *har, float xn, float yn, float *colf)
@@ -2312,6 +2514,11 @@ void do_halo_tex(HaloRen *har, float xn, float yn, float *colf)
                }
                else texres.tin= texres.ta;
 
+               /* inverse gamma correction */
+               if (R.r.color_mgt_flag & R_COLOR_MANAGEMENT) {
+                       color_manage_linearize(&texres.tr, &texres.tr);
+               }
+
                fact= texres.tin*mtex->colfac;
                facm= 1.0-fact;
                
@@ -2499,6 +2706,11 @@ void do_sky_tex(float *rco, float *lo, float *dxyview, float *hor, float *zen, f
                                
                                tcol[0]= texres.tr; tcol[1]= texres.tg; tcol[2]= texres.tb;
 
+                               /* inverse gamma correction */
+                               if (R.r.color_mgt_flag & R_COLOR_MANAGEMENT) {
+                                       color_manage_linearize(tcol, tcol);
+                               }
+
                                if(mtex->mapto & WOMAP_HORIZ) {
                                        texture_rgb_blend(hor, tcol, hor, texres.tin, mtex->colfac, mtex->blendtype);
                                }
@@ -2537,7 +2749,7 @@ void do_lamp_tex(LampRen *la, float *lavec, ShadeInput *shi, float *colf, int ef
        TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
        float *co = NULL, *dx = NULL, *dy = NULL, fact, stencilTin=1.0;
        float texvec[3], dxt[3], dyt[3], tempvec[3];
-       int tex_nr, rgb= 0;
+       int i, tex_nr, rgb= 0;
        
        if (R.r.scemode & R_NO_TEX) return;
        tex_nr= 0;
@@ -2603,31 +2815,43 @@ void do_lamp_tex(LampRen *la, float *lavec, ShadeInput *shi, float *colf, int ef
                        
                        
                        /* placement */
-                       if(mtex->projx) texvec[0]= mtex->size[0]*(co[mtex->projx-1]+mtex->ofs[0]);
+                       if(mtex->projx && co) texvec[0]= mtex->size[0]*(co[mtex->projx-1]+mtex->ofs[0]);
                        else texvec[0]= mtex->size[0]*(mtex->ofs[0]);
                        
-                       if(mtex->projy) texvec[1]= mtex->size[1]*(co[mtex->projy-1]+mtex->ofs[1]);
+                       if(mtex->projy && co) texvec[1]= mtex->size[1]*(co[mtex->projy-1]+mtex->ofs[1]);
                        else texvec[1]= mtex->size[1]*(mtex->ofs[1]);
                        
-                       if(mtex->projz) texvec[2]= mtex->size[2]*(co[mtex->projz-1]+mtex->ofs[2]);
+                       if(mtex->projz && co) texvec[2]= mtex->size[2]*(co[mtex->projz-1]+mtex->ofs[2]);
                        else texvec[2]= mtex->size[2]*(mtex->ofs[2]);
                        
                        if(shi->osatex) {
-                               if(mtex->projx) {
-                                       dxt[0]= mtex->size[0]*dx[mtex->projx-1];
-                                       dyt[0]= mtex->size[0]*dy[mtex->projx-1];
-                               }
-                               else dxt[0]= 0.0;
-                               if(mtex->projy) {
-                                       dxt[1]= mtex->size[1]*dx[mtex->projy-1];
-                                       dyt[1]= mtex->size[1]*dy[mtex->projy-1];
-                               }
-                               else dxt[1]= 0.0;
-                               if(mtex->projx) {
-                                       dxt[2]= mtex->size[2]*dx[mtex->projz-1];
-                                       dyt[2]= mtex->size[2]*dy[mtex->projz-1];
+                               if (!dx) {
+                                       for(i=0;i<2;i++) { 
+                                               dxt[i] = dyt[i] = 0.0;
+                                       }
+                               } else {
+                                       if(mtex->projx) {
+                                               dxt[0]= mtex->size[0]*dx[mtex->projx-1];
+                                               dyt[0]= mtex->size[0]*dy[mtex->projx-1];
+                                       } else {
+                                               dxt[0]= 0.0;
+                                               dyt[0]= 0.0;
+                                       }
+                                       if(mtex->projy) {
+                                               dxt[1]= mtex->size[1]*dx[mtex->projy-1];
+                                               dyt[1]= mtex->size[1]*dy[mtex->projy-1];
+                                       } else {
+                                               dxt[1]= 0.0;
+                                               dyt[1]= 0.0;
+                                       }
+                                       if(mtex->projz) {
+                                               dxt[2]= mtex->size[2]*dx[mtex->projz-1];
+                                               dyt[2]= mtex->size[2]*dy[mtex->projz-1];
+                                       } else {
+                                               dxt[2]= 0.0;
+                                               dyt[2]= 0.0;
+                                       }
                                }
-                               else dxt[2]= 0.0;
                        }
                        
                        /* texture */
@@ -2681,6 +2905,11 @@ void do_lamp_tex(LampRen *la, float *lavec, ShadeInput *shi, float *colf, int ef
                                }
                                else texres.tin= texres.ta;
 
+                               /* inverse gamma correction */
+                               if (R.r.color_mgt_flag & R_COLOR_MANAGEMENT) {
+                                       color_manage_linearize(&texres.tr, &texres.tr);
+                               }
+
                                /* lamp colors were premultiplied with this */
                                col[0]= texres.tr*la->energy;
                                col[1]= texres.tg*la->energy;
@@ -2784,7 +3013,7 @@ void render_realtime_texture(ShadeInput *shi, Image *ima)
        
        texr.nor= NULL;
        
-       if(shi->osatex) imagewraposa(tex, ima, NULL, texvec, dx, dy, &texr); 
+       if(shi->osatex) imagewraposa(tex, ima, NULL, texvec, dx, dy, &texr);
        else imagewrap(tex, ima, NULL, texvec, &texr); 
 
        shi->vcol[0]*= texr.tr;