svn merge -r 16866:17042 https://svn.blender.org/svnroot/bf-blender/trunk/blender
authorDaniel Genrich <daniel.genrich@gmx.net>
Sun, 12 Oct 2008 12:17:57 +0000 (12:17 +0000)
committerDaniel Genrich <daniel.genrich@gmx.net>
Sun, 12 Oct 2008 12:17:57 +0000 (12:17 +0000)
1  2 
source/blender/blenloader/intern/readfile.c
source/blender/render/extern/include/RE_shader_ext.h
source/blender/render/intern/include/shading.h
source/blender/render/intern/source/convertblender.c
source/blender/render/intern/source/rayshade.c
source/blender/render/intern/source/shadeinput.c
source/blender/src/buttons_shading.c

index 249459bf3a468a1b00f7f251b0bff46c2b357f0d,25f9e179ca901cbc1aed8775eedef452cc310b11..3cae5fe4972a44c289600d8b35497e4a35fd303f
@@@ -2476,7 -2476,6 +2476,7 @@@ static void lib_link_texture(FileData *
                        tex->ima= newlibadr_us(fd, tex->id.lib, tex->ima);
                        tex->ipo= newlibadr_us(fd, tex->id.lib, tex->ipo);
                        if(tex->env) tex->env->object= newlibadr(fd, tex->id.lib, tex->env->object);
 +                      if(tex->pd) tex->pd->object= newlibadr(fd, tex->id.lib, tex->pd->object);
  
                        tex->id.flag -= LIB_NEEDLINK;
                }
@@@ -2503,10 -2502,6 +2503,10 @@@ static void direct_link_texture(FileDat
                memset(tex->env->cube, 0, 6*sizeof(void *));
                tex->env->ok= 0;
        }
 +      tex->pd= newdataadr(fd, tex->pd);
 +      if(tex->pd) {
 +              tex->pd->point_tree = NULL;
 +      }
        tex->preview = direct_link_preview_image(fd, tex->preview);
  
        tex->iuser.ok= 1;
@@@ -7694,7 -7689,6 +7694,7 @@@ static void do_versions(FileData *fd, L
        if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 11)) {
                Object *ob;
                bActionStrip *strip;
 +
                
                /* nla-strips - scale */                
                for (ob= main->object.first; ob; ob= ob->id.next) {
                                ob->soft->shearstiff = 1.0f; 
                        }
                }
 +              
        }
  
        if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 14)) {
                        la->skyblendtype= MA_RAMP_ADD;
                        la->skyblendfac= 1.0f;
                }
 +              
 +      }
 +      
 +      if (main->versionfile <= 247) {
 +              Material *ma;
 +              Tex *tex;
 +              
 +              for(ma=main->mat.first; ma; ma= ma->id.next) {
 +                      /* trigger for non-volumetric file */
 +                      if (ma->vol_shade_stepsize < 0.0001f) {
 +                              ma->vol_shade_stepsize = 0.2f;
 +                              ma->vol_stepsize = 0.2f;
 +                              ma->vol_absorption = 1.0f;
 +                              ma->vol_scattering = 1.0f;
 +                              ma->vol_absorption_col[0] = ma->vol_absorption_col[1] = ma->vol_absorption_col[2] = 0.0f;       
 +                      }
 +              }
 +              
 +              for(tex=main->tex.first; tex; tex= tex->id.next) {
 +                      if (tex->pd == NULL) 
 +                              tex->pd = BKE_add_pointdensity();
 +                      else if (tex->pd->noise_size < 0.0001f) {
 +                              tex->pd->noise_size = 0.5f;
 +                              tex->pd->noise_depth = 1;
 +                              tex->pd->noise_fac = 1.0f;
 +                              tex->pd->noise_influence = TEX_PD_NOISE_STATIC;
 +                      }
 +              }
 +              
        }
        
        /* set the curve radius interpolation to 2.47 default - easy */
                        }
                }
        }
 +
        /* direction constraint actuators were always local in previous version */
        if (main->versionfile < 247 || (main->versionfile == 247 && main->subversionfile < 7)) {
                bActuator *act;
                        la->sky_exposure= 1.0f;
                }
        }
+       
+       /* BGE message actuators needed OB prefix, very confusing */
+       if (main->versionfile < 247 || (main->versionfile == 247 && main->subversionfile < 10)) {
+               bActuator *act;
+               Object *ob;
                
-               
-               
+               for(ob = main->object.first; ob; ob= ob->id.next) {
+                       for(act= ob->actuators.first; act; act= act->next) {
+                               if (act->type == ACT_MESSAGE) {
+                                       bMessageActuator *msgAct = (bMessageActuator *) act->data;
+                                       if (strlen(msgAct->toPropName) > 2) {
+                                               /* strip first 2 chars, would have only worked if these were OB anyway */
+                                               strncpy(msgAct->toPropName, msgAct->toPropName+2, sizeof(msgAct->toPropName));
+                                       } else {
+                                               msgAct->toPropName[0] = '\0';
+                                       }
+                               }
+                       }
+               }
+       }
+       
        /* WATCH IT!!!: pointers from libdata have not been converted yet here! */
        /* WATCH IT 2!: Userdef struct init has to be in src/usiblender.c! */
  
index 16449df02b06effe7d8524045b30af9873351b9f,888474ffa18bd2c492563dc2212d3def7589644b..112a1e9929dd68f667fa915bc318eef026b0bd64
@@@ -113,7 -113,7 +113,7 @@@ typedef struct ShadeInpu
        
        /* internal face coordinates */
        float u, v, dx_u, dx_v, dy_u, dy_v;
 -      float co[3], view[3];
 +      float co[3], view[3], camera_co[3];
        
        /* copy from material, keep synced so we can do memcopy */
        /* current size: 23*4 */
        
        int xs, ys;                             /* pixel to be rendered */
        int mask;                               /* subsample mask */
+       float scanco[3];                /* original scanline coordinate without jitter */
        
        int samplenr;                   /* sample counter, to detect if we should do shadow again */
        int depth;                              /* 1 or larger on raytrace shading */
 +      int volume_depth;               /* number of intersections through volumes */
        
        /* stored copy of original face normal (facenor) 
         * before flipping. Used in Front/back output on geometry node */
index 54a8d4b0404b5e022a1094552f21db4723a14f40,54311d2515a3d1eb7b2092cbac5f726950506800..8aa102a04a43b459ea3d550ad762ad9caaa7df0e
@@@ -33,7 -33,6 +33,7 @@@ struct VlakRen
  struct StrandSegment;
  struct StrandPoint;
  struct ObjectInstanceRen obi;
 +struct Isect;
  
  /* shadeinput.c */
  
@@@ -53,12 -52,12 +53,13 @@@ typedef struct ShadeSample 
  
        /* also the node shader callback */
  void shade_material_loop(struct ShadeInput *shi, struct ShadeResult *shr);
 +void shade_volume_loop(struct ShadeInput *shi, struct ShadeResult *shr);
  
  void shade_input_set_triangle_i(struct ShadeInput *shi, struct ObjectInstanceRen *obi, struct VlakRen *vlr, short i1, short i2, short i3);
  void shade_input_set_triangle(struct ShadeInput *shi, volatile int obi, volatile int facenr, int normal_flip);
  void shade_input_copy_triangle(struct ShadeInput *shi, struct ShadeInput *from);
- void shade_input_set_viewco(struct ShadeInput *shi, float x, float y, float z);
+ void shade_input_calc_viewco(struct ShadeInput *shi, float x, float y, float z, float *view, float *dxyview, float *co, float *dxco, float *dyco);
+ void shade_input_set_viewco(struct ShadeInput *shi, float x, float y, float sx, float sy, float z);
  void shade_input_set_uv(struct ShadeInput *shi);
  void shade_input_set_normals(struct ShadeInput *shi);
  void shade_input_flip_normals(struct ShadeInput *shi);
@@@ -87,11 -86,7 +88,11 @@@ void shade_color(struct ShadeInput *shi
  void ambient_occlusion_to_diffuse(struct ShadeInput *shi, float *diff);
  void ambient_occlusion(struct ShadeInput *shi);
  
 +ListBase *get_lights(struct ShadeInput *shi);
  float lamp_get_visibility(struct LampRen *lar, float *co, float *lv, float *dist);
  void lamp_get_shadow(struct LampRen *lar, ShadeInput *shi, float inp, float *shadfac, int do_real);
  
  float fresnel_fac(float *view, float *vn, float fresnel, float fac);
 +
 +/* rayshade.c */
 +extern void shade_ray(struct Isect *is, struct ShadeInput *shi, struct ShadeResult *shr);
index 07b2a5d3c82408745d410c8076a0be789a8c45c4,2d229cb33878568cdbbaf1646121e06d4b08d595..4b663c6caa65e114f09372e6b63b99cbdd1b9958
@@@ -41,7 -41,6 +41,7 @@@
  #include "BLI_rand.h"
  #include "BLI_memarena.h"
  #include "BLI_ghash.h"
 +#include "BLI_kdtree.h"
  
  #include "DNA_armature_types.h"
  #include "DNA_camera_types.h"
  #include "envmap.h"
  #include "multires.h"
  #include "occlusion.h"
 +#include "pointdensity.h"
  #include "render_types.h"
  #include "rendercore.h"
  #include "renderdatabase.h"
@@@ -923,28 -921,6 +923,28 @@@ static void flag_render_node_material(R
        }
  }
  
 +static void check_material_is_textured(Material *ma)
 +{
 +      MTex *mtex;
 +      Tex *tex;
 +      int tex_nr;
 +      
 +      for(tex_nr=0; tex_nr<MAX_MTEX; tex_nr++) {
 +              if(ma->septex & (1<<tex_nr))
 +                      continue;
 +              
 +              if(ma->mtex[tex_nr]) {
 +                      mtex= ma->mtex[tex_nr];
 +                      tex= mtex->tex;
 +                      if(tex==NULL)
 +                              continue;
 +                      else
 +                              ma->flag |= MA_IS_TEXTURED;
 +                              return;
 +              }
 +      }
 +}
 +
  static Material *give_render_material(Render *re, Object *ob, int nr)
  {
        extern Material defmaterial;    /* material.c */
        if(ma->nodetree && ma->use_nodes)
                flag_render_node_material(re, ma->nodetree);
        
 +      if (ma->material_type == MA_VOLUME) re->r.mode |= R_RAYTRACE;
 +      
 +      check_material_is_textured(ma);
 +      
        return ma;
  }
  
@@@ -2051,7 -2023,6 +2051,7 @@@ static int render_new_particle_system(R
                strandbuf->surface= cache_strand_surface(re, obr, psmd->dm, mat, timeoffset);
  
  /* 4. clean up */
 +
        if(ma) do_mat_ipo(ma);
  
        if(orco1)
@@@ -2472,7 -2443,6 +2472,6 @@@ static int dl_surf_to_renderdata(Object
        VlakRen *vlr, *vlr1, *vlr2, *vlr3;
        Curve *cu= ob->data;
        float *data, n1[3];
-       /*float flen; - as yet unused */
        int u, v, orcoret= 0;
        int p1, p2, p3, p4, a;
        int sizeu, nsizeu, sizev, nsizev;
                        vlr= RE_findOrAddVlak(obr, obr->totvlak++);
                        vlr->v1= v1; vlr->v2= v2; vlr->v3= v3; vlr->v4= v4;
                        
-                       /* flen= CalcNormFloat4(vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co, n1); - as yet unused */
+                       CalcNormFloat4(vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co, n1);
+                       
                        VECCOPY(vlr->n, n1);
                        
                        vlr->mat= matar[ dl->col];
@@@ -2816,8 -2787,10 +2816,10 @@@ static void init_render_curve(Render *r
                                        for(a=0; a<dl->parts; a++) {
  
                                                frontside= (a >= dl->nr/2);
-                                               DL_SURFINDEX(dl->flag & DL_CYCL_U, dl->flag & DL_CYCL_V, dl->nr, dl->parts);
+                                               
+                                               if (surfindex_displist(dl, a, &b, &p1, &p2, &p3, &p4)==0)
+                                                       break;
+                                               
                                                p1+= startvert;
                                                p2+= startvert;
                                                p3+= startvert;
@@@ -4435,8 -4408,6 +4437,8 @@@ void RE_Database_Free(Render *re
        end_radio_render();
        end_render_materials();
        
 +      free_pointdensities(re);
 +      
        if(re->wrld.aosphere) {
                MEM_freeN(re->wrld.aosphere);
                re->wrld.aosphere= NULL;
@@@ -4887,10 -4858,6 +4889,10 @@@ void RE_Database_FromScene(Render *re, 
                        /* ENVIRONMENT MAPS */
                        if(!re->test_break())
                                make_envmaps(re);
 +                              
 +                      /* point density texture */
 +                      if(!re->test_break())
 +                              make_pointdensities(re);
                }
                
                if(!re->test_break())
index 453e8ddcd48f19261fd9926452ba32092fccab17,f822d41bb85c11b11fea21cf0a294cd3f6b8061a..c431340d770a229b37b847a8eb8e3dd533ded6f1
@@@ -205,7 -205,7 +205,7 @@@ void makeraytree(Render *re
        re->stats_draw(&re->i);
  }
  
 -static void shade_ray(Isect *is, ShadeInput *shi, ShadeResult *shr)
 +void shade_ray(Isect *is, ShadeInput *shi, ShadeResult *shr)
  {
        VlakRen *vlr= (VlakRen*)is->face;
        ObjectInstanceRen *obi= RAY_OBJECT_GET(&R, is->ob);
                        ntreeShaderExecTree(shi->mat->nodetree, shi, shr);
                        shi->mat= vlr->mat;             /* shi->mat is being set in nodetree */
                }
 -              else
 -                      shade_material_loop(shi, shr);
 -              
 +              else {
 +                      if (shi->mat->material_type == MA_SOLID) shade_material_loop(shi, shr);
 +                      else if (shi->mat->material_type == MA_VOLUME) shade_volume_loop(shi, shr);
 +              }
                /* raytrace likes to separate the spec color */
                VECSUB(shr->diff, shr->combined, shr->spec);
        }       
@@@ -1793,21 -1792,62 +1793,62 @@@ void ray_ao(ShadeInput *shi, float *sha
                ray_ao_spheresamp(shi, shadfac);
  }
  
+ static void ray_shadow_jittered_coords(ShadeInput *shi, int max, float jitco[RE_MAX_OSA][3], int *totjitco)
+ {
+       /* magic numbers for reordering sample positions to give better
+        * results with adaptive sample, when it usually only takes 4 samples */
+       int order8[8] = {0, 1, 5, 6, 2, 3, 4, 7};
+       int order11[11] = {1, 3, 8, 10, 0, 2, 4, 5, 6, 7, 9};
+       int order16[16] = {1, 3, 9, 12, 0, 6, 7, 8, 13, 2, 4, 5, 10, 11, 14, 15};
+       int count = count_mask(shi->mask);
+       /* for better antialising shadow samples are distributed over the subpixel
+        * sample coordinates, this only works for raytracing depth 0 though */
+       if(!shi->strand && shi->depth == 0 && count > 1 && count <= max) {
+               float xs, ys, zs, view[3];
+               int samp, ordsamp, tot= 0;
+               for(samp=0; samp<R.osa; samp++) {
+                       if(R.osa == 8) ordsamp = order8[samp];
+                       else if(R.osa == 11) ordsamp = order11[samp];
+                       else if(R.osa == 16) ordsamp = order16[samp];
+                       else ordsamp = samp;
+                       if(shi->mask & (1<<ordsamp)) {
+                               /* zbuffer has this inverse corrected, ensures xs,ys are inside pixel */
+                               xs= (float)shi->scanco[0] + R.jit[ordsamp][0] + 0.5f;
+                               ys= (float)shi->scanco[1] + R.jit[ordsamp][1] + 0.5f;
+                               zs= shi->scanco[2];
+                               shade_input_calc_viewco(shi, xs, ys, zs, view, NULL, jitco[tot], NULL, NULL);
+                               tot++;
+                       }
+               }
+               *totjitco= tot;
+       }
+       else {
+               VECCOPY(jitco[0], shi->co);
+               *totjitco= 1;
+       }
+ }
  
  static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, float *lampco, float *shadfac, Isect *isec)
  {
        QMCSampler *qsa=NULL;
-       QMCSampler *qsa_jit=NULL;
        int samples=0;
-       float samp3d[3], jit[3], jitbias= 0.0f;
+       float samp3d[3];
  
        float fac=0.0f, vec[3];
        float colsq[4];
        float adapt_thresh = lar->adapt_thresh;
-       int max_samples = lar->ray_totsamp;
-       float pos[3];
+       int min_adapt_samples=4, max_samples = lar->ray_totsamp;
+       float *co;
        int do_soft=1, full_osa=0;
  
+       float jitco[RE_MAX_OSA][3];
+       int totjitco;
        colsq[0] = colsq[1] = colsq[2] = 0.0;
        if(isec->mode==RE_RAY_SHADOW_TRA) {
                shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 0.0f;
                if (do_soft) max_samples = lar->ray_totsamp;
                else max_samples = (R.osa > 4)?R.osa:5;
        }
-       if(shi->vlr && ((shi->vlr->flag & R_FULL_OSA) == 0))
-               jitbias= 0.5f*(VecLength(shi->dxco) + VecLength(shi->dyco));
+       
+       ray_shadow_jittered_coords(shi, max_samples, jitco, &totjitco);
  
        /* sampling init */
-       if (lar->ray_samp_method==LA_SAMP_HALTON) {
+       if (lar->ray_samp_method==LA_SAMP_HALTON)
                qsa = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HALTON, max_samples);
-               qsa_jit = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HALTON, max_samples);
-       } else if (lar->ray_samp_method==LA_SAMP_HAMMERSLEY) {
+       else if (lar->ray_samp_method==LA_SAMP_HAMMERSLEY)
                qsa = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HAMMERSLEY, max_samples);
-               qsa_jit = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HAMMERSLEY, max_samples);
-       }
        
        QMC_initPixel(qsa, shi->thread);
-       QMC_initPixel(qsa_jit, shi->thread);
        
        VECCOPY(vec, lampco);
        
        while (samples < max_samples) {
                isec->faceorig= (RayFace*)shi->vlr;
                isec->oborig= RAY_OBJECT_SET(&R, shi->obi);
-               
                /* manually jitter the start shading co-ord per sample
                 * based on the pre-generated OSA texture sampling offsets, 
                 * for anti-aliasing sharp shadow edges. */
-               VECCOPY(pos, shi->co);
-               if (shi->vlr && !full_osa) {
-                       QMC_sampleRect(jit, qsa_jit, shi->thread, samples, 1.0, 1.0);
-                       
-                       pos[0] += shi->dxco[0]*jit[0] + shi->dyco[0]*jit[1];
-                       pos[1] += shi->dxco[1]*jit[0] + shi->dyco[1]*jit[1];
-                       pos[2] += shi->dxco[2]*jit[0] + shi->dyco[2]*jit[1];
-               }
+               co = jitco[samples % totjitco];
  
                if (do_soft) {
                        /* sphere shadow source */
                                float ru[3], rv[3], v[3], s[3];
                                
                                /* calc tangent plane vectors */
-                               v[0] = pos[0] - lampco[0];
-                               v[1] = pos[1] - lampco[1];
-                               v[2] = pos[2] - lampco[2];
+                               v[0] = co[0] - lampco[0];
+                               v[1] = co[1] - lampco[1];
+                               v[2] = co[2] - lampco[2];
                                Normalize(v);
                                VecOrthoBasisf(v, ru, rv);
                                
                                s[2] = samp3d[0]*ru[2] + samp3d[1]*rv[2];
                                
                                VECCOPY(samp3d, s);
-                               if(jitbias != 0.0f) {
-                                       /* bias away somewhat to avoid self intersection */
-                                       pos[0] -= jitbias*v[0];
-                                       pos[1] -= jitbias*v[1];
-                                       pos[2] -= jitbias*v[2];
-                               }
                        }
                        else {
                                /* sampling, returns quasi-random vector in [sizex,sizey]^2 plane */
                        VECCOPY(isec->end, vec);
                }
  
-               if(jitbias != 0.0f && !(do_soft && lar->type==LA_LOCAL)) {
+               if(shi->strand) {
                        /* bias away somewhat to avoid self intersection */
+                       float jitbias= 0.5f*(VecLength(shi->dxco) + VecLength(shi->dyco));
                        float v[3];
  
-                       VECSUB(v, pos, isec->end);
+                       VECSUB(v, co, isec->end);
                        Normalize(v);
  
-                       pos[0] -= jitbias*v[0];
-                       pos[1] -= jitbias*v[1];
-                       pos[2] -= jitbias*v[2];
+                       co[0] -= jitbias*v[0];
+                       co[1] -= jitbias*v[1];
+                       co[2] -= jitbias*v[2];
                }
  
-               VECCOPY(isec->start, pos);
-               
+               VECCOPY(isec->start, co);
                
                /* trace the ray */
                if(isec->mode==RE_RAY_SHADOW_TRA) {
                if ((lar->ray_samp_method == LA_SAMP_HALTON)) {
                
                        /* adaptive sampling - consider samples below threshold as in shadow (or vice versa) and exit early */
-                       if ((max_samples > 4) && (adapt_thresh > 0.0) && (samples > max_samples / 3)) {
+                       if ((max_samples > min_adapt_samples) && (adapt_thresh > 0.0) && (samples > max_samples / 3)) {
                                if (isec->mode==RE_RAY_SHADOW_TRA) {
                                        if ((shadfac[3] / samples > (1.0-adapt_thresh)) || (shadfac[3] / samples < adapt_thresh))
                                                break;
        } else
                shadfac[3]= 1.0f-fac/samples;
  
-       if (qsa_jit)
-               release_thread_qmcsampler(&R, shi->thread, qsa_jit);
        if (qsa)
                release_thread_qmcsampler(&R, shi->thread, qsa);
  }
index 13dabb2a1db68d33c60749b810e78bef089245ac,476330152ecd47dbf90f67ff1dc55fa6dd2df9a3..aa11e3d75ddaf2e23d5a9cb101f906ed3f7d3ec0
@@@ -135,12 -135,6 +135,12 @@@ void shade_material_loop(ShadeInput *sh
        }       
  }
  
 +/* delivers a fully filled in ShadeResult, for all passes */
 +void shade_volume_loop(ShadeInput *shi, ShadeResult *shr)
 +{
 +      if(R.r.mode & R_RAYTRACE) volume_trace(shi, shr);
 +}
 +
  
  /* do a shade, finish up some passes, apply mist */
  void shade_input_do_shade(ShadeInput *shi, ShadeResult *shr)
                memcpy(&shi->r, &shi->mat->r, 23*sizeof(float));
                shi->har= shi->mat->har;
                
 -              shade_material_loop(shi, shr);
 +              if (shi->mat->material_type == MA_SOLID) shade_material_loop(shi, shr);
 +              else if (shi->mat->material_type == MA_VOLUME) shade_volume_loop(shi, shr);
        }
        
        /* copy additional passes */
@@@ -580,31 -573,25 +580,25 @@@ void shade_input_set_strand_texco(Shade
        }
  }
  
- /* scanline pixel coordinates */
- /* requires set_triangle */
- void shade_input_set_viewco(ShadeInput *shi, float x, float y, float z)
+ /* from scanline pixel coordinates to 3d coordinates, requires set_triangle */
+ void shade_input_calc_viewco(ShadeInput *shi, float x, float y, float z, float *view, float *dxyview, float *co, float *dxco, float *dyco)
  {
-       float fac;
+       /* returns not normalized, so is in viewplane coords */
+       calc_view_vector(view, x, y);
        
-       /* currently in use for dithering (soft shadow), node preview, irregular shad */
-       shi->xs= (int)(x);
-       shi->ys= (int)(y);
-       
-       calc_view_vector(shi->view, x, y);      /* returns not normalized, so is in viewplane coords */
-       
-       /* wire cannot use normal for calculating shi->co */
        if(shi->mat->mode & MA_WIRE) {
-               
+               /* wire cannot use normal for calculating shi->co, so
+                * we reconstruct the coordinate less accurate */
                if(R.r.mode & R_ORTHO)
-                       calc_renderco_ortho(shi->co, x, y, z);
+                       calc_renderco_ortho(co, x, y, z);
                else
-                       calc_renderco_zbuf(shi->co, shi->view, z);
+                       calc_renderco_zbuf(co, view, z);
        }
        else {
-               float dface, v1[3];
+               /* for non-wire, intersect with the triangle to get the exact coord */
+               float fac, dface, v1[3];
                
                VECCOPY(v1, shi->v1->co);
                if(shi->obi->flag & R_TRANSFORMED)
                        Mat4MulVecfl(shi->obi->mat, v1);
                
                        float fx= 2.0f/(R.winx*R.winmat[0][0]);
                        float fy= 2.0f/(R.winy*R.winmat[1][1]);
                        
-                       shi->co[0]= (x - 0.5f*R.winx)*fx - R.winmat[3][0]/R.winmat[0][0];
-                       shi->co[1]= (y - 0.5f*R.winy)*fy - R.winmat[3][1]/R.winmat[1][1];
+                       co[0]= (x - 0.5f*R.winx)*fx - R.winmat[3][0]/R.winmat[0][0];
+                       co[1]= (y - 0.5f*R.winy)*fy - R.winmat[3][1]/R.winmat[1][1];
                        
                        /* using a*x + b*y + c*z = d equation, (a b c) is normal */
                        if(shi->facenor[2]!=0.0f)
-                               shi->co[2]= (dface - shi->facenor[0]*shi->co[0] - shi->facenor[1]*shi->co[1])/shi->facenor[2];
+                               co[2]= (dface - shi->facenor[0]*co[0] - shi->facenor[1]*co[1])/shi->facenor[2];
                        else
-                               shi->co[2]= 0.0f;
+                               co[2]= 0.0f;
                        
-                       if(shi->osatex || (R.r.mode & R_SHADOW) ) {
-                               shi->dxco[0]= fx;
-                               shi->dxco[1]= 0.0f;
+                       if(dxco && dyco) {
+                               dxco[0]= fx;
+                               dxco[1]= 0.0f;
                                if(shi->facenor[2]!=0.0f)
-                                       shi->dxco[2]= (shi->facenor[0]*fx)/shi->facenor[2];
+                                       dxco[2]= (shi->facenor[0]*fx)/shi->facenor[2];
                                else 
-                                       shi->dxco[2]= 0.0f;
+                                       dxco[2]= 0.0f;
                                
-                               shi->dyco[0]= 0.0f;
-                               shi->dyco[1]= fy;
+                               dyco[0]= 0.0f;
+                               dyco[1]= fy;
                                if(shi->facenor[2]!=0.0f)
-                                       shi->dyco[2]= (shi->facenor[1]*fy)/shi->facenor[2];
+                                       dyco[2]= (shi->facenor[1]*fy)/shi->facenor[2];
                                else 
-                                       shi->dyco[2]= 0.0f;
+                                       dyco[2]= 0.0f;
                                
-                               if( (shi->mat->texco & TEXCO_REFL) ) {
-                                       if(shi->co[2]!=0.0f) fac= 1.0f/shi->co[2]; else fac= 0.0f;
-                                       shi->dxview= -R.viewdx*fac;
-                                       shi->dyview= -R.viewdy*fac;
+                               if(dxyview) {
+                                       if(co[2]!=0.0f) fac= 1.0f/co[2]; else fac= 0.0f;
+                                       dxyview[0]= -R.viewdx*fac;
+                                       dxyview[1]= -R.viewdy*fac;
                                }
                        }
                }
                else {
                        float div;
                        
-                       div= shi->facenor[0]*shi->view[0] + shi->facenor[1]*shi->view[1] + shi->facenor[2]*shi->view[2];
+                       div= shi->facenor[0]*view[0] + shi->facenor[1]*view[1] + shi->facenor[2]*view[2];
                        if (div!=0.0f) fac= dface/div;
                        else fac= 0.0f;
                        
-                       shi->co[0]= fac*shi->view[0];
-                       shi->co[1]= fac*shi->view[1];
-                       shi->co[2]= fac*shi->view[2];
+                       co[0]= fac*view[0];
+                       co[1]= fac*view[1];
+                       co[2]= fac*view[2];
                        
                        /* pixel dx/dy for render coord */
-                       if(shi->osatex || (R.r.mode & R_SHADOW) ) {
+                       if(dxco && dyco) {
                                float u= dface/(div - R.viewdx*shi->facenor[0]);
                                float v= dface/(div - R.viewdy*shi->facenor[1]);
                                
-                               shi->dxco[0]= shi->co[0]- (shi->view[0]-R.viewdx)*u;
-                               shi->dxco[1]= shi->co[1]- (shi->view[1])*u;
-                               shi->dxco[2]= shi->co[2]- (shi->view[2])*u;
+                               dxco[0]= co[0]- (view[0]-R.viewdx)*u;
+                               dxco[1]= co[1]- (view[1])*u;
+                               dxco[2]= co[2]- (view[2])*u;
                                
-                               shi->dyco[0]= shi->co[0]- (shi->view[0])*v;
-                               shi->dyco[1]= shi->co[1]- (shi->view[1]-R.viewdy)*v;
-                               shi->dyco[2]= shi->co[2]- (shi->view[2])*v;
+                               dyco[0]= co[0]- (view[0])*v;
+                               dyco[1]= co[1]- (view[1]-R.viewdy)*v;
+                               dyco[2]= co[2]- (view[2])*v;
                                
-                               if( (shi->mat->texco & TEXCO_REFL) ) {
+                               if(dxyview) {
                                        if(fac!=0.0f) fac= 1.0f/fac;
-                                       shi->dxview= -R.viewdx*fac;
-                                       shi->dyview= -R.viewdy*fac;
+                                       dxyview[0]= -R.viewdx*fac;
+                                       dxyview[1]= -R.viewdy*fac;
                                }
                        }
                }
        }
        
 +      /* set camera coords - for scanline, it's always 0.0,0.0,0.0 (render is in camera space)
 +       * however for raytrace it can be different - the position of the last intersection */
 +      shi->camera_co[0] = shi->camera_co[1] = shi->camera_co[2] = 0.0f;
 +      
        /* cannot normalize earlier, code above needs it at viewplane level */
-       Normalize(shi->view);
+       Normalize(view);
+ }
+ /* from scanline pixel coordinates to 3d coordinates, requires set_triangle */
+ void shade_input_set_viewco(ShadeInput *shi, float x, float y, float xs, float ys, float z)
+ {
+       float *dxyview= NULL, *dxco= NULL, *dyco= NULL;
+       
+       /* currently in use for dithering (soft shadow), node preview, irregular shad */
+       shi->xs= (int)xs;
+       shi->ys= (int)ys;
+       /* original scanline coordinate without jitter */
+       shi->scanco[0]= x;
+       shi->scanco[1]= y;
+       shi->scanco[2]= z;
+       /* check if we need derivatives */
+       if(shi->osatex || (R.r.mode & R_SHADOW)) {
+               dxco= shi->dxco;
+               dyco= shi->dyco;
+               if((shi->mat->texco & TEXCO_REFL))
+                       dxyview= &shi->dxview;
+       }
+       shade_input_calc_viewco(shi, xs, ys, z, shi->view, dxyview, shi->co, dxco, dyco);
  }
  
  /* calculate U and V, for scanline (silly render face u and v are in range -1 to 0) */
@@@ -1312,7 -1321,8 +1332,8 @@@ void shade_samples_fill_with_ps(ShadeSa
                                
                                for(samp=0; samp<R.osa; samp++) {
                                        if(curmask & (1<<samp)) {
-                                               xs= (float)x + R.jit[samp][0] + 0.5f;   /* zbuffer has this inverse corrected, ensures xs,ys are inside pixel */
+                                               /* zbuffer has this inverse corrected, ensures xs,ys are inside pixel */
+                                               xs= (float)x + R.jit[samp][0] + 0.5f;
                                                ys= (float)y + R.jit[samp][1] + 0.5f;
                                                
                                                if(shi_cp)
                                                shi->mask= (1<<samp);
  //                                            shi->rl= ssamp->rlpp[samp];
                                                shi->samplenr= R.shadowsamplenr[shi->thread]++; /* this counter is not being reset per pixel */
-                                               shade_input_set_viewco(shi, xs, ys, (float)ps->z);
+                                               shade_input_set_viewco(shi, x, y, xs, ys, (float)ps->z);
                                                shade_input_set_uv(shi);
                                                shade_input_set_normals(shi);
                                                
                                        xs= (float)x + 0.5f;
                                        ys= (float)y + 0.5f;
                                }
                                shi->mask= curmask;
                                shi->samplenr= R.shadowsamplenr[shi->thread]++;
-                               shade_input_set_viewco(shi, xs, ys, (float)ps->z);
+                               shade_input_set_viewco(shi, x, y, xs, ys, (float)ps->z);
                                shade_input_set_uv(shi);
                                shade_input_set_normals(shi);
                                shi++;
index 6ec8ce78e73118668afee848ae5120596a26a787,989684895c8cf0bb1406e63bf8946dcd7dd4633f..7be862b0f15b28fb99ee125fa813d8e87ebe0aa8
@@@ -731,107 -731,6 +731,107 @@@ static void texture_panel_voronoi(Tex *
        uiDefButF(block, NUMSLI, B_TEXPRV, "W4: ", 10, 10, 150, 19, &tex->vn_w4, -2.0, 2.0, 10, 0, "Sets feature weight 4");
  }
  
 +static void texture_panel_pointdensity(Tex *tex)
 +{
 +      uiBlock *block;
 +      PointDensity *pd;
 +      short yco=PANEL_YMAX;
 +      
 +      block= uiNewBlock(&curarea->uiblocks, "texture_panel_pointdensity", UI_EMBOSS, UI_HELV, curarea->win);
 +      if(uiNewPanel(curarea, block, "Point Density", "Texture", PANELX, PANELY, PANELW, PANELH)==0) return;
 +      uiSetButLock(tex->id.lib!=0, ERROR_LIBDATA_MESSAGE);
 +      
 +      if(tex->pd==NULL) {
 +              tex->pd= BKE_add_pointdensity();
 +              tex->pd->object= OBACT;
 +      }
 +      if(tex->pd) {
 +              pd= tex->pd;
 +
 +              uiDefBut(block, LABEL, B_NOP, "Density estimation:",
 +                      X2CLM1, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, "");
 +
 +              uiDefButF(block, NUM, B_REDR, "Radius: ",
 +                      X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->radius), 0.001, 100.0, 10, 2, "Radius to look for nearby particles within");
 +              
 +              yco -= YSPACE;
 +              
 +              uiDefBut(block, LABEL, B_NOP, "Falloff:",
 +                      X2CLM1, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, "");     
 +              uiDefButS(block, MENU, B_REDR, "Standard %x0|Smooth %x1|Sharp %x2|Constant %x3|Root %x4",
 +                      X2CLM1, yco-=BUTH, BUTW2, BUTH, &pd->falloff_type, 0.0, 0.0, 0, 0, "Falloff type");
 +              
 +              yco -= YSPACE;
 +              
 +              
 +              uiBlockBeginAlign(block);
 +              uiDefButBitS(block, TOG, TEX_PD_TURBULENCE, B_REDR, "Turbulence",
 +                      X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->flag), 0, 0, 0, 0, "Add directed turbulence to the density estimation");
 +                      
 +              if (pd->flag & TEX_PD_TURBULENCE) {
 +                      
 +                      uiDefButF(block, NUM, B_REDR, "Size: ",
 +                              X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_size), 0.001, 100.0, 10, 2, "Turbulence size");
 +                      uiDefButS(block, NUM, B_REDR, "Depth: ",
 +                              X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_depth), 0.0, 100.0, 10, 2, "Turbulence depth");
 +                      uiDefButF(block, NUM, B_REDR, "Strength: ",
 +                              X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_fac), 0.001, 100.0, 10, 2, "");
 +                      
 +                      uiBlockEndAlign(block);
 +                      
 +                      yco -= YSPACE;
 +
 +                      if (pd->source == TEX_PD_PSYS) {
 +                              uiDefButS(block, MENU, B_REDR, "Noise Influence %t|Static %x0|Velocity %x1|Angular Velocity %x2",
 +                                      X2CLM1, yco-=BUTH, BUTW2, BUTH, &(pd->noise_influence), 0.0, 0.0, 0, 0, "Noise Influence");
 +                      }
 +              }
 +              uiBlockEndAlign(block);
 +
 +              yco = PANEL_YMAX;
 +              
 +              uiDefBut(block, LABEL, B_NOP, "Point data source:",
 +                      X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, "");
 +              
 +              uiDefButS(block, MENU, B_TEXREDR_PRV, "Particle System %x0|Object Vertices %x1",
 +                      X2CLM2, yco-=BUTH, BUTW2, BUTH, &pd->source, 0.0, 0.0, 0, 0, "Source");
 +              
 +              yco -= YSPACE;
 +              
 +              if (pd->source == TEX_PD_PSYS) {
 +                      uiBlockBeginAlign(block);
 +                      uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_REDR, "Ob:",
 +                              X2CLM2, yco-=BUTH, BUTW2, BUTH, &(pd->object), "Object that has the particle system");
 +                              
 +                      if (pd->object && pd->object->particlesystem.first) {
 +                              uiDefButS(block, NUM, B_REDR, "PSys:", 
 +                                      X2CLM2, yco-=BUTH, BUTW2, BUTH, &(pd->psysindex), 1, 10, 10, 3, "Particle system number in the object");
 +                      }
 +                      uiBlockEndAlign(block);
 +                      
 +                      yco -= YSPACE;
 +                      
 +                      uiDefBut(block, LABEL, B_NOP, "Cache particles in:",
 +                              X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, "");
 +                      uiDefButS(block, MENU, B_TEXREDR_PRV, "Emit Object Location %x0|Emit Object Space %x1|Global Space %x2",
 +                              X2CLM2, yco-=BUTH, BUTW2, BUTH, &pd->psys_cache_space, 0.0, 0.0, 0, 0, "Co-ordinate system to cache particles in");
 +                              
 +              }
 +              else if (pd->source == TEX_PD_OBJECT) {
 +                      uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_REDR, "Ob:",
 +                              X2CLM2, yco-=BUTH, BUTW2, BUTH, &(pd->object), "Object to render as points");
 +                      
 +                      yco -= YSPACE;
 +                      
 +                      uiDefBut(block, LABEL, B_NOP, "Cache vertices in:",
 +                              X2CLM2, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, "");
 +                      uiDefButS(block, MENU, B_TEXREDR_PRV, "Object Location %x0|Object Space %x1|Global Space %x2",
 +                              X2CLM2, yco-=BUTH, BUTW2, BUTH, &pd->ob_cache_space, 0.0, 0.0, 0, 0, "Co-ordinate system to cache vertices in");
 +              }
 +      }
 +
 +}
 +
  
  static char *layer_menu(RenderResult *rr, short *curlay)
  {
@@@ -963,7 -862,9 +963,9 @@@ static void image_unlink_cb(void *ima_p
        
        if(ima_pp && *ima_pp) {
                Image *ima= *ima_pp;
-               ima->id.us--;
+               /* (for time being, texturefaces are no users, conflict in design...) */
+               if(ima->id.us>1)
+                       ima->id.us--;
                *ima_pp= NULL;
        }
  }
@@@ -1789,7 -1690,7 +1791,7 @@@ static void texture_panel_texture(MTex 
                /* newnoise: all texture types as menu, not enough room for more buttons.
                 * Can widen panel, but looks ugly when other panels overlap it */
                
 -              sprintf(textypes, "Texture Type %%t|None %%x%d|Image %%x%d|EnvMap %%x%d|Clouds %%x%d|Marble %%x%d|Stucci %%x%d|Wood %%x%d|Magic %%x%d|Blend %%x%d|Noise %%x%d|Plugin %%x%d|Musgrave %%x%d|Voronoi %%x%d|DistortedNoise %%x%d", 0, TEX_IMAGE, TEX_ENVMAP, TEX_CLOUDS, TEX_MARBLE, TEX_STUCCI, TEX_WOOD, TEX_MAGIC, TEX_BLEND, TEX_NOISE, TEX_PLUGIN, TEX_MUSGRAVE, TEX_VORONOI, TEX_DISTNOISE);
 +              sprintf(textypes, "Texture Type %%t|None %%x%d|Image %%x%d|EnvMap %%x%d|Clouds %%x%d|Marble %%x%d|Stucci %%x%d|Wood %%x%d|Magic %%x%d|Blend %%x%d|Noise %%x%d|Plugin %%x%d|Musgrave %%x%d|Voronoi %%x%d|DistortedNoise %%x%d|Point Density %%x%d", 0, TEX_IMAGE, TEX_ENVMAP, TEX_CLOUDS, TEX_MARBLE, TEX_STUCCI, TEX_WOOD, TEX_MAGIC, TEX_BLEND, TEX_NOISE, TEX_PLUGIN, TEX_MUSGRAVE, TEX_VORONOI, TEX_DISTNOISE, TEX_POINTDENSITY);
                uiDefBut(block, LABEL, 0, "Texture Type",               160, 150, 140, 20, 0, 0.0, 0.0, 0, 0, "");
                uiDefButS(block, MENU, B_TEXTYPE, textypes,     160, 125, 140, 25, &tex->type, 0,0,0,0, "Select texture type");
  
@@@ -2529,6 -2430,7 +2531,7 @@@ void do_lampbuts(unsigned short event
        case B_SHADBUF:
                la= G.buts->lockpoin; 
                la->mode &= ~LA_SHAD_RAY;
+               BIF_preview_changed(ID_LA);
                allqueue(REDRAWBUTSSHADING, 0); 
                allqueue(REDRAWVIEW3D, 0);              
                break;
                /* yafray: 'softlight' uses it's own shadbuf. flag.
                   Must be cleared here too when switching from ray shadow */
                la->mode &= ~LA_YF_SOFT;
+               BIF_preview_changed(ID_LA);
                allqueue(REDRAWBUTSSHADING, 0);
                allqueue(REDRAWVIEW3D, 0);      
                break;
@@@ -3516,12 -3419,6 +3520,12 @@@ static void material_panel_map_to(Objec
                uiDefButBitS(block, TOG, 1, B_MATPRV, "PAttr",          250,160,60,19, &pattr, 0, 0, 0, 0, "Display settings for particle attributes");
                uiBlockSetCol(block, TH_AUTO);
        }
 +      else if (ma->material_type == MA_VOLUME) {
 +              uiDefButBitS(block, TOG3, MAP_ALPHA, B_MATPRV, "Density",               10,180,60,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect the alpha value");
 +              uiDefButBitS(block, TOG3, MAP_EMIT, B_MATPRV, "Emit",           70,180,50,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect the emit value");
 +              uiDefButBitS(block, TOG, MAP_COL, B_MATPRV, "Emit Col",         120,180,80,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect basic color of the material");
 +              uiDefButBitS(block, TOG, MAP_COLMIR, B_MATPRV, "Absorb Col",            200,180,80,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect basic color of the material");
 +      }
        else {
                uiDefButBitS(block, TOG, MAP_COL, B_MATPRV, "Col",              10,180,40,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect basic color of the material");
                uiDefButBitS(block, TOG3, MAP_NORM, B_MATPRV, "Nor",            50,180,40,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect the rendered normal");
@@@ -3638,46 -3535,37 +3642,46 @@@ static void material_panel_map_input(Ob
        
        /* TEXCO */
        uiBlockBeginAlign(block);
 -      uiDefButS(block, ROW, B_MATPRV, "Glob",                 630,180,45,18, &(mtex->texco), 4.0, (float)TEXCO_GLOB, 0, 0, "Uses global coordinates for the texture coordinates");
 -      uiDefButS(block, ROW, B_MATPRV, "Object",               675,180,75,18, &(mtex->texco), 4.0, (float)TEXCO_OBJECT, 0, 0, "Uses linked object's coordinates for texture coordinates");
 -      if(mtex->texco == TEXCO_UV && !(mtex->texflag & MTEX_DUPLI_MAPTO)) {
 -              if(!verify_valid_uv_name(mtex->uvname))
 -            uiBlockSetCol(block, TH_REDALERT);
 -              but=uiDefBut(block, TEX, B_MATPRV, "UV:", 750,180,158,18, mtex->uvname, 0, 31, 0, 0, "Set name of UV layer to use, default is active UV layer");
 -              uiButSetCompleteFunc(but, autocomplete_uv, NULL);
 -              uiBlockSetCol(block, TH_AUTO);
 -      }
 -      else
 -              uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_MATPRV, "Ob:",750,180,158,18, &(mtex->object), "");
        
 -      uiDefButS(block, ROW, B_MATPRV, "UV",                   630,160,40,18, &(mtex->texco), 4.0, (float)TEXCO_UV, 0, 0, "Uses UV coordinates for texture coordinates");
 -      uiDefButS(block, ROW, B_MATPRV, "Orco",                 670,160,55,18, &(mtex->texco), 4.0, (float)TEXCO_ORCO, 0, 0, "Uses the original undeformed coordinates of the object");
 -      if( ob->particlesystem.first )
 -              uiDefButS(block, ROW, B_MATPRV, "Strand",       725,160,50,18, &(mtex->texco), 4.0, (float)TEXCO_STRAND, 0, 0, "Uses normalized strand texture coordinate (1D)");
 -      else
 -              uiDefButS(block, ROW, B_MATPRV, "Stick",        725,160,50,18, &(mtex->texco), 4.0, (float)TEXCO_STICKY, 0, 0, "Uses mesh's sticky coordinates for the texture coordinates");
 -      uiDefButS(block, ROW, B_MATPRV, "Win",                  775,160,45,18, &(mtex->texco), 4.0, (float)TEXCO_WINDOW, 0, 0, "Uses screen coordinates as texture coordinates");
 -      uiDefButS(block, ROW, B_MATPRV, "Nor",                  820,160,44,18, &(mtex->texco), 4.0, (float)TEXCO_NORM, 0, 0, "Uses normal vector as texture coordinates");
 -      uiDefButS(block, ROW, B_MATPRV, "Refl",                 864,160,44,18, &(mtex->texco), 4.0, (float)TEXCO_REFL, 0, 0, "Uses reflection vector as texture coordinates");
 +      if (ma->material_type == MA_VOLUME) {
 +              uiDefButS(block, ROW, B_MATPRV, "Glob",                 630,180,45,18, &(mtex->texco), 4.0, (float)TEXCO_GLOB, 0, 0, "Uses global coordinates for the texture coordinates");
 +              uiDefButS(block, ROW, B_MATPRV, "Object",               675,180,75,18, &(mtex->texco), 4.0, (float)TEXCO_OBJECT, 0, 0, "Uses linked object's coordinates for texture coordinates");
 +              uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_MATPRV, "Ob:",750,180,158,18, &(mtex->object), "");
 +              uiDefButS(block, ROW, B_MATPRV, "Local",                630,160,55,18, &(mtex->texco), 4.0, (float)TEXCO_ORCO, 0, 0, "Uses the original undeformed coordinates of the object");
        
 -      uiDefButS(block, ROW, B_MATPRV, "Stress",               630,140,70,18, &(mtex->texco), 4.0, (float)TEXCO_STRESS, 0, 0, "Uses the difference of edge lengths compared to original coordinates of the mesh");
 -      uiDefButS(block, ROW, B_MATPRV, "Tangent",              700,140,70,18, &(mtex->texco), 4.0, (float)TEXCO_TANGENT, 0, 0, "Uses the optional tangent vector as texture coordinates");
 -      uiBlockEndAlign(block);
  
 -      if(ELEM(mtex->texco, TEXCO_UV, TEXCO_ORCO))
 -              uiDefButBitS(block, TOG, MTEX_DUPLI_MAPTO, B_MATPRV, "From Dupli",      820,140,88,18, &(mtex->texflag), 0, 0, 0, 0, "Dupli's instanced from verts, faces or particles, inherit texture coordinate from their parent");
 -      else if(mtex->texco == TEXCO_OBJECT)
 -              uiDefButBitS(block, TOG, MTEX_OB_DUPLI_ORIG, B_MATPRV, "From Original", 820,140,88,18, &(mtex->texflag), 0, 0, 0, 0, "Dupli's derive their object coordinates from the original objects transformation");
 +      } else {
 +              uiDefButS(block, ROW, B_MATPRV, "Glob",                 630,180,45,18, &(mtex->texco), 4.0, (float)TEXCO_GLOB, 0, 0, "Uses global coordinates for the texture coordinates");
 +              uiDefButS(block, ROW, B_MATPRV, "Object",               675,180,75,18, &(mtex->texco), 4.0, (float)TEXCO_OBJECT, 0, 0, "Uses linked object's coordinates for texture coordinates");
 +              if(mtex->texco == TEXCO_UV && !(mtex->texflag & MTEX_DUPLI_MAPTO)) {
 +                      if(!verify_valid_uv_name(mtex->uvname))
 +                              uiBlockSetCol(block, TH_REDALERT);
 +                      but=uiDefBut(block, TEX, B_MATPRV, "UV:", 750,180,158,18, mtex->uvname, 0, 31, 0, 0, "Set name of UV layer to use, default is active UV layer");
 +                      uiButSetCompleteFunc(but, autocomplete_uv, NULL);
 +                      uiBlockSetCol(block, TH_AUTO);
 +              }
 +              else
 +                      uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_MATPRV, "Ob:",750,180,158,18, &(mtex->object), "");
 +              
 +              uiDefButS(block, ROW, B_MATPRV, "UV",                   630,160,40,18, &(mtex->texco), 4.0, (float)TEXCO_UV, 0, 0, "Uses UV coordinates for texture coordinates");
 +              uiDefButS(block, ROW, B_MATPRV, "Orco",                 670,160,55,18, &(mtex->texco), 4.0, (float)TEXCO_ORCO, 0, 0, "Uses the original undeformed coordinates of the object");
 +              if( ob->particlesystem.first )
 +                      uiDefButS(block, ROW, B_MATPRV, "Strand",       725,160,50,18, &(mtex->texco), 4.0, (float)TEXCO_STRAND, 0, 0, "Uses normalized strand texture coordinate (1D)");
 +              else
 +                      uiDefButS(block, ROW, B_MATPRV, "Stick",        725,160,50,18, &(mtex->texco), 4.0, (float)TEXCO_STICKY, 0, 0, "Uses mesh's sticky coordinates for the texture coordinates");
 +              uiDefButS(block, ROW, B_MATPRV, "Win",                  775,160,45,18, &(mtex->texco), 4.0, (float)TEXCO_WINDOW, 0, 0, "Uses screen coordinates as texture coordinates");
 +              uiDefButS(block, ROW, B_MATPRV, "Nor",                  820,160,44,18, &(mtex->texco), 4.0, (float)TEXCO_NORM, 0, 0, "Uses normal vector as texture coordinates");
 +              uiDefButS(block, ROW, B_MATPRV, "Refl",                 864,160,44,18, &(mtex->texco), 4.0, (float)TEXCO_REFL, 0, 0, "Uses reflection vector as texture coordinates");
 +              
 +              uiDefButS(block, ROW, B_MATPRV, "Stress",               630,140,70,18, &(mtex->texco), 4.0, (float)TEXCO_STRESS, 0, 0, "Uses the difference of edge lengths compared to original coordinates of the mesh");
 +              uiDefButS(block, ROW, B_MATPRV, "Tangent",              700,140,70,18, &(mtex->texco), 4.0, (float)TEXCO_TANGENT, 0, 0, "Uses the optional tangent vector as texture coordinates");
 +              uiBlockEndAlign(block);
  
 +              if(ELEM(mtex->texco, TEXCO_UV, TEXCO_ORCO))
 +                      uiDefButBitS(block, TOG, MTEX_DUPLI_MAPTO, B_MATPRV, "From Dupli",      820,140,88,18, &(mtex->texflag), 0, 0, 0, 0, "Dupli's instanced from verts, faces or particles, inherit texture coordinate from their parent");
 +              else if(mtex->texco == TEXCO_OBJECT)
 +                      uiDefButBitS(block, TOG, MTEX_OB_DUPLI_ORIG, B_MATPRV, "From Original", 820,140,88,18, &(mtex->texflag), 0, 0, 0, 0, "Dupli's derive their object coordinates from the original objects transformation");
 +      }
  
        /* COORDS */
        uiBlockBeginAlign(block);
@@@ -4259,7 -4147,7 +4263,7 @@@ static uiBlock *strand_menu(void *mat_v
  }
  
  
 -static void material_panel_material(Material *ma)
 +static void material_panel_material_solid(Material *ma)
  {
        uiBlock *block;
        float *colpoin = NULL;
  
  }
  
 +static void material_panel_material_volume(Material *ma)
 +{
 +      uiBlock *block;
 +      short yco=PANEL_YMAX;
 +      
 +      block= uiNewBlock(&curarea->uiblocks, "material_panel_material_volume", UI_EMBOSS, UI_HELV, curarea->win);
 +      if(uiNewPanel(curarea, block, "Volume", "Material", PANELX, PANELY, PANELW, PANELH)==0) return;
 +      
 +      uiSetButLock(ma->id.lib!=NULL, ERROR_LIBDATA_MESSAGE);
 +      
 +      uiBlockBeginAlign(block);
 +      uiDefButF(block, NUM, B_MATPRV, "Step Size: ",
 +              X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_stepsize), 0.001, 100.0, 10, 2, "Ray marching step size");
 +      uiBlockEndAlign(block);
 +      
 +      yco -= YSPACE;
 +                      
 +      uiBlockBeginAlign(block);
 +      uiDefButBitS(block, TOG, MA_VOL_ATTENUATED, B_MATPRV, "Shading",
 +              X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_shadeflag), 0, 0, 0, 0, "Uses absorption for light attenuation");
 +      uiDefButF(block, NUM, B_MATPRV, "Step Size: ",
 +              X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_shade_stepsize), 0.001, 100.0, 10, 2, "Step");
 +      uiBlockEndAlign(block);
 +      
 +      yco -= YSPACE;
 +      
 +      uiBlockBeginAlign(block);
 +      uiDefButS(block, MENU, B_TEXREDR_PRV, "Scattering Direction %t|Isotropic %x0|Mie Hazy %x1|Mie Murky %x2|Rayleigh %x3|Henyey-Greenstein %x4|Schlick %x5",
 +              X2CLM1, yco-=BUTH, BUTW2, BUTH, &ma->vol_phasefunc_type, 0.0, 0.0, 0, 0, "Scattering Direction (Phase Function)");
 +      if (ELEM(ma->vol_phasefunc_type, MA_VOL_PH_HG, MA_VOL_PH_SCHLICK)) {
 +              uiDefButF(block, NUM, B_MATPRV, "Asymmetry: ",
 +                      X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->vol_phasefunc_g), -1.0, 1.0, 0, 0, "> 0 is forward scattering, < 0 is back scattering");
 +      }
 +      uiBlockEndAlign(block);
 +      
 +              
 +      yco = PANEL_YMAX;
 +      
 +      uiDefButF(block, NUMSLI, B_MATPRV, "Density: ",
 +              X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->alpha), 0.0, 1.0, 0, 0, "Base opacity value");
 +      
 +      yco -= YSPACE;
 +      
 +      uiBlockBeginAlign(block);
 +      uiDefButF(block, NUM, B_MATPRV, "Absorption: ",
 +              X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->vol_absorption), 0.0, 10.0, 10, 0, "Multiplier for absorption");
 +      uiDefButF(block, COL, B_MATPRV, "",
 +              X2CLM2, yco-=BUTH, BUTW2, BUTH, ma->vol_absorption_col, 0, 0, 0, B_MATCOL, "");
 +      uiBlockEndAlign(block);
 +
 +      yco -= YSPACE;
 +      
 +      uiBlockBeginAlign(block);
 +      uiDefButF(block, NUMSLI, B_MATPRV, "Emit: ",
 +              X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->emit), 0.0, 2.0, 0, 0, "Emission component");
 +      uiDefButF(block, COL, B_MATPRV, "",
 +              X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->r), 0, 0, 0, B_MATCOL, "");
 +      uiBlockEndAlign(block);
 +      
 +      yco -= YSPACE;
 +      
 +      uiDefButF(block, NUM, B_MATPRV, "Scattering: ",
 +              X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->vol_scattering), 0.0, 10.0, 10, 0, "Multiplier for scattering");
 +}
 +
  static void material_panel_nodes(Material *ma)
  {
        bNode *node;
@@@ -4450,7 -4273,7 +4454,7 @@@ static void material_panel_links(Objec
        
        block= uiNewBlock(&curarea->uiblocks, "material_panel_links", UI_EMBOSS, UI_HELV, curarea->win);
        /* 310 makes sorting code to put it right after preview panel */
 -      if(uiNewPanel(curarea, block, "Links and Pipeline", "Material", 310, 0, 318, 204)==0) return;
 +      if(uiNewPanel(curarea, block, "Links and Pipeline", "Material", 310, 0, 338, 204)==0) return;
  
        /* Links from object to material/nodes */
        uiDefBut(block, ROUNDBOX, 0, "",                                        5, 90, 310, 110, NULL, 7.0, 0.0, 15 , 20, ""); 
        uiDefButBitI(block, TOG, MA_ONLYCAST, B_MATPRV,"OnlyCast",              85,10,75,19, &(ma->mode), 0, 0, 0, 0, "Makes faces cast shadows only, not rendered");
        uiDefButBitI(block, TOG, MA_TRACEBLE, B_NOP,"Traceable",        160,10,75,19, &(ma->mode), 0, 0, 0, 0, "Makes material detectable by ray tracing");
        uiDefButBitI(block, TOG, MA_SHADBUF, B_MATPRV,  "Shadbuf",              235,10,75,19, &(ma->mode), 0, 0, 0, 0, "Makes material cast shadows from shadow buffer lamps");
 -                                
 +      uiBlockEndAlign(block);
 +      
 +      uiDefButS(block, MENU, B_MATPRV, "Material Type %t|Solid %x0|Halo %x1|Volume %x2",
 +              10, -15, 300, 20, &(ma->material_type), 0.0, 0.0, 0, 0, "");
        
  }
  
@@@ -4604,26 -4424,21 +4608,26 @@@ void material_panels(
                
                ma= editnode_get_active_material(ma);
                if(ma) {
 -                      material_panel_material(ma);
 -                      material_panel_ramps(ma);
 -                      material_panel_shading(ma);
 -                      
 -                      if (G.scene->r.renderer==R_INTERN)
 -                              material_panel_tramir(ma);
 -                      else {
 -                              if(ma->YF_ar==0.f) {
 -                                      ma->YF_ar = ma->YF_ag = ma->YF_ab = 1;
 -                                      ma->YF_dscale = 1;
 +                      if (ma->material_type == MA_SOLID) {
 +                              material_panel_material_solid(ma);
 +                              material_panel_ramps(ma);
 +                              material_panel_shading(ma);
 +                              
 +                              if (G.scene->r.renderer==R_INTERN)
 +                                      material_panel_tramir(ma);
 +                              else {
 +                                      if(ma->YF_ar==0.f) {
 +                                              ma->YF_ar = ma->YF_ag = ma->YF_ab = 1;
 +                                              ma->YF_dscale = 1;
 +                                      }
 +                                      material_panel_tramir_yafray(ma);
                                }
 -                              material_panel_tramir_yafray(ma);
 -                      }
  
 -                      material_panel_sss(ma);
 +                              material_panel_sss(ma);
 +                              
 +                      } else if (ma->material_type == MA_VOLUME) {
 +                              material_panel_material_volume(ma);
 +                      }
                        material_panel_texture(ob, ma);
                        
                        mtex= ma->mtex[ ma->texact ];
@@@ -4794,9 -4609,6 +4798,9 @@@ void texture_panels(
                        case TEX_VORONOI:
                                texture_panel_voronoi(tex);
                                break;
 +                      case TEX_POINTDENSITY:
 +                              texture_panel_pointdensity(tex);
 +                              break;
                        }
                }
        }