svn merge -r 22571:22800 https://svn.blender.org/svnroot/bf-blender/trunk/blender
authorAndre Susano Pinto <andresusanopinto@gmail.com>
Tue, 15 Sep 2009 15:15:43 +0000 (15:15 +0000)
committerAndre Susano Pinto <andresusanopinto@gmail.com>
Tue, 15 Sep 2009 15:15:43 +0000 (15:15 +0000)
svn merge -r 22800:23207 https://svn.blender.org/svnroot/bf-blender/trunk/blender

Merged volumetric with new raytrace code (it compiles and rendered volume-cube.blend withouth problems)

Part1:
source/blender

18 files changed:
1  2 
source/blender/blenkernel/BKE_utildefines.h
source/blender/blenlib/intern/BLI_kdopbvh.c
source/blender/editors/armature/meshlaplacian.c
source/blender/makesdna/DNA_scene_types.h
source/blender/makesrna/intern/rna_scene.c
source/blender/render/SConscript
source/blender/render/extern/include/RE_raytrace.h
source/blender/render/extern/include/RE_shader_ext.h
source/blender/render/intern/include/rayobject.h
source/blender/render/intern/include/render_types.h
source/blender/render/intern/include/rendercore.h
source/blender/render/intern/source/rayobject.c
source/blender/render/intern/source/rayshade.c
source/blender/render/intern/source/rendercore.c
source/blender/render/intern/source/shadeinput.c
source/blender/render/intern/source/volume_precache.c
source/blender/render/intern/source/volumetric.c
source/blender/windowmanager/intern/wm_init_exit.c

index eba5032997d6a107dd41b13d51d55b9ec582d630,7d8cb41db825e07710281e1f5c867b7cc0edef43..c0ed843017702855a1a955b78c58730c624691ee
  
  #define INIT_MINMAX2(min, max) { (min)[0]= (min)[1]= 1.0e30f; (max)[0]= (max)[1]= -1.0e30f; }
  
 +#define DO_MIN(vec, min) { if( (min)[0]>(vec)[0] ) (min)[0]= (vec)[0];      \
 +                                                        if( (min)[1]>(vec)[1] ) (min)[1]= (vec)[1];   \
 +                                                        if( (min)[2]>(vec)[2] ) (min)[2]= (vec)[2]; } \
 +
 +#define DO_MAX(vec, max) { if( (max)[0]<(vec)[0] ) (max)[0]= (vec)[0];                \
 +                                                        if( (max)[1]<(vec)[1] ) (max)[1]= (vec)[1];   \
 +                                                        if( (max)[2]<(vec)[2] ) (max)[2]= (vec)[2]; } \
 +
  #define DO_MINMAX(vec, min, max) { if( (min)[0]>(vec)[0] ) (min)[0]= (vec)[0]; \
                                                          if( (min)[1]>(vec)[1] ) (min)[1]= (vec)[1]; \
                                                          if( (min)[2]>(vec)[2] ) (min)[2]= (vec)[2]; \
  #define VECSUB(v1,v2,v3)      {*(v1)= *(v2) - *(v3); *(v1+1)= *(v2+1) - *(v3+1); *(v1+2)= *(v2+2) - *(v3+2);}
  #define VECSUB2D(v1,v2,v3)    {*(v1)= *(v2) - *(v3); *(v1+1)= *(v2+1) - *(v3+1);}
  #define VECADDFAC(v1,v2,v3,fac) {*(v1)= *(v2) + *(v3)*(fac); *(v1+1)= *(v2+1) + *(v3+1)*(fac); *(v1+2)= *(v2+2) + *(v3+2)*(fac);}
+ #define VECSUBFAC(v1,v2,v3,fac) {*(v1)= *(v2) - *(v3)*(fac); *(v1+1)= *(v2+1) - *(v3+1)*(fac); *(v1+2)= *(v2+2) - *(v3+2)*(fac);}
  #define QUATADDFAC(v1,v2,v3,fac) {*(v1)= *(v2) + *(v3)*(fac); *(v1+1)= *(v2+1) + *(v3+1)*(fac); *(v1+2)= *(v2+2) + *(v3+2)*(fac); *(v1+3)= *(v2+3) + *(v3+3)*(fac);}
  
  #define INPR(v1, v2)          ( (v1)[0]*(v2)[0] + (v1)[1]*(v2)[1] + (v1)[2]*(v2)[2] )
  #define SET_INT_IN_POINTER(i) ((void*)(intptr_t)(i))
  #define GET_INT_FROM_POINTER(i) ((int)(intptr_t)(i))
  
+ /*little array macro library.  example of usage:
+ int *arr = NULL;
+ V_DECLARE(arr);
+ int i;
+ for (i=0; i<10; i++) {
+       V_GROW(arr);
+       arr[i] = something;
+ }
+ V_FREE(arr);
+ arrays are buffered, using double-buffering (so on each reallocation,
+ the array size is doubled).  supposedly this should give good Big Oh
+ behaviour, though it may not be the best in practice.
+ */
+ #define V_DECLARE(vec) int _##vec##_count=0; void *_##vec##_tmp
+ /*in the future, I plan on having V_DECLARE allocate stack memory it'll
+   use at first, and switch over to heap when it needs more.  that'll mess
+   up cases where you'd want to use this API to build a dynamic list for
+   non-local use, so all such cases should use this macro.*/
+ #define V_DYNDECLARE(vec) V_DECLARE(vec)
+ /*this returns the entire size of the array, including any buffering.*/
+ #define V_SIZE(vec) ((signed int)((vec)==NULL ? 0 : MEM_allocN_len(vec) / sizeof(*vec)))
+ /*this returns the logical size of the array, not including buffering.*/
+ #define V_COUNT(vec) _##vec##_count
+ /*grow the array by one.  zeroes the new elements.*/
+ #define V_GROW(vec) \
+       V_SIZE(vec) > _##vec##_count ? _##vec##_count++ : \
+       ((_##vec##_tmp = MEM_callocN(sizeof(*vec)*(_##vec##_count*2+2), #vec " " __FILE__ " ")),\
+       (vec && memcpy(_##vec##_tmp, vec, sizeof(*vec) * _##vec##_count)),\
+       (vec && (MEM_freeN(vec),1)),\
+       (vec = _##vec##_tmp),\
+       _##vec##_count++)
+ #define V_FREE(vec) if (vec) MEM_freeN(vec);
+ /*resets the logical size of an array to zero, but doesn't
+   free the memory.*/
+ #define V_RESET(vec) _##vec##_count=0
+ /*set the count of the array*/
+ #define V_SETCOUNT(vec, count) _##vec##_count = (count)
  #endif
  
index 3e9df678f895570ee33924159aba94b5ccd89f40,61d9cce1a583beabab700bf5a38dc7fde515a22c..c5e6ca4b1aea0b22cc46e47db191e20a7a54c85a
@@@ -52,7 -52,6 +52,7 @@@ typedef struct BVHNod
  {
        struct BVHNode **children;
        struct BVHNode *parent; // some user defined traversed need that
 +      struct BVHNode *skip[2];
        float *bv;              // Bounding volume of all nodes, max 13 axis
        int index;              // face, edge, vertex index
        char totnode;   // how many nodes are used, used for speedup
@@@ -73,10 -72,10 +73,10 @@@ struct BVHTre
        char    start_axis, stop_axis; // KDOP_AXES array indices according to axis
  };
  
- typedef struct BVHOverlapData
- {
-       BVHTree *tree1, *tree2;
-       BVHTreeOverlap *overlap;
+ typedef struct BVHOverlapData 
+ {  
+       BVHTree *tree1, *tree2; 
+       BVHTreeOverlap *overlap; 
        int i, max_overlap; /* i is number of overlaps */
        int start_axis, stop_axis;
  } BVHOverlapData;
@@@ -102,8 -101,6 +102,8 @@@ typedef struct BVHRayCastDat
  
        BVHTreeRay    ray;
        float ray_dot_axis[13];
 +      float idot_axis[13];
 +      int index[6];
  
        BVHTreeRayHit hit;
  } BVHRayCastData;
  
  ////////////////////////////////////////////////////////////////////////
  // Bounding Volume Hierarchy Definition
- //
+ // 
  // Notes: From OBB until 26-DOP --> all bounding volumes possible, just choose type below
  // Notes: You have to choose the type at compile time ITM
  // Notes: You can choose the tree type --> binary, quad, octree, choose below
@@@ -191,10 -188,10 +191,10 @@@ int ADJUST_MEMORY(void *local_memblock
  
  
  //////////////////////////////////////////////////////////////////////////////////////////////////////
- // Introsort
+ // Introsort 
  // with permission deriven from the following Java code:
  // http://ralphunden.net/content/tutorials/a-guide-to-introsort/
- // and he derived it from the SUN STL
+ // and he derived it from the SUN STL 
  //////////////////////////////////////////////////////////////////////////////////////////////////////
  static int size_threshold = 16;
  /*
@@@ -356,23 -353,6 +356,23 @@@ int partition_nth_element(BVHNode **a, 
  }
  
  //////////////////////////////////////////////////////////////////////////////////////////////////////
 +static void build_skip_links(BVHTree *tree, BVHNode *node, BVHNode *left, BVHNode *right)
 +{
 +      int i;
 +      
 +      node->skip[0] = left;
 +      node->skip[1] = right;
 +      
 +      for (i = 0; i < node->totnode; i++)
 +      {
 +              if(i+1 < node->totnode)
 +                      build_skip_links(tree, node->children[i], left, node->children[i+1] );
 +              else
 +                      build_skip_links(tree, node->children[i], left, right );
 +
 +              left = node->children[i];
 +      }
 +}
  
  /*
   * BVHTree bounding volumes functions
@@@ -382,7 -362,7 +382,7 @@@ static void create_kdop_hull(BVHTree *t
        float newminmax;
        float *bv = node->bv;
        int i, k;
+       
        // don't init boudings for the moving case
        if(!moving)
        {
                        bv[2*i + 1] = -FLT_MAX;
                }
        }
+       
        for(k = 0; k < numpoints; k++)
        {
                // for all Axes.
@@@ -414,7 -394,7 +414,7 @@@ static void refit_kdop_hull(BVHTree *tr
        int i, j;
        float *bv = node->bv;
  
+       
        for (i = tree->start_axis; i < tree->stop_axis; i++)
        {
                bv[2*i] = FLT_MAX;
  // for all Axes.
                for (i = tree->start_axis; i < tree->stop_axis; i++)
                {
-                       newmin = tree->nodes[j]->bv[(2 * i)];
+                       newmin = tree->nodes[j]->bv[(2 * i)];   
                        if ((newmin < bv[(2 * i)]))
                                bv[(2 * i)] = newmin;
+  
                        newmax = tree->nodes[j]->bv[(2 * i) + 1];
                        if ((newmax > bv[(2 * i) + 1]))
                                bv[(2 * i) + 1] = newmax;
@@@ -447,14 -427,14 +447,14 @@@ static char get_largest_axis(float *bv
        middle_point[0] = (bv[1]) - (bv[0]); // x axis
        middle_point[1] = (bv[3]) - (bv[2]); // y axis
        middle_point[2] = (bv[5]) - (bv[4]); // z axis
-       if (middle_point[0] > middle_point[1])
+       if (middle_point[0] > middle_point[1]) 
        {
                if (middle_point[0] > middle_point[2])
                        return 1; // max x axis
                else
                        return 5; // max z axis
        }
-       else
+       else 
        {
                if (middle_point[1] > middle_point[2])
                        return 3; // max y axis
  static void node_join(BVHTree *tree, BVHNode *node)
  {
        int i, j;
+       
        for (i = tree->start_axis; i < tree->stop_axis; i++)
        {
                node->bv[2*i] = FLT_MAX;
                node->bv[2*i + 1] = -FLT_MAX;
        }
+       
        for (i = 0; i < tree->tree_type; i++)
        {
-               if (node->children[i])
+               if (node->children[i]) 
                {
                        for (j = tree->start_axis; j < tree->stop_axis; j++)
                        {
-                               // update minimum
-                               if (node->children[i]->bv[(2 * j)] < node->bv[(2 * j)])
+                               // update minimum 
+                               if (node->children[i]->bv[(2 * j)] < node->bv[(2 * j)]) 
                                        node->bv[(2 * j)] = node->children[i]->bv[(2 * j)];
-                               // update maximum
+                               
+                               // update maximum 
                                if (node->children[i]->bv[(2 * j) + 1] > node->bv[(2 * j) + 1])
                                        node->bv[(2 * j) + 1] = node->children[i]->bv[(2 * j) + 1];
                        }
@@@ -538,7 -518,7 +538,7 @@@ static void bvhtree_info(BVHTree *tree
  static void verify_tree(BVHTree *tree)
  {
        int i, j, check = 0;
+       
        // check the pointer list
        for(i = 0; i < tree->totleaf; i++)
        {
                        check = 0;
                }
        }
+       
        // check the leaf list
        for(i = 0; i < tree->totleaf; i++)
        {
                        check = 0;
                }
        }
+       
        printf("branches: %d, leafs: %d, total: %d\n", tree->totbranch, tree->totleaf, tree->totbranch + tree->totleaf);
  }
  #endif
@@@ -723,7 -703,7 +723,7 @@@ static void non_recursive_bvh_div_nodes
  
        BVHBuildHelper data;
        int depth;
+       
        // set parent from root node to NULL
        BVHNode *tmp = branches_array+0;
        tmp->parent = NULL;
        }
  
        branches_array--;       //Implicit trees use 1-based indexs
+       
        build_implicit_tree_helper(tree, &data);
  
        //Loop tree levels (log N) loops
@@@ -826,11 -806,11 +826,11 @@@ BVHTree *BLI_bvhtree_new(int maxsize, f
  {
        BVHTree *tree;
        int numnodes, i;
+       
        // theres not support for trees below binary-trees :P
        if(tree_type < 2)
                return NULL;
+       
        if(tree_type > MAX_TREETYPE)
                return NULL;
  
        //so that tangent rays can still hit a bounding volume..
        //this bug would show up when casting a ray aligned with a kdop-axis and with an edge of 2 faces
        epsilon = MAX2(FLT_EPSILON, epsilon);
+       
        if(tree)
        {
                tree->epsilon = epsilon;
-               tree->tree_type = tree_type;
+               tree->tree_type = tree_type; 
                tree->axis = axis;
+               
                if(axis == 26)
                {
                        tree->start_axis = 0;
                numnodes = maxsize + implicit_needed_branches(tree_type, maxsize) + tree_type;
  
                tree->nodes = (BVHNode **)MEM_callocN(sizeof(BVHNode *)*numnodes, "BVHNodes");
+               
                if(!tree->nodes)
                {
                        MEM_freeN(tree);
                        return NULL;
                }
+               
                tree->nodebv = (float*)MEM_callocN(sizeof(float)* axis * numnodes, "BVHNodeBV");
                if(!tree->nodebv)
                {
                }
  
                tree->nodearray = (BVHNode *)MEM_callocN(sizeof(BVHNode)* numnodes, "BVHNodeArray");
+               
                if(!tree->nodearray)
                {
                        MEM_freeN(tree->nodechild);
                        tree->nodearray[i].bv = tree->nodebv + i * axis;
                        tree->nodearray[i].children = tree->nodechild + i * tree_type;
                }
+               
        }
  
        return tree;
  }
  
  void BLI_bvhtree_free(BVHTree *tree)
- {
+ {     
        if(tree)
        {
                MEM_freeN(tree->nodes);
@@@ -959,7 -939,6 +959,7 @@@ void BLI_bvhtree_balance(BVHTree *tree
        for(i = 0; i < tree->totbranch; i++)
                tree->nodes[tree->totleaf + i] = branches_array + i;
  
 +      build_skip_links(tree, tree->nodes[tree->totleaf], NULL, NULL);
        //bvhtree_info(tree);
  }
  
@@@ -967,27 -946,27 +967,27 @@@ int BLI_bvhtree_insert(BVHTree *tree, i
  {
        int i;
        BVHNode *node = NULL;
+       
        // insert should only possible as long as tree->totbranch is 0
        if(tree->totbranch > 0)
                return 0;
+       
        if(tree->totleaf+1 >= MEM_allocN_len(tree->nodes)/sizeof(*(tree->nodes)))
                return 0;
+       
        // TODO check if have enough nodes in array
+       
        node = tree->nodes[tree->totleaf] = &(tree->nodearray[tree->totleaf]);
        tree->totleaf++;
+       
        create_kdop_hull(tree, node, co, numpoints, 0);
        node->index= index;
+       
        // inflate the bv with some epsilon
        for (i = tree->start_axis; i < tree->stop_axis; i++)
        {
-               node->bv[(2 * i)] -= tree->epsilon; // minimum
-               node->bv[(2 * i) + 1] += tree->epsilon; // maximum
+               node->bv[(2 * i)] -= tree->epsilon; // minimum 
+               node->bv[(2 * i) + 1] += tree->epsilon; // maximum 
        }
  
        return 1;
@@@ -999,23 -978,23 +999,23 @@@ int BLI_bvhtree_update_node(BVHTree *tr
  {
        int i;
        BVHNode *node= NULL;
+       
        // check if index exists
        if(index > tree->totleaf)
                return 0;
+       
        node = tree->nodearray + index;
+       
        create_kdop_hull(tree, node, co, numpoints, 0);
+       
        if(co_moving)
                create_kdop_hull(tree, node, co_moving, numpoints, 1);
+       
        // inflate the bv with some epsilon
        for (i = tree->start_axis; i < tree->stop_axis; i++)
        {
-               node->bv[(2 * i)] -= tree->epsilon; // minimum
-               node->bv[(2 * i) + 1] += tree->epsilon; // maximum
+               node->bv[(2 * i)] -= tree->epsilon; // minimum 
+               node->bv[(2 * i) + 1] += tree->epsilon; // maximum 
        }
  
        return 1;
@@@ -1051,24 -1030,24 +1051,24 @@@ static int tree_overlap(BVHNode *node1
        float *bv2 = node2->bv;
  
        float *bv1_end = bv1 + (stop_axis<<1);
+               
        bv1 += start_axis<<1;
        bv2 += start_axis<<1;
+       
        // test all axis if min + max overlap
        for (; bv1 != bv1_end; bv1+=2, bv2+=2)
        {
-               if ((*(bv1) > *(bv2 + 1)) || (*(bv2) > *(bv1 + 1)))
+               if ((*(bv1) > *(bv2 + 1)) || (*(bv2) > *(bv1 + 1))) 
                        return 0;
        }
+       
        return 1;
  }
  
  static void traverse(BVHOverlapData *data, BVHNode *node1, BVHNode *node2)
  {
        int j;
+       
        if(tree_overlap(node1, node2, data->start_axis, data->stop_axis))
        {
                // check if node1 is a leaf
                        // check if node2 is a leaf
                        if(!node2->totnode)
                        {
+                               
                                if(node1 == node2)
                                {
                                        return;
                                }
+                                       
                                if(data->i >= data->max_overlap)
-                               {
+                               {       
                                        // try to make alloc'ed memory bigger
                                        data->overlap = realloc(data->overlap, sizeof(BVHTreeOverlap)*data->max_overlap*2);
+                                       
                                        if(!data->overlap)
                                        {
                                                printf("Out of Memory in traverse\n");
                                        }
                                        data->max_overlap *= 2;
                                }
+                               
                                // both leafs, insert overlap!
                                data->overlap[data->i].indexA = node1->index;
                                data->overlap[data->i].indexB = node2->index;
                }
                else
                {
+                       
                        for(j = 0; j < data->tree2->tree_type; j++)
                        {
                                if(node1->children[j])
@@@ -1129,21 -1108,21 +1129,21 @@@ BVHTreeOverlap *BLI_bvhtree_overlap(BVH
        int j, total = 0;
        BVHTreeOverlap *overlap = NULL, *to = NULL;
        BVHOverlapData **data;
+       
        // check for compatibility of both trees (can't compare 14-DOP with 18-DOP)
        if((tree1->axis != tree2->axis) && (tree1->axis == 14 || tree2->axis == 14) && (tree1->axis == 18 || tree2->axis == 18))
                return 0;
+       
        // fast check root nodes for collision before doing big splitting + traversal
        if(!tree_overlap(tree1->nodes[tree1->totleaf], tree2->nodes[tree2->totleaf], MIN2(tree1->start_axis, tree2->start_axis), MIN2(tree1->stop_axis, tree2->stop_axis)))
                return 0;
  
        data = MEM_callocN(sizeof(BVHOverlapData *)* tree1->tree_type, "BVHOverlapData_star");
+       
        for(j = 0; j < tree1->tree_type; j++)
        {
                data[j] = (BVHOverlapData *)MEM_callocN(sizeof(BVHOverlapData), "BVHOverlapData");
+               
                // init BVHOverlapData
                data[j]->overlap = (BVHTreeOverlap *)malloc(sizeof(BVHTreeOverlap)*MAX2(tree1->totleaf, tree2->totleaf));
                data[j]->tree1 = tree1;
        {
                traverse(data[j], tree1->nodes[tree1->totleaf]->children[j], tree2->nodes[tree2->totleaf]);
        }
+       
        for(j = 0; j < tree1->tree_type; j++)
                total += data[j]->i;
+       
        to = overlap = (BVHTreeOverlap *)MEM_callocN(sizeof(BVHTreeOverlap)*total, "BVHTreeOverlap");
+       
        for(j = 0; j < tree1->tree_type; j++)
        {
                memcpy(to, data[j]->overlap, data[j]->i*sizeof(BVHTreeOverlap));
                to+=data[j]->i;
        }
+       
        for(j = 0; j < tree1->tree_type; j++)
        {
                free(data[j]->overlap);
                MEM_freeN(data[j]);
        }
        MEM_freeN(data);
+       
        (*result) = total;
        return overlap;
  }
@@@ -1194,7 -1173,7 +1194,7 @@@ static float squared_dist(const float *
  }
  
  //Determines the nearest point of the given node BV. Returns the squared distance to that point.
- static float calc_nearest_point(BVHNearestData *data, BVHNode *node, float *nearest)
+ static float calc_nearest_point(const float *proj, BVHNode *node, float *nearest)
  {
        int i;
        const float *bv = node->bv;
        //nearest on AABB hull
        for(i=0; i != 3; i++, bv += 2)
        {
-               if(bv[0] > data->proj[i])
+               if(bv[0] > proj[i])
                        nearest[i] = bv[0];
-               else if(bv[1] < data->proj[i])
+               else if(bv[1] < proj[i])
                        nearest[i] = bv[1];
                else
-                       nearest[i] = data->proj[i];
+                       nearest[i] = proj[i]; 
        }
  
  /*
                }
        }
  */
-       return squared_dist(data->co, nearest);
+       return squared_dist(proj, nearest);
  }
  
  
@@@ -1252,7 -1231,7 +1252,7 @@@ static void dfs_find_nearest_dfs(BVHNea
                else
                {
                        data->nearest.index     = node->index;
-                       data->nearest.dist      = calc_nearest_point(data, node, data->nearest.co);
+                       data->nearest.dist      = calc_nearest_point(data->proj, node, data->nearest.co);
                }
        }
        else
                int i;
                float nearest[3];
  
-               if(data->proj[ (int)node->main_axis ] <= node->children[0]->bv[(int)node->main_axis*2+1])
+               if(data->proj[ node->main_axis ] <= node->children[0]->bv[node->main_axis*2+1])
                {
  
                        for(i=0; i != node->totnode; i++)
                        {
-                               if( calc_nearest_point(data, node->children[i], nearest) >= data->nearest.dist) continue;
+                               if( calc_nearest_point(data->proj, node->children[i], nearest) >= data->nearest.dist) continue;
                                dfs_find_nearest_dfs(data, node->children[i]);
                        }
                }
                {
                        for(i=node->totnode-1; i >= 0 ; i--)
                        {
-                               if( calc_nearest_point(data, node->children[i], nearest) >= data->nearest.dist) continue;
+                               if( calc_nearest_point(data->proj, node->children[i], nearest) >= data->nearest.dist) continue;
                                dfs_find_nearest_dfs(data, node->children[i]);
                        }
                }
  static void dfs_find_nearest_begin(BVHNearestData *data, BVHNode *node)
  {
        float nearest[3], sdist;
-       sdist = calc_nearest_point(data, node, nearest);
+       sdist = calc_nearest_point(data->proj, node, nearest);
        if(sdist >= data->nearest.dist) return;
        dfs_find_nearest_dfs(data, node);
  }
@@@ -1322,7 -1301,7 +1322,7 @@@ static void bfs_find_nearest(BVHNearest
        }
  
        current.node = node;
-       current.dist = calc_nearest_point(data, node, nearest);
+       current.dist = calc_nearest_point(data->proj, node, nearest);
  
        while(current.dist < data->nearest.dist)
        {
                                }
  
                                heap[heap_size].node = current.node->children[i];
-                               heap[heap_size].dist = calc_nearest_point(data, current.node->children[i], nearest);
+                               heap[heap_size].dist = calc_nearest_point(data->proj, current.node->children[i], nearest);
  
                                if(heap[heap_size].dist >= data->nearest.dist) continue;
                                heap_size++;
                                push_heaps++;
                        }
                }
+               
                if(heap_size == 0) break;
  
                current = heap[0];
  }
  #endif
  
  int BLI_bvhtree_find_nearest(BVHTree *tree, const float *co, BVHTreeNearest *nearest, BVHTree_NearestPointCallback callback, void *userdata)
  {
        int i;
   * raycast is done by performing a DFS on the BVHTree and saving the closest hit
   */
  
 +
  //Determines the distance that the ray must travel to hit the bounding volume of the given node
  static float ray_nearest_hit(BVHRayCastData *data, float *bv)
  {
                                if(lu > low)   low = lu;
                                if(ll < upper) upper = ll;
                        }
+       
                        if(low > upper) return FLT_MAX;
                }
        }
        return low;
  }
  
 +//Determines the distance that the ray must travel to hit the bounding volume of the given node
 +//Based on Tactical Optimization of Ray/Box Intersection, by Graham Fyffe
 +//[http://tog.acm.org/resources/RTNews/html/rtnv21n1.html#art9]
 +//
 +//TODO this doens't has data->ray.radius in consideration
 +static float fast_ray_nearest_hit(const BVHRayCastData *data, const BVHNode *node)
 +{
 +      const float *bv = node->bv;
 +      float dist;
 +      
 +      float t1x = (bv[data->index[0]] - data->ray.origin[0]) * data->idot_axis[0];
 +      float t2x = (bv[data->index[1]] - data->ray.origin[0]) * data->idot_axis[0];
 +      float t1y = (bv[data->index[2]] - data->ray.origin[1]) * data->idot_axis[1];
 +      float t2y = (bv[data->index[3]] - data->ray.origin[1]) * data->idot_axis[1];
 +      float t1z = (bv[data->index[4]] - data->ray.origin[2]) * data->idot_axis[2];
 +      float t2z = (bv[data->index[5]] - data->ray.origin[2]) * data->idot_axis[2];
 +
 +      if(t1x > t2y || t2x < t1y || t1x > t2z || t2x < t1z || t1y > t2z || t2y < t1z) return FLT_MAX;
 +      if(t2x < 0.0 || t2y < 0.0 || t2z < 0.0) return FLT_MAX;
 +      if(t1x > data->hit.dist || t1y > data->hit.dist || t1z > data->hit.dist) return FLT_MAX;
 +
 +      dist = t1x;
 +      if (t1y > dist) dist = t1y;
 +    if (t1z > dist) dist = t1z;
 +      return dist;
 +}
 +
  static void dfs_raycast(BVHRayCastData *data, BVHNode *node)
  {
        int i;
  
        //ray-bv is really fast.. and simple tests revealed its worth to test it
        //before calling the ray-primitive functions
 -      float dist = ray_nearest_hit(data, node->bv);
 +      float dist = fast_ray_nearest_hit(data, node);
        if(dist >= data->hit.dist) return;
  
        if(node->totnode == 0)
        }
  }
  
 +static void iterative_raycast(BVHRayCastData *data, BVHNode *node)
 +{
 +      while(node)
 +      {
 +              float dist = fast_ray_nearest_hit(data, node);
 +              if(dist >= data->hit.dist)
 +              {
 +                      node = node->skip[1];
 +                      continue;
 +              }
 +
 +              if(node->totnode == 0)
 +              {
 +                      if(data->callback)
 +                              data->callback(data->userdata, node->index, &data->ray, &data->hit);
 +                      else
 +                      {
 +                              data->hit.index = node->index;
 +                              data->hit.dist  = dist;
 +                              VECADDFAC(data->hit.co, data->ray.origin, data->ray.direction, dist);
 +                      }
 +                      
 +                      node = node->skip[1];
 +              }
 +              else
 +              {
 +                      node = node->children[0];
 +              }       
 +      }
 +}
 +
  int BLI_bvhtree_ray_cast(BVHTree *tree, const float *co, const float *dir, float radius, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata)
  {
        int i;
        for(i=0; i<3; i++)
        {
                data.ray_dot_axis[i] = INPR( data.ray.direction, KDOP_AXES[i]);
 +              data.idot_axis[i] = 1.0f / data.ray_dot_axis[i];
  
                if(fabs(data.ray_dot_axis[i]) < FLT_EPSILON)
 +              {
                        data.ray_dot_axis[i] = 0.0;
 +              }
 +              data.index[2*i] = data.idot_axis[i] < 0.0 ? 1 : 0;
 +              data.index[2*i+1] = 1 - data.index[2*i];
 +              data.index[2*i]   += 2*i;
 +              data.index[2*i+1] += 2*i;
        }
  
  
        }
  
        if(root)
 +      {
                dfs_raycast(&data, root);
 +//            iterative_raycast(&data, root);
 +      }
  
  
        if(hit)
@@@ -1622,28 -1533,115 +1623,115 @@@ float BLI_bvhtree_bb_raycast(float *bv
        float dist = 0.0;
  
        data.hit.dist = FLT_MAX;
+       
        // get light direction
        data.ray.direction[0] = light_end[0] - light_start[0];
        data.ray.direction[1] = light_end[1] - light_start[1];
        data.ray.direction[2] = light_end[2] - light_start[2];
+       
        data.ray.radius = 0.0;
+       
        data.ray.origin[0] = light_start[0];
        data.ray.origin[1] = light_start[1];
        data.ray.origin[2] = light_start[2];
+       
        Normalize(data.ray.direction);
        VECCOPY(data.ray_dot_axis, data.ray.direction);
+       
        dist = ray_nearest_hit(&data, bv);
+       
        if(dist > 0.0)
        {
                VECADDFAC(pos, light_start, data.ray.direction, dist);
        }
        return dist;
+       
+ }
+ /*
+  * Range Query - as request by broken :P
+  *
+  * Allocs and fills an array with the indexs of node that are on the given spherical range (center, radius) 
+  * Returns the size of the array.
+  */
+ typedef struct RangeQueryData
+ {
+       BVHTree *tree;
+       const float *center;
+       float radius;                   //squared radius
+       int hits;
+       BVHTree_RangeQuery callback;
+       void *userdata;
  
+ } RangeQueryData;
+ static void dfs_range_query(RangeQueryData *data, BVHNode *node)
+ {
+       if(node->totnode == 0)
+       {
+               //Calculate the node min-coords (if the node was a point then this is the point coordinates)
+               float co[3];
+               co[0] = node->bv[0];
+               co[1] = node->bv[2];
+               co[2] = node->bv[4];
+       }
+       else
+       {
+               int i;
+               for(i=0; i != node->totnode; i++)
+               {
+                       float nearest[3];
+                       float dist = calc_nearest_point(data->center, node->children[i], nearest);
+                       if(dist < data->radius)
+                       {
+                               //Its a leaf.. call the callback
+                               if(node->children[i]->totnode == 0)
+                               {
+                                       data->hits++;
+                                       data->callback( data->userdata, node->children[i]->index, dist );
+                               }
+                               else
+                                       dfs_range_query( data, node->children[i] );
+                       }
+               }
+       }
  }
  
+ int BLI_bvhtree_range_query(BVHTree *tree, const float *co, float radius, BVHTree_RangeQuery callback, void *userdata)
+ {
+       BVHNode * root = tree->nodes[tree->totleaf];
+       RangeQueryData data;
+       data.tree = tree;
+       data.center = co;
+       data.radius = radius*radius;
+       data.hits = 0;
+       data.callback = callback;
+       data.userdata = userdata;
+       if(root != NULL)
+       {
+               float nearest[3];
+               float dist = calc_nearest_point(data.center, root, nearest);
+               if(dist < data.radius)
+               {
+                       //Its a leaf.. call the callback
+                       if(root->totnode == 0)
+                       {
+                               data.hits++;
+                               data.callback( data.userdata, root->index, dist );
+                       }
+                       else
+                               dfs_range_query( &data, root );
+               }
+       }
+       return data.hits;
+ }
index ff3fed6be34d43a24f2411f56e4684b2f5ed3a2e,a6c94bee5b1a216373a8bdbbb42b172deded9d87..7f95fb47d6177eb7cc51a1ba8c493d98c6625711
@@@ -30,7 -30,6 +30,7 @@@
  
  #include <math.h>
  #include <string.h>
 +#include <assert.h>
  
  #include "MEM_guardedalloc.h"
  
@@@ -106,7 -105,7 +106,7 @@@ struct LaplacianSystem 
                float *p;                       /* values from all p vectors */
                float *mindist;         /* minimum distance to a bone for all vertices */
                
 -              RayTree *raytree;       /* ray tracing acceleration structure */
 +              RayObject *raytree;     /* ray tracing acceleration structure */
                MFace **vface;          /* a face that the vertex belongs to */
        } heat;
  
@@@ -395,32 -394,77 +395,32 @@@ float laplacian_system_get_solution(in
  #define DISTANCE_EPSILON      1e-4f
  
  /* Raytracing for vertex to bone visibility */
 -
 -static LaplacianSystem *HeatSys = NULL;
 -
 -static void heat_ray_coords_func(RayFace *face, float **v1, float **v2, float **v3, float **v4)
 -{
 -      MFace *mface= (MFace*)face;
 -      float (*verts)[3]= HeatSys->heat.verts;
 -
 -      *v1= verts[mface->v1];
 -      *v2= verts[mface->v2];
 -      *v3= verts[mface->v3];
 -      *v4= (mface->v4)? verts[mface->v4]: NULL;
 -}
 -
 -static int heat_ray_check_func(Isect *is, int ob, RayFace *face)
 -{
 -      float *v1, *v2, *v3, *v4, nor[3];
 -
 -      /* don't intersect if the ray faces along the face normal */
 -      heat_ray_coords_func(face, &v1, &v2, &v3, &v4);
 -
 -      if(v4) CalcNormFloat4(v1, v2, v3, v4, nor);
 -      else CalcNormFloat(v1, v2, v3, nor);
 -
 -      return (INPR(nor, is->vec) < 0);
 -}
 -
  static void heat_ray_tree_create(LaplacianSystem *sys)
  {
        Mesh *me = sys->heat.mesh;
 -      RayTree *tree;
        MFace *mface;
 -      float min[3], max[3];
        int a;
  
 -      /* create a raytrace tree from the mesh */
 -      INIT_MINMAX(min, max);
 -
 -      for(a=0; a<me->totvert; a++)
 -              DO_MINMAX(sys->heat.verts[a], min, max);
 -
 -      tree= RE_ray_tree_create(64, me->totface, min, max,
 -              heat_ray_coords_func, heat_ray_check_func, NULL, NULL);
 -      
 -      sys->heat.vface= MEM_callocN(sizeof(MFace*)*me->totvert, "HeatVFaces");
 -
 -      HeatSys= sys;
 +      assert(0); //TODO
 +      //sys->heat.raytree = RE_rayobject_mesh_create(me, me);
  
 +      sys->heat.vface = MEM_callocN(sizeof(MFace*)*me->totvert, "HeatVFaces");
        for(a=0, mface=me->mface; a<me->totface; a++, mface++) {
 -              RE_ray_tree_add_face(tree, 0, mface);
 -
                sys->heat.vface[mface->v1]= mface;
                sys->heat.vface[mface->v2]= mface;
                sys->heat.vface[mface->v3]= mface;
                if(mface->v4) sys->heat.vface[mface->v4]= mface;
        }
 -
 -      HeatSys= NULL;
 -      
 -      RE_ray_tree_done(tree);
 -
 -      sys->heat.raytree= tree;
  }
  
  static int heat_ray_bone_visible(LaplacianSystem *sys, int vertex, int bone)
  {
        Isect isec;
        MFace *mface;
 -      float dir[3];
 +      float end[3];
        int visible;
  
 +      assert( 0 );
        mface= sys->heat.vface[vertex];
        if(!mface)
                return 1;
        memset(&isec, 0, sizeof(isec));
        isec.mode= RE_RAY_SHADOW;
        isec.lay= -1;
 -      isec.face_last= NULL;
 -      isec.faceorig= mface;
 +      isec.orig.face = mface;
 +      isec.skip = RE_SKIP_CULLFACE;
  
        VECCOPY(isec.start, sys->heat.verts[vertex]);
 -      PclosestVL3Dfl(isec.end, isec.start,
 -              sys->heat.root[bone], sys->heat.tip[bone]);
 +      PclosestVL3Dfl(end, isec.start, sys->heat.root[bone], sys->heat.tip[bone]);
 +
 +      VECSUB(isec.vec, end, isec.start);
 +      isec.labda = 1.0f;
  
 +#if 0
 +      TODO
        /* add an extra offset to the start position to avoid self intersection */
 -      VECSUB(dir, isec.end, isec.start);
 +      VECCOPY(dir, isec.vec);
        Normalize(dir);
        VecMulf(dir, 1e-5);
        VecAddf(isec.start, isec.start, dir);
 -      
 -      HeatSys= sys;
 -      visible= !RE_ray_tree_intersect(sys->heat.raytree, &isec);
 -      HeatSys= NULL;
 +#endif        
 +      visible= !RE_rayobject_raycast(sys->heat.raytree, &isec);
  
        return visible;
  }
@@@ -630,9 -672,9 +630,9 @@@ void heat_bone_weighting(Object *ob, Me
                /* clear weights */
                if(bbone && firstsegment) {
                        for(a=0; a<me->totvert; a++) {
-                               remove_vert_defgroup(ob, dgrouplist[j], a);
+                               ED_vgroup_vert_remove(ob, dgrouplist[j], a);
                                if(vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0)
-                                       remove_vert_defgroup(ob, dgroupflip[j], vertsflipped[a]);
+                                       ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]);
                        }
                }
  
                                
                                if(bbone) {
                                        if(solution > 0.0f)
-                                               add_vert_to_defgroup(ob, dgrouplist[j], a, solution,
+                                               ED_vgroup_vert_add(ob, dgrouplist[j], a, solution,
                                                        WEIGHT_ADD);
                                }
                                else {
                                        weight= heat_limit_weight(solution);
                                        if(weight > 0.0f)
-                                               add_vert_to_defgroup(ob, dgrouplist[j], a, weight,
+                                               ED_vgroup_vert_add(ob, dgrouplist[j], a, weight,
                                                        WEIGHT_REPLACE);
                                        else
-                                               remove_vert_defgroup(ob, dgrouplist[j], a);
+                                               ED_vgroup_vert_remove(ob, dgrouplist[j], a);
                                }
  
                                /* do same for mirror */
                                if(vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) {
                                        if(bbone) {
                                                if(solution > 0.0f)
-                                                       add_vert_to_defgroup(ob, dgroupflip[j], vertsflipped[a],
+                                                       ED_vgroup_vert_add(ob, dgroupflip[j], vertsflipped[a],
                                                                solution, WEIGHT_ADD);
                                        }
                                        else {
                                                weight= heat_limit_weight(solution);
                                                if(weight > 0.0f)
-                                                       add_vert_to_defgroup(ob, dgroupflip[j], vertsflipped[a],
+                                                       ED_vgroup_vert_add(ob, dgroupflip[j], vertsflipped[a],
                                                                weight, WEIGHT_REPLACE);
                                                else
-                                                       remove_vert_defgroup(ob, dgroupflip[j], vertsflipped[a]);
+                                                       ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]);
                                        }
                                }
                        }
                /* remove too small vertex weights */
                if(bbone && lastsegment) {
                        for(a=0; a<me->totvert; a++) {
-                               weight= get_vert_defgroup(ob, dgrouplist[j], a);
+                               weight= ED_vgroup_vert_weight(ob, dgrouplist[j], a);
                                weight= heat_limit_weight(weight);
                                if(weight <= 0.0f)
-                                       remove_vert_defgroup(ob, dgrouplist[j], a);
+                                       ED_vgroup_vert_remove(ob, dgrouplist[j], a);
  
                                if(vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) {
-                                       weight= get_vert_defgroup(ob, dgroupflip[j], vertsflipped[a]);
+                                       weight= ED_vgroup_vert_weight(ob, dgroupflip[j], vertsflipped[a]);
                                        weight= heat_limit_weight(weight);
                                        if(weight <= 0.0f)
-                                               remove_vert_defgroup(ob, dgroupflip[j], vertsflipped[a]);
+                                               ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]);
                                }
                        }
                }
        /* free */
        if(vertsflipped) MEM_freeN(vertsflipped);
  
 -      RE_ray_tree_free(sys->heat.raytree);
 +      RE_rayobject_free(sys->heat.raytree);
        MEM_freeN(sys->heat.vface);
  
        MEM_freeN(sys->heat.mindist);
@@@ -1007,7 -1049,7 +1007,7 @@@ typedef struct MeshDeformBind 
        int *varidx;
  
        /* raytrace */
 -      RayTree *raytree;
 +      RayObject *raytree;
  } MeshDeformBind;
  
  /* ray intersection */
@@@ -1131,7 -1173,7 +1131,7 @@@ static void meshdeform_ray_tree_free(Me
  static int meshdeform_intersect(MeshDeformBind *mdb, Isect *isec)
  {
        MFace *mface;
 -      float face[4][3], co[3], uvw[3], len, nor[3];
 +      float face[4][3], co[3], uvw[3], len, nor[3], end[3];
        int f, hit, is= 0, totface;
  
        isec->labda= 1e10;
        mface= mdb->cagedm->getFaceArray(mdb->cagedm);
        totface= mdb->cagedm->getNumFaces(mdb->cagedm);
  
 +      VECADDFAC( end, isec->start, isec->vec, isec->labda );
 +
        for(f=0; f<totface; f++, mface++) {
                VECCOPY(face[0], mdb->cagecos[mface->v1]);
                VECCOPY(face[1], mdb->cagecos[mface->v2]);
  
                if(mface->v4) {
                        VECCOPY(face[3], mdb->cagecos[mface->v4]);
 -                      hit= meshdeform_tri_intersect(isec->start, isec->end, face[0], face[1], face[2], co, uvw);
 +                      hit = meshdeform_tri_intersect(isec->start, end, face[0], face[1], face[2], co, uvw);
  
                        if(hit) {
                                CalcNormFloat(face[0], face[1], face[2], nor);
                        }
                        else {
 -                              hit= meshdeform_tri_intersect(isec->start, isec->end, face[0], face[2], face[3], co, uvw);
 +                              hit= meshdeform_tri_intersect(isec->start, end, face[0], face[2], face[3], co, uvw);
                                CalcNormFloat(face[0], face[2], face[3], nor);
                        }
                }
                else {
 -                      hit= meshdeform_tri_intersect(isec->start, isec->end, face[0], face[1], face[2], co, uvw);
 +                      hit= meshdeform_tri_intersect(isec->start, end, face[0], face[1], face[2], co, uvw);
                        CalcNormFloat(face[0], face[1], face[2], nor);
                }
  
                if(hit) {
 -                      len= VecLenf(isec->start, co)/VecLenf(isec->start, isec->end);
 +                      len= VecLenf(isec->start, co)/VecLenf(isec->start, end);
                        if(len < isec->labda) {
                                isec->labda= len;
 -                              isec->face= mface;
 +                              isec->hit.face = mface;
                                isec->isect= (INPR(isec->vec, nor) <= 0.0f);
                                is= 1;
                        }
@@@ -1183,18 -1223,20 +1183,18 @@@ static MDefBoundIsect *meshdeform_ray_t
        Isect isec;
        float (*cagecos)[3];
        MFace *mface;
 -      float vert[4][3], len;
 +      float vert[4][3], len, end[3];
        static float epsilon[3]= {0, 0, 0}; //1e-4, 1e-4, 1e-4};
  
        /* setup isec */
        memset(&isec, 0, sizeof(isec));
        isec.mode= RE_RAY_MIRROR; /* we want the closest intersection */
        isec.lay= -1;
 -      isec.face_last= NULL;
 -      isec.faceorig= NULL;
        isec.labda= 1e10f;
  
        VECADD(isec.start, co1, epsilon);
 -      VECADD(isec.end, co2, epsilon);
 -      VECSUB(isec.vec, isec.end, isec.start);
 +      VECADD(end, co2, epsilon);
 +      VECSUB(isec.vec, end, isec.start);
  
  #if 0
        /*if(RE_ray_tree_intersect(mdb->raytree, &isec)) {*/
  
        if(meshdeform_intersect(mdb, &isec)) {
                len= isec.labda;
 -              mface= isec.face;
 +              mface=(MFace*)isec.hit.face;
  
                /* create MDefBoundIsect */
                isect= BLI_memarena_alloc(mdb->memarena, sizeof(*isect));
index 82658be24bfa7157c0f6d1fd40cd5cb8566188aa,73afc3d1a5310081599b40451f014fb22f8cf518..b00500a321a48823a79a4f108ea15c579a951904
@@@ -47,6 -47,8 +47,8 @@@ struct Text
  struct bNodeTree;
  struct AnimData;
  struct Editing;
+ struct SceneStats;
+ struct bGPdata;
  
  typedef struct Base {
        struct Base *next, *prev;
@@@ -160,8 -162,6 +162,8 @@@ typedef struct SceneRenderLayer 
  #define SCE_PASS_RADIO                8192 /* Radio removed, can use for new GI? */
  #define SCE_PASS_MIST         16384
  
 +#define SCE_PASS_RAYHITS      32768
 +
  /* note, srl->passflag is treestore element 'nr' in outliner, short still... */
  
  
@@@ -238,9 -238,6 +240,9 @@@ typedef struct RenderData 
  
        /* render engine (deprecated), octree resolution */
        short renderer, ocres;
 +      short raystructure;
 +      short raytrace_tree_type;
 +      short pad4[2];
  
        /**
         * What to do with the sky/background. Picks sky/premul/key
@@@ -392,7 -389,7 +394,7 @@@ typedef struct GameData 
         * bit 3: (gameengine): Activity culling is enabled.
         * bit 5: (gameengine) : enable Bullet DBVT tree for view frustrum culling
        */
-       short mode, pad11;
+       short mode, flag, matmode, pad[3];
        short occlusionRes;             /* resolution of occlusion Z buffer in pixel */
        short physicsEngine;
        short ticrate, maxlogicstep, physubstep, maxphystep;
        struct GameDome dome;
        short stereoflag, stereomode, xsch, ysch; //xsch and ysch can be deleted !!!
  } GameData;
  #define STEREO_NOSTEREO               1
  #define STEREO_ENABLED                2
  #define STEREO_DOME                   3
  #define WOPHY_ODE             4
  #define WOPHY_BULLET  5
  
+ /* GameData.flag */
+ #define GAME_ENABLE_ALL_FRAMES                                (1 << 1)
+ #define GAME_SHOW_DEBUG_PROPS                         (1 << 2)
+ #define GAME_SHOW_FRAMERATE                                   (1 << 3)
+ #define GAME_SHOW_PHYSICS                                     (1 << 4)
+ #define GAME_DISPLAY_LISTS                                    (1 << 5)
+ #define GAME_GLSL_NO_LIGHTS                                   (1 << 6)
+ #define GAME_GLSL_NO_SHADERS                          (1 << 7)
+ #define GAME_GLSL_NO_SHADOWS                          (1 << 8)
+ #define GAME_GLSL_NO_RAMPS                                    (1 << 9)
+ #define GAME_GLSL_NO_NODES                                    (1 << 10)
+ #define GAME_GLSL_NO_EXTRA_TEX                                (1 << 11)
+ #define GAME_IGNORE_DEPRECATION_WARNINGS      (1 << 12)
+ /* GameData.matmode */
+ #define GAME_MAT_TEXFACE      0
+ #define GAME_MAT_MULTITEX     1
+ #define GAME_MAT_GLSL         2
  typedef struct TimeMarker {
        struct TimeMarker *next, *prev;
        int frame;
@@@ -439,8 -456,11 +461,11 @@@ typedef struct Paint 
        Brush **brushes;
        int active_brush_index, brush_count;
        
-       /* WM handle */
+       /* WM Paint cursor */
        void *paint_cursor;
+       unsigned char paint_cursor_col[4];
+       int pad;
  } Paint;
  
  typedef struct ImagePaintSettings {
@@@ -468,10 -488,15 +493,15 @@@ typedef struct ParticleEditSettings 
        ParticleBrushData brush[7]; /* 7 = PE_TOT_BRUSH */
        void *paintcursor;                      /* runtime */
  
-       float emitterdist;
-       int draw_timed;
+       float emitterdist, rt;
+       int selectmode;
+       int edittype;
+       int draw_step, fade_frames;
  
-       int selectmode, pad;
+       struct Scene *scene;
+       struct Object *object;
  } ParticleEditSettings;
  
  typedef struct TransformOrientation {
  
  typedef struct Sculpt {
        Paint paint;
-       
-       /* WM handle */
-       void *cursor;
  
        /* For rotating around a pivot point */
        float pivot[3];
@@@ -702,7 -724,9 +729,9 @@@ typedef struct Scene 
  
        /* Units */
        struct UnitSettings unit;
+       
+       /* Grease Pencil */
+       struct bGPdata *gpd;
  } Scene;
  
  
  #define R_INTERN      0
  #define R_YAFRAY      1
  
 +/* raytrace structure */
 +#define R_RAYSTRUCTURE_AUTO                           0
 +#define R_RAYSTRUCTURE_OCTREE                 1
 +#define R_RAYSTRUCTURE_BLIBVH                 2
 +#define R_RAYSTRUCTURE_VBVH                           3
 +#define R_RAYSTRUCTURE_SIMD_SVBVH             4       /* needs SIMD */
 +#define R_RAYSTRUCTURE_SIMD_QBVH              5       /* needs SIMD */
 +#define R_RAYSTRUCTURE_BIH                            6
 +
  /* scemode (int now) */
  #define R_DOSEQ                               0x0001
  #define R_BG_RENDER                   0x0002
@@@ -1032,9 -1047,10 +1061,10 @@@ typedef enum SculptFlags 
  #define PE_LOCK_FIRST                 2
  #define PE_DEFLECT_EMITTER            4
  #define PE_INTERPOLATE_ADDED  8
- #define PE_SHOW_CHILD                 16
- #define PE_SHOW_TIME                  32
+ #define PE_DRAW_PART                  16
  #define PE_X_MIRROR                           64
+ #define PE_FADE_TIME                  128
+ #define PE_AUTO_VELOCITY              256
  
  /* toolsetting->particle brushtype */
  #define PE_BRUSH_NONE         -1
  #define PE_BRUSH_LENGTH               2
  #define PE_BRUSH_PUFF         3
  #define PE_BRUSH_ADD          4
- #define PE_BRUSH_WEIGHT               5
- #define PE_BRUSH_SMOOTH               6
+ #define PE_BRUSH_SMOOTH               5
  
  /* this must equal ParticleEditSettings.brush array size */
- #define PE_TOT_BRUSH          7  
+ #define PE_TOT_BRUSH          6
+ /* tooksettings->particle edittype */
+ #define PE_TYPE_PARTICLES     0
+ #define PE_TYPE_SOFTBODY      1
+ #define PE_TYPE_CLOTH         2
  
  /* toolsettings->retopo_mode */
  #define RETOPO 1
index db832f1d31c4488a0cadd43718b5c56e76ed95b3,965796c6d5ba5b9f83dcaf5ea15c9571cb28730e..903859413569d1975b17513e6c5e602f85be7912
@@@ -32,6 -32,9 +32,9 @@@
  #include "DNA_scene_types.h"
  #include "DNA_userdef_types.h"
  
+ /* Include for Bake Options */
+ #include "RE_pipeline.h"
  #ifdef WITH_FFMPEG
  #include "BKE_writeffmpeg.h"
  #include <libavcodec/avcodec.h> 
@@@ -62,6 -65,9 +65,9 @@@ EnumPropertyItem prop_mode_items[] =
  
  #include "BLI_threads.h"
  
+ #include "ED_info.h"
+ #include "ED_node.h"
  #include "RE_pipeline.h"
  
  PointerRNA rna_Scene_objects_get(CollectionPropertyIterator *iter)
@@@ -357,12 -363,6 +363,6 @@@ static void rna_SceneRenderLayer_layer_
        rl->lay= layer_set(rl->lay, values);
  }
  
- static void rna_SceneRenderLayer_zmask_layer_set(PointerRNA *ptr, const int *values)
- {
-       SceneRenderLayer *rl= (SceneRenderLayer*)ptr->data;
-       rl->lay_zmask= layer_set(rl->lay_zmask, values);
- }
  static void rna_SceneRenderLayer_pass_update(bContext *C, PointerRNA *ptr)
  {
        Scene *scene= (Scene*)ptr->id.data;
                ntreeCompositForceHidden(scene->nodetree, scene);
  }
  
+ void rna_Scene_use_nodes_set(PointerRNA *ptr, int value)
+ {
+       Scene *scene= (Scene*)ptr->data;
+       scene->use_nodes= value;
+       if(scene->use_nodes && scene->nodetree==NULL)
+               ED_node_composit_default(scene);
+ }
  #else
  
  static void rna_def_tool_settings(BlenderRNA  *brna)
        PropertyRNA *prop;
  
        static EnumPropertyItem uv_select_mode_items[] = {
-               {UV_SELECT_VERTEX, "VERTEX", ICON_VERTEXSEL, "Vertex", "Vertex selection mode."},
-               {UV_SELECT_EDGE, "EDGE", ICON_EDGESEL, "Edge", "Edge selection mode."},
-               {UV_SELECT_FACE, "FACE", ICON_FACESEL, "Face", "Face selection mode."},
-               {UV_SELECT_ISLAND, "ISLAND", ICON_LINKEDSEL, "Island", "Island selection mode."},
+               {UV_SELECT_VERTEX, "VERTEX", ICON_UV_VERTEXSEL, "Vertex", "Vertex selection mode."},
+               {UV_SELECT_EDGE, "EDGE", ICON_UV_EDGESEL, "Edge", "Edge selection mode."},
+               {UV_SELECT_FACE, "FACE", ICON_UV_FACESEL, "Face", "Face selection mode."},
+               {UV_SELECT_ISLAND, "ISLAND", ICON_UV_ISLANDSEL, "Island", "Island selection mode."},
                {0, NULL, 0, NULL, NULL}};
  
        static EnumPropertyItem mesh_select_mode_items[] = {
                {0, NULL, 0, NULL, NULL}};
                
        static EnumPropertyItem auto_key_items[] = {
-               {AUTOKEY_MODE_NORMAL, "ADD_REPLACE_KEYS", 0, "Add/Replace", ""},
+               {AUTOKEY_MODE_NORMAL, "ADD_REPLACE_KEYS", 0, "Add & Replace", ""},
                {AUTOKEY_MODE_EDITKEYS, "REPLACE_KEYS", 0, "Replace", ""},
                {0, NULL, 0, NULL, NULL}};
  
        RNA_def_property_enum_items(prop, prop_mode_items);
        RNA_def_property_ui_text(prop, "Proportional Editing Falloff", "Falloff type for proportional editing mode.");
  
+       prop= RNA_def_property(srna, "normal_size", PROP_FLOAT, PROP_DISTANCE);
+       RNA_def_property_float_sdna(prop, NULL, "normalsize");
+       RNA_def_property_ui_text(prop, "Normal Size", "Display size for normals in the 3D view.");
+       RNA_def_property_range(prop, 0.00001, 1000.0);
+       RNA_def_property_ui_range(prop, 0.01, 10.0, 0.1, 2);
+       RNA_def_property_update(prop, NC_GEOM|ND_DATA, NULL);
        prop= RNA_def_property(srna, "automerge_editing", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "automerge", 0);
        RNA_def_property_ui_text(prop, "AutoMerge Editing", "Automatically merge vertices moved to the same location.");
@@@ -575,7 -591,7 +591,7 @@@ void rna_def_render_layer_common(Struct
        else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
  
        /* layers */
-       prop= RNA_def_property(srna, "visible_layers", PROP_BOOLEAN, PROP_NONE);
+       prop= RNA_def_property(srna, "visible_layers", PROP_BOOLEAN, PROP_LAYER_MEMBER);
        RNA_def_property_boolean_sdna(prop, NULL, "lay", 1);
        RNA_def_property_array(prop, 20);
        RNA_def_property_ui_text(prop, "Visible Layers", "Scene layers included in this render layer.");
        if(scene) RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL);
        else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
  
-       prop= RNA_def_property(srna, "zmask_layers", PROP_BOOLEAN, PROP_NONE);
+       prop= RNA_def_property(srna, "zmask_layers", PROP_BOOLEAN, PROP_LAYER);
        RNA_def_property_boolean_sdna(prop, NULL, "lay_zmask", 1);
        RNA_def_property_array(prop, 20);
        RNA_def_property_ui_text(prop, "Zmask Layers", "Zmask scene layers.");
-       if(scene) RNA_def_property_boolean_funcs(prop, NULL, "rna_SceneRenderLayer_zmask_layer_set");
-       else RNA_def_property_boolean_funcs(prop, NULL, "rna_RenderLayer_zmask_layer_set");
        if(scene) RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL);
        else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
  
@@@ -776,9 -790,9 +790,9 @@@ void rna_def_scene_game_data(BlenderRN
        PropertyRNA *prop;
  
        static EnumPropertyItem framing_types_items[] ={
-               {SCE_GAMEFRAMING_BARS, "BARS", 0, "Stretch", ""},
-               {SCE_GAMEFRAMING_EXTEND, "EXTEND", 0, "Extend", ""},
-               {SCE_GAMEFRAMING_SCALE, "SCALE", 0, "Scale", ""},
+               {SCE_GAMEFRAMING_BARS, "LETTERBOX", 0, "Letterbox", "Show the entire viewport in the display window, using bar horizontally or vertically"},
+               {SCE_GAMEFRAMING_EXTEND, "EXTEND", 0, "Extend", "Show the entire viewport in the display window, viewing more horizontally or vertically"},
+               {SCE_GAMEFRAMING_SCALE, "SCALE", 0, "Scale", "Stretch or squeeze the viewport to fill the display window"},
                {0, NULL, 0, NULL, NULL}};
  
        static EnumPropertyItem dome_modes_items[] ={
                {0, NULL, 0, NULL, NULL}};
                
        static EnumPropertyItem stereo_items[] ={
-               {STEREO_NOSTEREO, "NO_STEREO", 0, "No Stereo", ""},
+               {STEREO_NOSTEREO, "NONE", 0, "None", ""},
                {STEREO_ENABLED, "STEREO", 0, "Stereo", ""},
                {STEREO_DOME, "DOME", 0, "Dome", ""},
                {0, NULL, 0, NULL, NULL}};
                {WOPHY_BULLET, "BULLET", 0, "Bullet", ""},
                {0, NULL, 0, NULL, NULL}};
  
+       static EnumPropertyItem material_items[] ={
+               {GAME_MAT_TEXFACE, "TEXTURE_FACE", 0, "Texture Face", "Single texture face materials."},
+               {GAME_MAT_MULTITEX, "MULTITEXTURE", 0, "Multitexture", "Multitexture materials."},
+               {GAME_MAT_GLSL, "GLSL", 0, "GLSL", "OpenGL shading language shaders."},
+               {0, NULL, 0, NULL, NULL}};
        srna= RNA_def_struct(brna, "SceneGameData", NULL);
        RNA_def_struct_sdna(srna, "GameData");
        RNA_def_struct_nested(brna, srna, "Scene");
        RNA_def_property_range(prop, 0.0, 1000.0);
        RNA_def_property_ui_text(prop, "box radius", "Radius of the activity bubble, in Manhattan length. Objects outside the box are activity-culled");
        RNA_def_property_update(prop, NC_SCENE, NULL);
+       /* booleans */
+       prop= RNA_def_property(srna, "all_frames", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", GAME_ENABLE_ALL_FRAMES);
+       RNA_def_property_ui_text(prop, "All Frames", "Render as many frames as possible, rather than respecting framerate.");
+       RNA_def_property_update(prop, NC_SCENE, NULL);
+       prop= RNA_def_property(srna, "show_debug_properties", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", GAME_SHOW_DEBUG_PROPS);
+       RNA_def_property_ui_text(prop, "Show Debug Properties", "Show properties marked for debugging while the game runs.");
+       RNA_def_property_update(prop, NC_SCENE, NULL);
+       prop= RNA_def_property(srna, "show_framerate_profile", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", GAME_SHOW_FRAMERATE);
+       RNA_def_property_ui_text(prop, "Show Framerate and Profile", "Show framerate and profiling information while the game runs.");
+       RNA_def_property_update(prop, NC_SCENE, NULL);
+       prop= RNA_def_property(srna, "show_physics_visualization", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", GAME_SHOW_PHYSICS);
+       RNA_def_property_ui_text(prop, "Show Physics Visualization", "Show a visualization of physics bounds and interactions.");
+       RNA_def_property_update(prop, NC_SCENE, NULL);
+       prop= RNA_def_property(srna, "display_lists", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", GAME_DISPLAY_LISTS);
+       RNA_def_property_ui_text(prop, "Display Lists", "Use display lists to speed up rendering by keeping geometry on the GPU.");
+       RNA_def_property_update(prop, NC_SCENE, NULL);
+       prop= RNA_def_property(srna, "deprecation_warnings", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_IGNORE_DEPRECATION_WARNINGS);
+       RNA_def_property_ui_text(prop, "Deprecation Warnings", "Print warnings when using deprecated features in the python API.");
+       RNA_def_property_update(prop, NC_SCENE, NULL);
+       /* materials */
+       prop= RNA_def_property(srna, "material_mode", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_sdna(prop, NULL, "matmode");
+       RNA_def_property_enum_items(prop, material_items);
+       RNA_def_property_ui_text(prop, "Material Mode", "Material mode to use for rendering.");
+       RNA_def_property_update(prop, NC_SCENE, NULL);
+       prop= RNA_def_property(srna, "glsl_lights", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_GLSL_NO_LIGHTS);
+       RNA_def_property_ui_text(prop, "GLSL Lights", "Use lights for GLSL rendering.");
+       RNA_def_property_update(prop, NC_SCENE, NULL);
+       prop= RNA_def_property(srna, "glsl_shaders", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_GLSL_NO_SHADERS);
+       RNA_def_property_ui_text(prop, "GLSL Shaders", "Use shaders for GLSL rendering.");
+       RNA_def_property_update(prop, NC_SCENE, NULL);
+       prop= RNA_def_property(srna, "glsl_shadows", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_GLSL_NO_SHADOWS);
+       RNA_def_property_ui_text(prop, "GLSL Shadows", "Use shadows for GLSL rendering.");
+       RNA_def_property_update(prop, NC_SCENE, NULL);
+       prop= RNA_def_property(srna, "glsl_ramps", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_GLSL_NO_RAMPS);
+       RNA_def_property_ui_text(prop, "GLSL Ramps", "Use ramps for GLSL rendering.");
+       RNA_def_property_update(prop, NC_SCENE, NULL);
+       prop= RNA_def_property(srna, "glsl_nodes", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_GLSL_NO_NODES);
+       RNA_def_property_ui_text(prop, "GLSL Nodes", "Use nodes for GLSL rendering.");
+       RNA_def_property_update(prop, NC_SCENE, NULL);
+       prop= RNA_def_property(srna, "glsl_extra_textures", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_GLSL_NO_EXTRA_TEX);
+       RNA_def_property_ui_text(prop, "GLSL Extra Textures", "Use extra textures like normal or specular maps for GLSL rendering.");
+       RNA_def_property_update(prop, NC_SCENE, NULL);
  }
  
  static void rna_def_scene_render_layer(BlenderRNA *brna)
@@@ -1024,24 -1112,37 +1112,48 @@@ static void rna_def_scene_render_data(B
                {R_OUTPUT_WINDOW, "WINDOW", 0, "New Window", "Images are rendered in new Window"},
                {0, NULL, 0, NULL, NULL}};
        
+       /* Bake */
+       static EnumPropertyItem bake_mode_items[] ={
+               {RE_BAKE_ALL, "FULL", 0, "Full Render", ""},
+               {RE_BAKE_AO, "AO", 0, "Ambient Occlusion", ""},
+               {RE_BAKE_SHADOW, "SHADOW", 0, "Shadow", ""},
+               {RE_BAKE_NORMALS, "NORMALS", 0, "Normals", ""},
+               {RE_BAKE_TEXTURE, "TEXTURE", 0, "Textures", ""},
+               {RE_BAKE_DISPLACEMENT, "DISPLACEMENT", 0, "Displacement", ""},
+               {0, NULL, 0, NULL, NULL}};
+       static EnumPropertyItem bake_normal_space_items[] ={
+               {R_BAKE_SPACE_CAMERA, "CAMERA", 0, "Camera", ""},
+               {R_BAKE_SPACE_WORLD, "WORLD", 0, "World", ""},
+               {R_BAKE_SPACE_OBJECT, "OBJECT", 0, "Object", ""},
+               {R_BAKE_SPACE_TANGENT, "TANGENT", 0, "Tangent", ""},
+               {0, NULL, 0, NULL, NULL}};
+               
+       static EnumPropertyItem bake_aa_items[] ={
+               {5, "AA_5", 0, "5", ""},
+               {8, "AA_8", 0, "8", ""},
+               {11, "AA_11", 0, "11", ""},
+               {16, "AA_16", 0, "16", ""},
+               {0, NULL, 0, NULL, NULL}};
+       
        static EnumPropertyItem octree_resolution_items[] = {
                {64, "OCTREE_RES_64", 0, "64", ""},
                {128, "OCTREE_RES_128", 0, "128", ""},
                {256, "OCTREE_RES_256", 0, "256", ""},
                {512, "OCTREE_RES_512", 0, "512", ""},
                {0, NULL, 0, NULL, NULL}};
 -              
 +
 +      static EnumPropertyItem raytrace_structure_items[] = {
 +              {R_RAYSTRUCTURE_AUTO, "{R_RAYSTRUCTURE_AUTO", 0, "auto", ""},
 +              {R_RAYSTRUCTURE_OCTREE, "R_RAYSTRUCTURE_OCTREE", 0, "octree", "Use old octree structure (no support for instances)"},
 +              {R_RAYSTRUCTURE_BLIBVH, "R_RAYSTRUCTURE_BLIBVH", 0, "blibvh", "Use BLI_kdopbvh.c"},
 +              {R_RAYSTRUCTURE_VBVH, "R_RAYSTRUCTURE_VBVH", 0, "vBVH", ""},
 +              {R_RAYSTRUCTURE_SIMD_SVBVH, "R_RAYSTRUCTURE_SIMD_SVBVH", 0, "SIMD SVBVH", "Requires SIMD"},
 +              {R_RAYSTRUCTURE_SIMD_QBVH, "R_RAYSTRUCTURE_SIMD_QBVH", 0, "SIMD QBVH", "Requires SIMD"},
 +              {R_RAYSTRUCTURE_BIH, "R_RAYSTRUCTURE_BIH", 0, "BIH", ""},
 +              {0, NULL, 0, NULL, NULL}
 +              };
 +
        static EnumPropertyItem fixed_oversample_items[] = {
                {5, "OVERSAMPLE_5", 0, "5", ""},
                {8, "OVERSAMPLE_8", 0, "8", ""},
                {0, "STAMP_FONT_LARGE", 0, "Large", ""},
                {4, "STAMP_FONT_EXTRALARGE", 0, "Extra Large", ""},
                {0, NULL, 0, NULL, NULL}};
-               
-       
        static EnumPropertyItem image_type_items[] = {
+               {0, "", 0, "Image", NULL},
                {R_PNG, "PNG", 0, "PNG", ""},
                {R_JPEG90, "JPEG", 0, "JPEG", ""},
  #ifdef WITH_OPENJPEG
                {R_JP2, "JPEG2000", 0, "JPEG 2000", ""},
  #endif                
-               {R_TIFF, "TIFF", 0, "TIFF", ""},        // XXX only with G.have_libtiff
                {R_BMP, "BMP", 0, "BMP", ""},
                {R_TARGA, "TARGA", 0, "Targa", ""},
                {R_RAWTGA, "RAWTARGA", 0, "Targa Raw", ""},
                //{R_DDS, "DDS", 0, "DDS", ""}, // XXX not yet implemented
                {R_HAMX, "HAMX", 0, "HamX", ""},
                {R_IRIS, "IRIS", 0, "Iris", ""},
-               {0, "", 0, NULL, NULL},
+               {0, "", 0, " ", NULL},
  #ifdef WITH_OPENEXR
                {R_OPENEXR, "OPENEXR", 0, "OpenEXR", ""},
                {R_MULTILAYER, "MULTILAYER", 0, "MultiLayer", ""},
  #endif
+               {R_TIFF, "TIFF", 0, "TIFF", ""},        // XXX only with G.have_libtiff
                {R_RADHDR, "RADHDR", 0, "Radiance HDR", ""},
                {R_CINEON, "CINEON", 0, "Cineon", ""},
                {R_DPX, "DPX", 0, "DPX", ""},
-               {0, "", 0, NULL, NULL},
+               {0, "", 0, "Movie", NULL},
                {R_AVIRAW, "AVIRAW", 0, "AVI Raw", ""},
                {R_AVIJPEG, "AVIJPEG", 0, "AVI JPEG", ""},
  #ifdef _WIN32
  #endif
                {R_FFMPEG, "FFMPEG", 0, "FFMpeg", ""},
  #endif
-               {0, "", 0, NULL, NULL},
                {R_FRAMESERVER, "FRAMESERVER", 0, "Frame Server", ""},
                {0, NULL, 0, NULL, NULL}};
                
        RNA_def_property_enum_items(prop, octree_resolution_items);
        RNA_def_property_ui_text(prop, "Octree Resolution", "Resolution of raytrace accelerator. Use higher resolutions for larger scenes.");
        RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL);
 -      
 +
 +      prop= RNA_def_property(srna, "raytrace_structure", PROP_ENUM, PROP_NONE);
 +      RNA_def_property_enum_sdna(prop, NULL, "raystructure");
 +      RNA_def_property_enum_items(prop, raytrace_structure_items);
 +      RNA_def_property_ui_text(prop, "Raytrace Acceleration Structure", "Type of raytrace accelerator structure.");
 +      RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL);
 +
        prop= RNA_def_property(srna, "antialiasing", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "mode", R_OSA);
        RNA_def_property_ui_text(prop, "Anti-Aliasing", "Render and combine multiple samples per pixel to prevent jagged edges.");
        RNA_def_property_ui_text(prop, "Edge", "Create a toon outline around the edges of geometry");
        RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL);
        
-       prop= RNA_def_property(srna, "edge_intensity", PROP_INT, PROP_NONE);
+       prop= RNA_def_property(srna, "edge_threshold", PROP_INT, PROP_NONE);
        RNA_def_property_int_sdna(prop, NULL, "edgeint");
        RNA_def_property_range(prop, 0, 255);
-       RNA_def_property_ui_text(prop, "Edge Intensity", "Threshold for drawing outlines on geometry edges");
+       RNA_def_property_ui_text(prop, "Edge Threshold", "Threshold for drawing outlines on geometry edges");
        RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL);
        
        prop= RNA_def_property(srna, "edge_color", PROP_FLOAT, PROP_COLOR);
        RNA_def_property_ui_text(prop, "Motion Blur", "Use multi-sampled 3D scene motion blur (uses number of anti-aliasing samples).");
        RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL);
        
-       prop= RNA_def_property(srna, "border", PROP_BOOLEAN, PROP_NONE);
+       prop= RNA_def_property(srna, "use_border", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "mode", R_BORDER);
        RNA_def_property_ui_text(prop, "Border", "Render a user-defined border region, within the frame size.");
        RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL);
        RNA_def_property_ui_text(prop, "Crop to Border", "Crop the rendered frame to the defined border size.");
        RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL);
        
-       prop= RNA_def_property(srna, "placeholders", PROP_BOOLEAN, PROP_NONE);
+       prop= RNA_def_property(srna, "use_placeholder", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "mode", R_TOUCH);
        RNA_def_property_ui_text(prop, "Placeholders", "Create empty placeholder files while rendering frames (similar to Unix 'touch').");
        RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL);
        
-       prop= RNA_def_property(srna, "no_overwrite", PROP_BOOLEAN, PROP_NONE);
-       RNA_def_property_boolean_sdna(prop, NULL, "mode", R_NO_OVERWRITE);
-       RNA_def_property_ui_text(prop, "No Overwrite", "Skip and don't overwrite existing files while rendering");
+       prop= RNA_def_property(srna, "use_overwrite", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_negative_sdna(prop, NULL, "mode", R_NO_OVERWRITE);
+       RNA_def_property_ui_text(prop, "Overwrite", "Overwrite existing files while rendering.");
        RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL);
        
        prop= RNA_def_property(srna, "use_compositing", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "scemode", R_FREE_IMAGE);
        RNA_def_property_ui_text(prop, "Free Image Textures", "Free all image texture from memory after render, to save memory before compositing.");
        RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL);
-       
+       prop= RNA_def_property(srna, "free_unused_nodes", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "scemode", R_FREE_IMAGE);
+       RNA_def_property_ui_text(prop, "Free Unused Nodes", "Free Nodes that are not used while compositing, to save memory.");
+       RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL);
        prop= RNA_def_property(srna, "save_buffers", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "scemode", R_EXR_TILE_FILE);
        RNA_def_property_boolean_funcs(prop, "rna_SceneRenderData_save_buffers_get", NULL);
        RNA_def_property_ui_text(prop, "Output Path", "Directory/name to save animations, # characters defines the position and length of frame numbers.");
        RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL);
  
+       /* Bake */
+       
+       prop= RNA_def_property(srna, "bake_type", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_bitflag_sdna(prop, NULL, "bake_mode");
+       RNA_def_property_enum_items(prop, bake_mode_items);
+       RNA_def_property_ui_text(prop, "Bake Mode", "");
+       
+       prop= RNA_def_property(srna, "bake_normal_space", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_bitflag_sdna(prop, NULL, "bake_normal_space");
+       RNA_def_property_enum_items(prop, bake_normal_space_items);
+       RNA_def_property_ui_text(prop, "Normal Space", "Choose normal space for baking");
+       
+       prop= RNA_def_property(srna, "bake_aa_mode", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_bitflag_sdna(prop, NULL, "bake_osa");
+       RNA_def_property_enum_items(prop, bake_aa_items);
+       RNA_def_property_ui_text(prop, "Anti-Aliasing Level", "");
+       
+       prop= RNA_def_property(srna, "bake_active", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "bake_flag", R_BAKE_TO_ACTIVE);
+       RNA_def_property_ui_text(prop, "Selected to Active", "Bake shading on the surface of selected objects to the active object");
+       
+       prop= RNA_def_property(srna, "bake_normalized", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "bake_flag", R_BAKE_NORMALIZE);
+       RNA_def_property_ui_text(prop, "Normalized", "");
+       //"Bake ambient occlusion normalized, without taking into acount material settings"
+       //"Normalized displacement value to fit the 'Dist' range"
+       // XXX: Need 1 tooltip here...
+       
+       prop= RNA_def_property(srna, "bake_clear", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "bake_flag", R_BAKE_CLEAR);
+       RNA_def_property_ui_text(prop, "Clear", "Clear Images before baking");
+       
+       prop= RNA_def_property(srna, "bake_enable_aa", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "bake_flag", R_BAKE_OSA);
+       RNA_def_property_ui_text(prop, "Anti-Aliasing", "Enables Anti-aliasing");
+       
+       prop= RNA_def_property(srna, "bake_margin", PROP_INT, PROP_NONE);
+       RNA_def_property_int_sdna(prop, NULL, "bake_filter");
+       RNA_def_property_range(prop, 0, 32);
+       RNA_def_property_ui_text(prop, "Margin", "Amount of pixels to extend the baked result with, as post process filter");
+       prop= RNA_def_property(srna, "bake_distance", PROP_FLOAT, PROP_NONE);
+       RNA_def_property_float_sdna(prop, NULL, "bake_maxdist");
+       RNA_def_property_range(prop, 0.0, 1000.0);
+       RNA_def_property_ui_text(prop, "Distance", "Maximum distance from active object to other object (in blender units");
+       
+       prop= RNA_def_property(srna, "bake_bias", PROP_FLOAT, PROP_NONE);
+       RNA_def_property_float_sdna(prop, NULL, "bake_biasdist");
+       RNA_def_property_range(prop, 0.0, 1000.0);
+       RNA_def_property_ui_text(prop, "Bias", "Bias towards faces further away from the object (in blender units)");
+       
        /* stamp */
        
        prop= RNA_def_property(srna, "stamp_time", PROP_BOOLEAN, PROP_NONE);
@@@ -1750,6 -1900,7 +1917,7 @@@ void RNA_def_scene(BlenderRNA *brna
  {
        StructRNA *srna;
        PropertyRNA *prop;
+       FunctionRNA *func;
        
        /* Struct definition */
        srna= RNA_def_struct(brna, "Scene", "ID");
        RNA_def_property_collection_funcs(prop, 0, 0, 0, "rna_Scene_objects_get", 0, 0, 0, 0, 0);
  
        /* Layers */
-       prop= RNA_def_property(srna, "visible_layers", PROP_BOOLEAN, PROP_NONE);
+       prop= RNA_def_property(srna, "visible_layers", PROP_BOOLEAN, PROP_LAYER_MEMBER);
        RNA_def_property_boolean_sdna(prop, NULL, "lay", 1);
        RNA_def_property_array(prop, 20);
        RNA_def_property_ui_text(prop, "Visible Layers", "Layers visible when rendering the scene.");
        /* Nodes (Compositing) */
        prop= RNA_def_property(srna, "nodetree", PROP_POINTER, PROP_NONE);
        RNA_def_property_ui_text(prop, "Node Tree", "Compositing node tree.");
+       prop= RNA_def_property(srna, "use_nodes", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "use_nodes", 1);
+       RNA_def_property_boolean_funcs(prop, NULL, "rna_Scene_use_nodes_set");
+       RNA_def_property_ui_text(prop, "Use Nodes", "Enable the compositing node tree.");
+       RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL);
        
        /* Sequencer */
        prop= RNA_def_property(srna, "sequence_editor", PROP_POINTER, PROP_NONE);
        
        prop= RNA_def_property(srna, "active_keying_set", PROP_POINTER, PROP_NONE);
        RNA_def_property_struct_type(prop, "KeyingSet");
+       RNA_def_property_flag(prop, PROP_EDITABLE);
        RNA_def_property_editable_func(prop, "rna_Scene_active_keying_set_editable");
        RNA_def_property_pointer_funcs(prop, "rna_Scene_active_keying_set_get", "rna_Scene_active_keying_set_set", NULL);
        RNA_def_property_ui_text(prop, "Active Keying Set", "Active Keying Set used to insert/delete keyframes.");
        RNA_def_property_pointer_sdna(prop, NULL, "gm");
        RNA_def_property_struct_type(prop, "SceneGameData");
        RNA_def_property_ui_text(prop, "Game Data", "");
+       /* Statistics */
+       func= RNA_def_function(srna, "statistics", "ED_info_stats_string");
+       prop= RNA_def_string(func, "statistics", "", 0, "Statistics", "");
+       RNA_def_function_return(func, prop);
+       
+       /* Grease Pencil */
+       prop= RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
+       RNA_def_property_pointer_sdna(prop, NULL, "gpd");
+       RNA_def_property_flag(prop, PROP_EDITABLE);
+       RNA_def_property_struct_type(prop, "GreasePencil");
+       RNA_def_property_ui_text(prop, "Grease Pencil Data", "Grease Pencil datablock");
        
+       /* Nestled Data  */
        rna_def_tool_settings(brna);
        rna_def_unit_settings(brna);
        rna_def_scene_render_data(brna);
        rna_def_scene_game_data(brna);
        rna_def_scene_render_layer(brna);
+       
+       /* Scene API */
+       RNA_api_scene(srna);
  }
  
  #endif
index 9c1dd385635b88912771c4bbdb57358dc0eb036b,db151775b966691edc4780eac2f767d13245a8bf..a15dada1bec3af4f68d9c0b4fc4e454a2a33898c
@@@ -1,14 -1,12 +1,14 @@@
  #!/usr/bin/python
  Import ('env')
  
- cflags = ['-O3','-msse2','-mfpmath=sse']
- cxxflags = ['-O3','-msse2','-mfpmath=sse']
 -cflags=''
++cflags = ['-msse2','-mfpmath=sse']
++cxxflags = ['-msse2','-mfpmath=sse']
  sources = env.Glob('intern/source/*.c')
 +raysources = env.Glob('intern/raytrace/*.cpp')
  
  incs = 'intern/include #/intern/guardedalloc ../blenlib ../makesdna ../makesrna'
  incs += ' extern/include ../blenkernel ../radiosity/extern/include ../imbuf'
- incs += ' ../include ../blenloader'
+ incs += ' ../include ../blenloader ../../../intern/smoke/extern'
  
  defs = []
  
@@@ -23,7 -21,6 +23,7 @@@ if env['WITH_BF_OPENEXR']
      defs.append('WITH_OPENEXR')
  
  if env['OURPLATFORM']=='linux2':
 -    cflags='-pthread'
 +    cflags += ['-pthread']
  
  env.BlenderLib ( libname = 'bf_render', sources = sources, includes = Split(incs), defines=defs, libtype='core', priority=145, compileflags=cflags )
 +env.BlenderLib ( libname = 'bf_render_raytrace', sources = raysources, includes = Split(incs), defines=defs, libtype='core', priority=145, compileflags=cflags, cxx_compileflags=cxxflags )
index 0bdecb333e8e5c27a8a40c8275eb9c823e9c241f,8f429f7dd906f9a0eae9be6b5dbf74f981e7f83d..af3ea8e2ac0973b06b1534b4283b3e1f5820ef29
@@@ -22,7 -22,7 +22,7 @@@
   *
   * The Original Code is: all of this file.
   *
 - * Contributor(s): none yet.
 + * Contributor(s): André Pinto.
   *
   * ***** END GPL LICENSE BLOCK *****
   * RE_raytrace.h: ray tracing api, can be used independently from the renderer. 
  #ifndef RE_RAYTRACE_H
  #define RE_RAYTRACE_H
  
 -/* ray types */
 -#define RE_RAY_SHADOW 0
 -#define RE_RAY_MIRROR 1
 -#define RE_RAY_SHADOW_TRA 2
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
  
 -/* spatial tree for raytracing acceleration */
 -typedef void RayTree;
 -/* abstraction of face type */
 -typedef void RayFace;
 +//#define RE_RAYCOUNTER                       /* enable counters per ray, usefull for measuring raytrace structures performance */
  
 -/* object numbers above this are transformed */
 -#define RE_RAY_TRANSFORM_OFFS 0x8000000
 +#define RE_RAY_LCTS_MAX_SIZE  256
 +#define RT_USE_LAST_HIT                       /* last shadow hit is reused before raycasting on whole tree */
 +//#define RT_USE_HINT                 /* last hit object is reused before raycasting on whole tree */
  
 -/* convert from pointer to index in array and back, with offset if the
 - * instance is transformed */
 -#define RAY_OBJECT_SET(re, obi) \
 -      ((obi == NULL)? 0: \
 -      ((obi - (re)->objectinstance) + ((obi->flag & R_TRANSFORMED)? RE_RAY_TRANSFORM_OFFS: 0)))
  
 -#define RAY_OBJECT_GET(re, i) \
 -      ((re)->objectinstance + ((i >= RE_RAY_TRANSFORM_OFFS)? i-RE_RAY_TRANSFORM_OFFS: i))
  
 +/* Internals about raycasting structures can be found on intern/raytree.h */
 +typedef struct RayObject RayObject;
 +typedef struct Isect Isect;
 +typedef struct RayHint RayHint;
 +typedef struct RayTraceHint RayTraceHint;
 +typedef struct RayCounter RayCounter;
  
 -/* struct for intersection data */
 -typedef struct Isect {
 -      float start[3];                 /* start+vec = end, in ray_tree_intersect */
 -      float vec[3];
 -      float end[3];                   
 +struct DerivedMesh;
 +struct Mesh;
 +
 +int  RE_rayobject_raycast(RayObject *r, Isect *i);
 +void RE_rayobject_add    (RayObject *r, RayObject *);
 +void RE_rayobject_done(RayObject *r);
 +void RE_rayobject_free(RayObject *r);
 +
++/* Extend min/max coords so that the rayobject is inside them */
++void RE_rayobject_merge_bb(RayObject *ob, float *min, float *max);
++
 +/* initializes an hint for optiming raycast where it is know that a ray will pass by the given BB often the origin point */
 +void RE_rayobject_hint_bb(RayObject *r, RayHint *hint, float *min, float *max);
 +
 +/* initializes an hint for optiming raycast where it is know that a ray will be contained inside the given cone*/
 +/* void RE_rayobject_hint_cone(RayObject *r, RayHint *hint, float *); */
 +
 +/* RayObject constructors */
 +RayObject* RE_rayobject_octree_create(int ocres, int size);
 +RayObject* RE_rayobject_instance_create(RayObject *target, float transform[][4], void *ob, void *target_ob);
 +
 +RayObject* RE_rayobject_blibvh_create(int size);      /* BLI_kdopbvh.c   */
 +RayObject* RE_rayobject_bvh_create(int size);         /* raytrace/rayobject_bvh.c */
 +RayObject* RE_rayobject_vbvh_create(int size);                /* raytrace/rayobject_vbvh.c */
 +RayObject* RE_rayobject_qbvh_create(int size);                /* raytrace/rayobject_qbvh.c */
 +RayObject* RE_rayobject_svbvh_create(int size);               /* raytrace/rayobject_svbvh.c */
 +RayObject* RE_rayobject_bih_create(int size);         /* rayobject_bih.c */
 +
 +
 +typedef struct LCTSHint LCTSHint;
 +struct LCTSHint
 +{
 +      int size;
 +      RayObject *stack[RE_RAY_LCTS_MAX_SIZE];
 +};
  
 -      float labda, u, v;              /* distance to hitpoint, uv weights */
 +struct RayHint
 +{
 +      union
 +      {
 +              LCTSHint lcts;
 +      } data;
 +};
  
 -      RayFace *face;                  /* face is where to intersect with */
 -      int ob;
 -      RayFace *faceorig;              /* start face */
 -      int oborig;
 -      RayFace *face_last;             /* for shadow optimize, last intersected face */
 -      int ob_last;
  
 +/* Ray Intersection */
 +struct Isect
 +{
 +      float start[3];
 +      float vec[3];
 +      float labda;
 +
 +      /* length of vec, configured by RE_rayobject_raycast */
 +      int   bv_index[6];
 +      float idot_axis[3];
 +      float dist;
 +
 +/*    float end[3];                    - not used */
 +
 +      float u, v;
 +      
 +      struct
 +      {
 +              void *ob;
 +              void *face;
 +      }
 +      hit, orig;
 +      
 +      RayObject *last_hit;    /* last hit optimization */
 +
 +#ifdef RT_USE_HINT
 +      RayTraceHint *hint, *hit_hint;
 +#endif
 +      
        short isect;                    /* which half of quad */
        short mode;                             /* RE_RAY_SHADOW, RE_RAY_MIRROR, RE_RAY_SHADOW_TRA */
        int lay;                                /* -1 default, set for layer lamps */
 +      
 +      int skip;                               /* RE_SKIP_CULLFACE */
  
 -      /* only used externally */
        float col[4];                   /* RGBA for shadow_tra */
  
 -      /* octree only */
 -      RayFace *facecontr;
 -      int obcontr;
 -      float ddalabda;
 -      short faceisect;                /* flag if facecontr was done or not */
 -
 -      /* custom pointer to be used in the RayCheckFunc */
        void *userdata;
 -} Isect;
 -
 -/* function callbacks for face type abstraction */
 -typedef void (*RayCoordsFunc)(RayFace *face,
 -      float **v1, float **v2, float **v3, float **v4);
 -typedef int (*RayCheckFunc)(Isect *is, int ob, RayFace *face);
 -typedef float *(*RayObjectTransformFunc)(void *userdata, int ob);
 -
 -/* tree building and freeing */
 -RayTree *RE_ray_tree_create(int ocres, int totface, float *min, float *max,
 -      RayCoordsFunc coordfunc, RayCheckFunc checkfunc,
 -      RayObjectTransformFunc transformfunc, void *userdata);
 -void RE_ray_tree_add_face(RayTree *tree, int ob, RayFace *face);
 -void RE_ray_tree_done(RayTree *tree);
 -void RE_ray_tree_free(RayTree *tree);
 -
 -/* intersection with full tree and single face */
 -int RE_ray_tree_intersect(RayTree *tree, Isect *is);
 -int RE_ray_tree_intersect_check(RayTree *tree, Isect *is, RayCheckFunc check);
 -int RE_ray_face_intersection(Isect *is, RayObjectTransformFunc transformfunc,
 -      RayCoordsFunc coordsfunc);
 -
 -/* retrieve the diameter of the tree structure, for setting intersection
 -   end distance */
 -float RE_ray_tree_max_size(RayTree *tree);
 +      
 +      RayHint *hint;
 +      
 +#ifdef RE_RAYCOUNTER
 +      RayCounter *raycounter;
 +#endif
 +};
  
 -#endif /*__RE_RAYTRACE_H__*/
 +/* ray types */
 +#define RE_RAY_SHADOW 0
 +#define RE_RAY_MIRROR 1
 +#define RE_RAY_SHADOW_TRA 2
  
- #define RE_SKIP_VLR_NEIGHBOUR         (1 << 1)
- #define RE_SKIP_VLR_RENDER_CHECK      (1 << 2)
 +/* skip options */
 +#define RE_SKIP_CULLFACE              (1 << 0)
 +
 +/* if using this flag then *face should be a pointer to a VlakRen */
++#define RE_SKIP_VLR_NEIGHBOUR                 (1 << 1)
++#define RE_SKIP_VLR_RENDER_CHECK              (1 << 2)
++#define RE_SKIP_VLR_NON_SOLID_MATERIAL        (1 << 3)
 +
 +/* TODO use: FLT_MAX? */
 +#define RE_RAYTRACE_MAXDIST   1e33
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +
 +#endif /*__RE_RAYTRACE_H__*/
index 9a340e625f3e8da78b90a98b480f0d652c073611,435e3ddc07fbbe8537256b3fc0c2997e2261d3ea..5660b37d01c388d4c52ae671ac2886ce0d548782
@@@ -30,7 -30,6 +30,7 @@@
  #ifndef RE_SHADER_EXT_H
  #define RE_SHADER_EXT_H
  
 +#include "RE_raytrace.h" /* For RE_RAYCOUNTER */
  /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  /* this include is for shading and texture exports            */
  /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
@@@ -57,7 -56,6 +57,7 @@@ typedef struct ShadeResul
        float refr[3];
        float nor[3];
        float winspeed[4];
 +      float rayhits[4];
  } ShadeResult;
  
  /* only here for quick copy */
@@@ -114,7 -112,7 +114,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 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 */
        struct Group *light_override;
        struct Material *mat_override;
        
 +#ifdef RE_RAYCOUNTER
 +      RayCounter raycounter;
 +#endif
 +      
  } ShadeInput;
  
  
index 2a9b42d22fe51d6b10c52f8b67c4f835f4bcef60,0000000000000000000000000000000000000000..19608fba262432a7feb88d57efa14fa01d04045f
mode 100644,000000..100644
--- /dev/null
@@@ -1,219 -1,0 +1,212 @@@
- /*
-  * Extend min/max coords so that the rayobject is inside them
-  */
- void RE_rayobject_merge_bb(RayObject *ob, float *min, float *max);
 +/**
 + * $Id$
 + *
 + * ***** BEGIN GPL LICENSE BLOCK *****
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version. 
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software Foundation,
 + * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 + *
 + * The Original Code is Copyright (C) 2009 Blender Foundation.
 + * All rights reserved.
 + *
 + * The Original Code is: all of this file.
 + *
 + * Contributor(s): André Pinto.
 + *
 + * ***** END GPL LICENSE BLOCK *****
 + */
 +#ifndef RE_RAYOBJECT_H
 +#define RE_RAYOBJECT_H
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +#include "RE_raytrace.h"
 +#include "render_types.h"
 +#include <float.h>
 +
 +
 +/* RayObject
 +      
 +      A ray object is everything where we can cast rays like:
 +              * a face/triangle
 +              * an octree
 +              * a bvh tree
 +              * an octree of bvh's
 +              * a bvh of bvh's
 +      
 +              
 +      All types of RayObjects can be created by implementing the
 +      callbacks of the RayObject.
 +
 +      Due to high computing time evolved with casting on faces
 +      there is a special type of RayObject (named RayFace)
 +      which won't use callbacks like other generic nodes.
 +      
 +      In order to allow a mixture of RayFace+RayObjects,
 +      all RayObjects must be 4byte aligned, allowing us to use the
 +      2 least significant bits (with the mask 0x02) to define the
 +      type of RayObject.
 +      
 +      This leads to 4 possible types of RayObject, but at the moment
 +      only 2 are used:
 +
 +       addr&2  - type of object
 +              0               Self (reserved for each structure)
 +              1       RayFace
 +              2               RayObject (generic with API callbacks)
 +              3               RayObject_Vlak
 +
 +      0 means it's reserved and has it own meaning inside each ray acceleration structure
 +      (this way each structure can use the allign offset to determine if a node represents a
 +       RayObject primitive, which can be used to save memory)
 +
 +      You actually don't need to care about this if you are only using the API
 +      described on RE_raytrace.h
 + */
 +
 +/* used to align a given ray object */
 +#define RE_rayobject_align(o)                         ((RayObject*)(((intptr_t)o)&(~3)))
 +
 +/* used to unalign a given ray object */
 +#define RE_rayobject_unalignRayFace(o)                ((RayObject*)(((intptr_t)o)|1))
 +#define RE_rayobject_unalignRayAPI(o)         ((RayObject*)(((intptr_t)o)|2))
 +#define RE_rayobject_unalignRayVlak(o)                ((RayObject*)(((intptr_t)o)|3))
 +
 +/* used to test the type of ray object */
 +#define RE_rayobject_isAligned(o)     ((((intptr_t)o)&3) == 0)
 +#define RE_rayobject_isRayFace(o)     ((((intptr_t)o)&3) == 1)
 +#define RE_rayobject_isRayAPI(o)      ((((intptr_t)o)&3) == 2)
 +#define RE_rayobject_isRayVlak(o)     ((((intptr_t)o)&3) == 3)
 +
 +
 +/*
 + * This ray object represents faces directly from a given VlakRen structure.
 + * Thus allowing to save memory, but making code dependant on render structures
 +typedef struct RayVlak
 +{
 +      struct ObjectInstanceRen *ob;
 +      struct VlakRen *face;
 +} RayVlak;
 + */
 +
 +/*
 + * This ray object represents a triangle or a quad face.
 + * All data needed to realize intersection is "localy" available.
 + */
 +typedef struct RayFace
 +{
 +      float v1[4], v2[4], v3[4], v4[3];
 +      int quad;
 +      void *ob;
 +      void *face;
 +      
 +} RayFace;
 +
 +#define RE_rayface_isQuad(a) ((a)->quad)
 +/* Loads a VlakRen on a RayFace */
 +void RE_rayface_from_vlak(RayFace *face, ObjectInstanceRen *obi, VlakRen *vlr);
 +
 +
 +
 +/*
 + * This rayobject represents a generic object. With it's own callbacks for raytrace operations.
 + * It's suitable to implement things like LOD.
 + */
 +struct RayObject
 +{
 +      struct RayObjectAPI *api;
 +};
 +
 +
 +typedef int  (*RE_rayobject_raycast_callback)(RayObject *, Isect *);
 +typedef void (*RE_rayobject_add_callback)(RayObject *raytree, RayObject *rayobject);
 +typedef void (*RE_rayobject_done_callback)(RayObject *);
 +typedef void (*RE_rayobject_free_callback)(RayObject *);
 +typedef void (*RE_rayobject_merge_bb_callback)(RayObject *, float *min, float *max);
 +typedef float (*RE_rayobject_cost_callback)(RayObject *);
 +typedef void (*RE_rayobject_hint_bb_callback)(RayObject *, RayHint *, float *, float *);
 +
 +typedef struct RayObjectAPI
 +{
 +      RE_rayobject_raycast_callback   raycast;
 +      RE_rayobject_add_callback               add;
 +      RE_rayobject_done_callback              done;
 +      RE_rayobject_free_callback              free;
 +      RE_rayobject_merge_bb_callback  bb;
 +      RE_rayobject_cost_callback              cost;
 +      RE_rayobject_hint_bb_callback   hint_bb;
 +      
 +} RayObjectAPI;
 +
 +
 +/*
 + * This function differs from RE_rayobject_raycast
 + * RE_rayobject_intersect does NOT perform last-hit optimization
 + * So this is probably a function to call inside raytrace structures
 + */
 +int RE_rayobject_intersect(RayObject *r, Isect *i);
 +
 +/*
 + * Returns distance ray must travel to hit the given bounding box
 + * BB should be in format [2][3]
 + */
 +/* float RE_rayobject_bb_intersect(const Isect *i, const float *bb); */
 +int RE_rayobject_bb_intersect_test(const Isect *i, const float *bb); /* same as bb_intersect but doens't calculates distance */
 +
 +/*
 + * Returns the expected cost of raycast on this node, primitives have a cost of 1
 + */
 +float RE_rayobject_cost(RayObject *r);
 +
 +
 +
 +
 +#define ISECT_EPSILON ((float)FLT_EPSILON)
 +
 +
 +
 +#if !defined(_WIN32)
 +
 +#include <sys/time.h>
 +#include <time.h>
 +#include <stdio.h>
 +
 +#define BENCH(a,name) \
 +      do {                    \
 +              double _t1, _t2;                                \
 +              struct timeval _tstart, _tend;  \
 +              clock_t _clock_init = clock();  \
 +              gettimeofday ( &_tstart, NULL); \
 +              (a);                                                    \
 +              gettimeofday ( &_tend, NULL);   \
 +              _t1 = ( double ) _tstart.tv_sec + ( double ) _tstart.tv_usec/ ( 1000*1000 );    \
 +              _t2 = ( double )   _tend.tv_sec + ( double )   _tend.tv_usec/ ( 1000*1000 );    \
 +              printf("BENCH:%s: %fs (real) %fs (cpu)\n", #name, _t2-_t1, (float)(clock()-_clock_init)/CLOCKS_PER_SEC);\
 +      } while(0)
 +#else
 +
 +#define BENCH(a)      (a)
 +
 +#endif
 +
 +
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +
 +#endif
index c412921eb3146435bf90100719166191a505b9b4,e50e498228d6ed82c735393afc7442698e09edf5..67c692592133e25840102a7bfd314814e893f837
@@@ -53,8 -53,6 +53,8 @@@ struct VlakTableNode
  struct GHash;
  struct RenderBuckets;
  struct ObjectInstanceRen;
 +struct RayObject;
 +struct RayFace;
  
  #define TABLEINITSIZE 1024
  #define LAMPINITSIZE 256
@@@ -170,9 -168,7 +170,9 @@@ struct Rende
        ListBase parts;
        
        /* octree tables and variables for raytrace */
 -      void *raytree;
 +      struct RayObject *raytree;
 +      struct RayFace *rayfaces;
 +      float maxdist; /* needed for keeping an incorrect behaviour of SUN and HEMI lights (avoid breaking old scenes) */
  
        /* occlusion tree */
        void *occlusiontree;
        ListBase customdata_names;
  
        struct Object *excludeob;
+       ListBase render_volumes_inside;
+       ListBase volumes;
+       ListBase volume_precache_parts;
  
        /* arena for allocating data for use during render, for
                * example dynamic TFaces to go in the VlakRen structure.
@@@ -282,12 -281,6 +285,12 @@@ typedef struct ObjectRen 
        int  actmtface, actmcol, bakemtface;
  
        float obmat[4][4];      /* only used in convertblender.c, for instancing */
 +
 +      /* used on makeraytree */
 +      struct RayObject *raytree;
 +      struct RayFace *rayfaces;
 +      struct ObjectInstanceRen *rayobi;
 +      
  } ObjectRen;
  
  typedef struct ObjectInstanceRen {
  
        float dupliorco[3], dupliuv[2];
        float (*duplitexmat)[4];
+       
+       struct VolumePrecache *volume_precache;
+       
        float *vectors;
        int totvector;
 +      
 +      /* used on makeraytree */
 +      struct RayObject *raytree;
 +
  } ObjectInstanceRen;
  
  /* ------------------------------------------------------------------------- */
@@@ -416,6 -407,46 +421,46 @@@ typedef struct StrandRen 
        float orco[3];
  } StrandRen;
  
 -      struct RayTree *tree;
+ /* ------------------------------------------------------------------------- */
+ typedef struct VolumeOb
+ {
+       struct VolumeOb *next, *prev;
+       struct Material *ma;
+       struct ObjectRen *obr;
+ } VolumeOb;
+ typedef struct MatInside {
+       struct MatInside *next, *prev;
+       struct Material *ma;
+       struct ObjectInstanceRen *obi;
+ } MatInside;
+ typedef struct VolPrecachePart
+ {
+       struct VolPrecachePart *next, *prev;
++      struct RayObject *tree;
+       struct ShadeInput *shi;
+       struct ObjectInstanceRen *obi;
+       int num;
+       int minx, maxx;
+       int miny, maxy;
+       int minz, maxz;
+       int res[3];
+       float bbmin[3];
+       float voxel[3];
+       int working, done;
+ } VolPrecachePart;
+ typedef struct VolumePrecache
+ {
+       int res[3];
+       float *data_r;
+       float *data_g;
+       float *data_b;
+ } VolumePrecache;
+ /* ------------------------------------------------------------------------- */
  
  struct LampRen;
  struct MTex;
@@@ -505,7 -536,8 +550,7 @@@ typedef struct LampRen 
        short YF_glowtype;
        
        /* ray optim */
 -      VlakRen *vlr_last[BLENDER_MAX_THREADS];
 -      ObjectInstanceRen *obi_last[BLENDER_MAX_THREADS];
 +      struct RayObject *last_hit[BLENDER_MAX_THREADS];
        
        struct MTex *mtex[MAX_MTEX];
  
index 4b28529a1472cbd1b23f4448a91ddea2d4be6620,4b28529a1472cbd1b23f4448a91ddea2d4be6620..250fbc000cbe74a2dde543ae7183e12e99831e66
@@@ -95,6 -95,6 +95,7 @@@ int get_sample_layers(struct RenderPar
  
  extern void freeraytree(Render *re);
  extern void makeraytree(Render *re);
++RayObject* makeraytree_object(Render *re, ObjectInstanceRen *obi);
  
  extern void ray_shadow(ShadeInput *, LampRen *, float *);
  extern void ray_trace(ShadeInput *, ShadeResult *);
index 05308361fdb631d292b214ef6621fa374656763f,0000000000000000000000000000000000000000..4bd8a12aa01d0b0a15bc2d0d82383fe661b62f39
mode 100644,000000..100644
--- /dev/null
@@@ -1,457 -1,0 +1,471 @@@
 +/**
 + * $Id$
 + *
 + * ***** BEGIN GPL LICENSE BLOCK *****
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version. 
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software Foundation,
 + * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 + *
 + * The Original Code is Copyright (C) 2009 Blender Foundation.
 + * All rights reserved.
 + *
 + * The Original Code is: all of this file.
 + *
 + * Contributor(s): André Pinto.
 + *
 + * ***** END GPL LICENSE BLOCK *****
 + */
 +#include <assert.h>
 +
 +#include "BKE_utildefines.h"
 +#include "BLI_arithb.h"
 +
 +#include "RE_raytrace.h"
 +#include "render_types.h"
 +#include "rayobject.h"
 +#include "raycounter.h"
 +
 +/*
 + * Determines the distance that the ray must travel to hit the bounding volume of the given node
 + * Based on Tactical Optimization of Ray/Box Intersection, by Graham Fyffe
 + *  [http://tog.acm.org/resources/RTNews/html/rtnv21n1.html#art9]
 + */
 +int RE_rayobject_bb_intersect_test(const Isect *isec, const float *_bb)
 +{
 +      const float *bb = _bb;
 +      
 +      float t1x = (bb[isec->bv_index[0]] - isec->start[0]) * isec->idot_axis[0];
 +      float t2x = (bb[isec->bv_index[1]] - isec->start[0]) * isec->idot_axis[0];
 +      float t1y = (bb[isec->bv_index[2]] - isec->start[1]) * isec->idot_axis[1];
 +      float t2y = (bb[isec->bv_index[3]] - isec->start[1]) * isec->idot_axis[1];
 +      float t1z = (bb[isec->bv_index[4]] - isec->start[2]) * isec->idot_axis[2];
 +      float t2z = (bb[isec->bv_index[5]] - isec->start[2]) * isec->idot_axis[2];
 +
 +      RE_RC_COUNT(isec->raycounter->bb.test);
 +      
 +      if(t1x > t2y || t2x < t1y || t1x > t2z || t2x < t1z || t1y > t2z || t2y < t1z) return 0;
 +      if(t2x < 0.0 || t2y < 0.0 || t2z < 0.0) return 0;
 +      if(t1x > isec->labda || t1y > isec->labda || t1z > isec->labda) return 0;
 +      RE_RC_COUNT(isec->raycounter->bb.hit);  
 +
 +      return 1;
 +}
 +
 +
 +/* only for self-intersecting test with current render face (where ray left) */
 +static int intersection2(VlakRen *face, float r0, float r1, float r2, float rx1, float ry1, float rz1)
 +{
 +      float co1[3], co2[3], co3[3], co4[3];
 +      float x0,x1,x2,t00,t01,t02,t10,t11,t12,t20,t21,t22;
 +      float m0, m1, m2, divdet, det, det1;
 +      float u1, v, u2;
 +
 +      VECCOPY(co1, face->v1->co);
 +      VECCOPY(co2, face->v2->co);
 +      if(face->v4)
 +      {
 +              VECCOPY(co3, face->v4->co);
 +              VECCOPY(co4, face->v3->co);
 +      }
 +      else
 +      {
 +              VECCOPY(co3, face->v3->co);
 +      }
 +
 +      t00= co3[0]-co1[0];
 +      t01= co3[1]-co1[1];
 +      t02= co3[2]-co1[2];
 +      t10= co3[0]-co2[0];
 +      t11= co3[1]-co2[1];
 +      t12= co3[2]-co2[2];
 +      
 +      x0= t11*r2-t12*r1;
 +      x1= t12*r0-t10*r2;
 +      x2= t10*r1-t11*r0;
 +
 +      divdet= t00*x0+t01*x1+t02*x2;
 +
 +      m0= rx1-co3[0];
 +      m1= ry1-co3[1];
 +      m2= rz1-co3[2];
 +      det1= m0*x0+m1*x1+m2*x2;
 +      
 +      if(divdet!=0.0f) {
 +              u1= det1/divdet;
 +
 +              if(u1<ISECT_EPSILON) {
 +                      det= t00*(m1*r2-m2*r1);
 +                      det+= t01*(m2*r0-m0*r2);
 +                      det+= t02*(m0*r1-m1*r0);
 +                      v= det/divdet;
 +
 +                      if(v<ISECT_EPSILON && (u1 + v) > -(1.0f+ISECT_EPSILON)) {
 +                              return 1;
 +                      }
 +              }
 +      }
 +
 +      if(face->v4) {
 +
 +              t20= co3[0]-co4[0];
 +              t21= co3[1]-co4[1];
 +              t22= co3[2]-co4[2];
 +
 +              divdet= t20*x0+t21*x1+t22*x2;
 +              if(divdet!=0.0f) {
 +                      u2= det1/divdet;
 +              
 +                      if(u2<ISECT_EPSILON) {
 +                              det= t20*(m1*r2-m2*r1);
 +                              det+= t21*(m2*r0-m0*r2);
 +                              det+= t22*(m0*r1-m1*r0);
 +                              v= det/divdet;
 +      
 +                              if(v<ISECT_EPSILON && (u2 + v) >= -(1.0f+ISECT_EPSILON)) {
 +                                      return 2;
 +                              }
 +                      }
 +              }
 +      }
 +      return 0;
 +}
 +
 +#include "DNA_material_types.h"
 +static int vlr_check_intersect(Isect *is, ObjectInstanceRen *obi, VlakRen *vlr)
 +{
 +      /* for baking selected to active non-traceable materials might still
 +       * be in the raytree */
 +      if(!(vlr->mat->mode & MA_TRACEBLE))
 +              return 0;
 +
 +      /* I know... cpu cycle waste, might do smarter once */
 +      if(is->mode==RE_RAY_MIRROR)
 +              return !(vlr->mat->mode & MA_ONLYCAST);
 +      else
 +              return (is->lay & obi->lay);
 +}
 +
++static int vlr_check_intersect_solid(Isect *is, ObjectInstanceRen* obi, VlakRen *vlr)
++{
++      /* solid material types only */
++      if (vlr->mat->material_type == MA_TYPE_SURFACE)
++              return 1;
++      else
++              return 0;
++}
++
 +/* ray - triangle or quad intersection */
 +/* this function shall only modify Isect if it detects an hit */
 +static int intersect_rayface(RayFace *face, Isect *is)
 +{
 +      float co1[3],co2[3],co3[3],co4[3];
 +      float x0,x1,x2,t00,t01,t02,t10,t11,t12,t20,t21,t22,r0,r1,r2;
 +      float m0, m1, m2, divdet, det1;
 +      float labda, u, v;
 +      short ok=0;
 +      
 +      if(is->orig.ob == face->ob && is->orig.face == face->face)
 +              return 0;
 +              
 +      if(is->skip & RE_SKIP_VLR_RENDER_CHECK)
 +      {
 +              if(vlr_check_intersect(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face ) == 0)
 +                      return 0;
 +      }
++      if(is->skip & RE_SKIP_VLR_NON_SOLID_MATERIAL)
++      {
++              if(vlr_check_intersect_solid(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face) == 0)
++                      return 0;
++      }
 +
 +      RE_RC_COUNT(is->raycounter->faces.test);
 +
 +      //Load coords
 +      VECCOPY(co1, face->v1);
 +      VECCOPY(co2, face->v2);
 +      if(RE_rayface_isQuad(face))
 +      {
 +              VECCOPY(co3, face->v4);
 +              VECCOPY(co4, face->v3);
 +      }
 +      else
 +      {
 +              VECCOPY(co3, face->v3);
 +      }
 +
 +      t00= co3[0]-co1[0];
 +      t01= co3[1]-co1[1];
 +      t02= co3[2]-co1[2];
 +      t10= co3[0]-co2[0];
 +      t11= co3[1]-co2[1];
 +      t12= co3[2]-co2[2];
 +      
 +      r0= is->vec[0];
 +      r1= is->vec[1];
 +      r2= is->vec[2];
 +      
 +      x0= t12*r1-t11*r2;
 +      x1= t10*r2-t12*r0;
 +      x2= t11*r0-t10*r1;
 +
 +      divdet= t00*x0+t01*x1+t02*x2;
 +
 +      m0= is->start[0]-co3[0];
 +      m1= is->start[1]-co3[1];
 +      m2= is->start[2]-co3[2];
 +      det1= m0*x0+m1*x1+m2*x2;
 +      
 +      if(divdet!=0.0f) {
 +
 +              divdet= 1.0f/divdet;
 +              u= det1*divdet;
 +              if(u<ISECT_EPSILON && u>-(1.0f+ISECT_EPSILON)) {
 +                      float cros0, cros1, cros2;
 +                      
 +                      cros0= m1*t02-m2*t01;
 +                      cros1= m2*t00-m0*t02;
 +                      cros2= m0*t01-m1*t00;
 +                      v= divdet*(cros0*r0 + cros1*r1 + cros2*r2);
 +
 +                      if(v<ISECT_EPSILON && (u + v) > -(1.0f+ISECT_EPSILON)) {
 +                              labda= divdet*(cros0*t10 + cros1*t11 + cros2*t12);
 +
 +                              if(labda>-ISECT_EPSILON && labda<is->labda) {
 +                                      ok= 1;
 +                              }
 +                      }
 +              }
 +      }
 +
 +      if(ok==0 && RE_rayface_isQuad(face)) {
 +
 +              t20= co3[0]-co4[0];
 +              t21= co3[1]-co4[1];
 +              t22= co3[2]-co4[2];
 +
 +              divdet= t20*x0+t21*x1+t22*x2;
 +              if(divdet!=0.0f) {
 +                      divdet= 1.0f/divdet;
 +                      u = det1*divdet;
 +                      
 +                      if(u<ISECT_EPSILON && u>-(1.0f+ISECT_EPSILON)) {
 +                              float cros0, cros1, cros2;
 +                              cros0= m1*t22-m2*t21;
 +                              cros1= m2*t20-m0*t22;
 +                              cros2= m0*t21-m1*t20;
 +                              v= divdet*(cros0*r0 + cros1*r1 + cros2*r2);
 +      
 +                              if(v<ISECT_EPSILON && (u + v) >-(1.0f+ISECT_EPSILON)) {
 +                                      labda= divdet*(cros0*t10 + cros1*t11 + cros2*t12);
 +                                      
 +                                      if(labda>-ISECT_EPSILON && labda<is->labda) {
 +                                              ok= 2;
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +
 +      if(ok) {
 +      
 +              /* when a shadow ray leaves a face, it can be little outside the edges of it, causing
 +              intersection to be detected in its neighbour face */
 +              if(is->skip & RE_SKIP_VLR_NEIGHBOUR)
 +              {
 +                      if(labda < 0.1f && is->orig.ob == face->ob)
 +                      {
 +                              VlakRen * a = is->orig.face;
 +                              VlakRen * b = face->face;
 +
 +                              /* so there's a shared edge or vertex, let's intersect ray with face
 +                              itself, if that's true we can safely return 1, otherwise we assume
 +                              the intersection is invalid, 0 */
 +                              if(a->v1==b->v1 || a->v2==b->v1 || a->v3==b->v1 || a->v4==b->v1
 +                              || a->v1==b->v2 || a->v2==b->v2 || a->v3==b->v2 || a->v4==b->v2
 +                              || a->v1==b->v3 || a->v2==b->v3 || a->v3==b->v3 || a->v4==b->v3
 +                              || (b->v4 && (a->v1==b->v4 || a->v2==b->v4 || a->v3==b->v4 || a->v4==b->v4)))
 +                              if(!intersection2((VlakRen*)a, -r0, -r1, -r2, is->start[0], is->start[1], is->start[2]))
 +                              {
 +                                      return 0;
 +                              }
 +                      }
 +              }
 +
 +              RE_RC_COUNT(is->raycounter->faces.hit);
 +
 +              is->isect= ok;  // wich half of the quad
 +              is->labda= labda;
 +              is->u= u; is->v= v;
 +
 +              is->hit.ob   = face->ob;
 +              is->hit.face = face->face;
 +#ifdef RT_USE_LAST_HIT
 +              is->last_hit = (RayObject*) RE_rayobject_unalignRayFace(face);
 +#endif
 +              return 1;
 +      }
 +
 +      return 0;
 +}
 +
 +void RE_rayface_from_vlak(RayFace *face, ObjectInstanceRen *obi, VlakRen *vlr)
 +{
 +      VECCOPY(face->v1, vlr->v1->co);
 +      VECCOPY(face->v2, vlr->v2->co);
 +      VECCOPY(face->v3, vlr->v3->co);
 +      if(vlr->v4)
 +      {
 +              VECCOPY(face->v4, vlr->v4->co);
 +              face->quad = 1;
 +      }
 +      else
 +      {
 +              face->quad = 0;
 +      }
 +
 +      face->ob   = obi;
 +      face->face = vlr;
 +}
 +
 +
 +int RE_rayobject_raycast(RayObject *r, Isect *isec)
 +{
 +      int i;
 +      RE_RC_COUNT(isec->raycounter->raycast.test);
 +
 +      /* Setup vars used on raycast */
 +      isec->labda *= Normalize(isec->vec);
 +      isec->dist = VecLength(isec->vec);
 +      
 +      for(i=0; i<3; i++)
 +      {
 +              isec->idot_axis[i]              = 1.0f / isec->vec[i];
 +              
 +              isec->bv_index[2*i]             = isec->idot_axis[i] < 0.0 ? 1 : 0;
 +              isec->bv_index[2*i+1]   = 1 - isec->bv_index[2*i];
 +              
 +              isec->bv_index[2*i]             = i+3*isec->bv_index[2*i];
 +              isec->bv_index[2*i+1]   = i+3*isec->bv_index[2*i+1];
 +      }
 +
 +#ifdef RT_USE_LAST_HIT        
 +      /* Last hit heuristic */
 +      if(isec->mode==RE_RAY_SHADOW && isec->last_hit)
 +      {
 +              RE_RC_COUNT(isec->raycounter->rayshadow_last_hit.test);
 +              
 +              if(RE_rayobject_intersect(isec->last_hit, isec))
 +              {
 +                      RE_RC_COUNT(isec->raycounter->raycast.hit);
 +                      RE_RC_COUNT(isec->raycounter->rayshadow_last_hit.hit);
 +                      return 1;
 +              }
 +      }
 +#endif
 +
 +#ifdef RT_USE_HINT
 +      isec->hit_hint = 0;
 +#endif
 +
 +      if(RE_rayobject_intersect(r, isec))
 +      {
 +              RE_RC_COUNT(isec->raycounter->raycast.hit);
 +
 +#ifdef RT_USE_HINT
 +              isec->hint = isec->hit_hint;
 +#endif
 +              return 1;
 +      }
 +      return 0;
 +}
 +
 +int RE_rayobject_intersect(RayObject *r, Isect *i)
 +{
 +      if(RE_rayobject_isRayFace(r))
 +      {
 +              return intersect_rayface( (RayFace*) RE_rayobject_align(r), i);
 +      }
 +      else if(RE_rayobject_isRayAPI(r))
 +      {
 +              r = RE_rayobject_align( r );
 +              return r->api->raycast( r, i );
 +      }
 +      else assert(0);
 +}
 +
 +void RE_rayobject_add(RayObject *r, RayObject *o)
 +{
 +      r = RE_rayobject_align( r );
 +      return r->api->add( r, o );
 +}
 +
 +void RE_rayobject_done(RayObject *r)
 +{
 +      r = RE_rayobject_align( r );
 +      r->api->done( r );
 +}
 +
 +void RE_rayobject_free(RayObject *r)
 +{
 +      r = RE_rayobject_align( r );
 +      r->api->free( r );
 +}
 +
 +void RE_rayobject_merge_bb(RayObject *r, float *min, float *max)
 +{
 +      if(RE_rayobject_isRayFace(r))
 +      {
 +              RayFace *face = (RayFace*) RE_rayobject_align(r);
 +              
 +              DO_MINMAX( face->v1, min, max );
 +              DO_MINMAX( face->v2, min, max );
 +              DO_MINMAX( face->v3, min, max );
 +              if(RE_rayface_isQuad(face)) DO_MINMAX( face->v4, min, max );
 +      }
 +      else if(RE_rayobject_isRayAPI(r))
 +      {
 +              r = RE_rayobject_align( r );
 +              r->api->bb( r, min, max );
 +      }
 +      else assert(0);
 +}
 +
 +float RE_rayobject_cost(RayObject *r)
 +{
 +      if(RE_rayobject_isRayFace(r))
 +      {
 +              return 1.0;
 +      }
 +      else if(RE_rayobject_isRayAPI(r))
 +      {
 +              r = RE_rayobject_align( r );
 +              return r->api->cost( r );
 +      }
 +      else assert(0);
 +}
 +
 +void RE_rayobject_hint_bb(RayObject *r, RayHint *hint, float *min, float *max)
 +{
 +      if(RE_rayobject_isRayFace(r))
 +      {
 +              return;
 +      }
 +      else if(RE_rayobject_isRayAPI(r))
 +      {
 +              r = RE_rayobject_align( r );
 +              return r->api->hint_bb( r, hint, min, max );
 +      }
 +      else assert(0);
 +}
 +
index 7e2cb4c6992e3d10b049573ec00f06485a998b41,d2599f6050c18caac6576823c84cbb5751a00124..8cb11d11762166a22c919a84f35a472918f67437
@@@ -29,7 -29,6 +29,7 @@@
  #include <string.h>
  #include <stdlib.h>
  #include <float.h>
 +#include <assert.h>
  
  #include "MEM_guardedalloc.h"
  
  #include "pixelshading.h"
  #include "shading.h"
  #include "texture.h"
+ #include "volumetric.h"
  
  #include "RE_raytrace.h"
 +#include "rayobject.h"
 +#include "raycounter.h"
  
  #define RAY_TRA               1
  #define RAY_TRAFLIP   2
  /* only to be used here in this file, it's for speed */
  extern struct Render R;
  /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 -
 -static void vlr_face_coords(RayFace *face, float **v1, float **v2, float **v3, float **v4)
 +RayObject *  RE_rayobject_create(int type, int size)
  {
 -      VlakRen *vlr= (VlakRen*)face;
 +      if(type == R_RAYSTRUCTURE_AUTO)
 +      {
 +              //TODO
 +//            if(detect_simd())
 +//                    type = R_RAYSTRUCTURE_SIMD_SVBVH;
 +//            else
 +//                    type = R_RAYSTRUCTURE_VBVH;
  
 -      *v1 = (vlr->v1)? vlr->v1->co: NULL;
 -      *v2 = (vlr->v2)? vlr->v2->co: NULL;
 -      *v3 = (vlr->v3)? vlr->v3->co: NULL;
 -      *v4 = (vlr->v4)? vlr->v4->co: NULL;
 +                      type = R_RAYSTRUCTURE_SIMD_QBVH;
 +      }
 +      
 +      
 +      if(type == R_RAYSTRUCTURE_OCTREE)
 +      {
 +              //TODO dynamic ocres
 +              return RE_rayobject_octree_create(R.r.ocres, size);
 +      }
 +      if(type == R_RAYSTRUCTURE_BLIBVH)
 +      {
 +              return RE_rayobject_blibvh_create(size);
 +      }
 +      if(type == R_RAYSTRUCTURE_VBVH)
 +      {
 +              return RE_rayobject_vbvh_create(size);
 +      }
 +      if(type == R_RAYSTRUCTURE_SIMD_SVBVH)
 +      {
 +              return RE_rayobject_svbvh_create(size);
 +      }
 +      if(type == R_RAYSTRUCTURE_SIMD_QBVH)
 +      {
 +              return RE_rayobject_qbvh_create(size);
 +      }
 +      if(type == R_RAYSTRUCTURE_BIH)
 +      {
 +//            return RE_rayobject_bih_create(size);
 +      }
 +      
 +      return NULL;
  }
  
 -static int vlr_check_intersect(Isect *is, int ob, RayFace *face)
 -{
 -      ObjectInstanceRen *obi= RAY_OBJECT_GET((Render*)is->userdata, ob);
 -      VlakRen *vlr = (VlakRen*)face;
 +#ifdef RE_RAYCOUNTER
 +RayCounter re_rc_counter[BLENDER_MAX_THREADS] = {};
 +#endif
  
 -      /* for baking selected to active non-traceable materials might still
 -       * be in the raytree */
 -      if(!(vlr->mat->mode & MA_TRACEBLE))
 -              return 0;
 -      /* I know... cpu cycle waste, might do smarter once */
 -      if(is->mode==RE_RAY_MIRROR)
 -              return !(vlr->mat->mode & MA_ONLYCAST);
 -      else
 -              return (is->lay & obi->lay);
 +void freeraytree(Render *re)
 +{
 +      ObjectInstanceRen *obi;
 +      
 +      if(re->raytree)
 +      {
 +              RE_rayobject_free(re->raytree);
 +              re->raytree = NULL;
 +      }
 +      if(re->rayfaces)
 +      {
 +              MEM_freeN(re->rayfaces);
 +              re->rayfaces = NULL;
 +      }
 +
 +      for(obi=re->instancetable.first; obi; obi=obi->next)
 +      {
 +              ObjectRen *obr = obi->obr;
 +              if(obr->raytree)
 +              {
 +                      RE_rayobject_free(obr->raytree);
 +                      obr->raytree = NULL;
 +              }
 +              if(obr->rayfaces)
 +              {
 +                      MEM_freeN(obr->rayfaces);
 +                      obr->rayfaces = NULL;
 +              }
 +              if(obi->raytree)
 +              {
 +                      RE_rayobject_free(obi->raytree);
 +                      obi->raytree = NULL;
 +              }
 +      }
 +      
 +#ifdef RE_RAYCOUNTER
 +      {
 +              RayCounter sum = {};
 +              int i;
 +              for(i=0; i<BLENDER_MAX_THREADS; i++)
 +                      RE_RC_MERGE(&sum, re_rc_counter+i);
 +              RE_RC_INFO(&sum);
 +      }
 +#endif
  }
  
 -static int vlr_check_intersect_solid(Isect *is, int ob, RayFace *face)
 +static int is_raytraceable_vlr(Render *re, VlakRen *vlr)
  {
 -      VlakRen *vlr = (VlakRen*)face;
 -
 -      /* solid material types only */
 -      if (vlr->mat->material_type == MA_TYPE_SURFACE)
 +      if((re->flag & R_BAKE_TRACE) || (vlr->mat->mode & MA_TRACEBLE))
 +      if(vlr->mat->material_type != MA_TYPE_WIRE)
                return 1;
 -      else
 -              return 0;
 +      return 0;
  }
  
 -static float *vlr_get_transform(void *userdata, int i)
 +static int is_raytraceable(Render *re, ObjectInstanceRen *obi)
  {
 -      ObjectInstanceRen *obi= RAY_OBJECT_GET((Render*)userdata, i);
 +      int v;
 +      ObjectRen *obr = obi->obr;
  
 -      return (obi->flag & R_TRANSFORMED)? (float*)obi->mat: NULL;
 -}
 +      if(re->excludeob && obr->ob == re->excludeob)
 +              return 0;
  
 -void freeraytree(Render *re)
 -{
 -      if(re->raytree) {
 -              RE_ray_tree_free(re->raytree);
 -              re->raytree= NULL;
 +      for(v=0;v<obr->totvlak;v++)
 +      {
 +              VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
 +              if(is_raytraceable_vlr(re, vlr))
 +                      return 1;
        }
 +      return 0;
  }
  
 -void makeraytree(Render *re)
 -{
 -      ObjectInstanceRen *obi;
 -      ObjectRen *obr;
 -      VlakRen *vlr= NULL;
 -      float min[3], max[3], co1[3], co2[3], co3[3], co4[3];
 -      double lasttime= PIL_check_seconds_timer();
 -      int v, totv = 0, totface = 0;
 -
 -      INIT_MINMAX(min, max);
 -
 -      /* first min max raytree space */
 -      for(obi=re->instancetable.first; obi; obi=obi->next) {
 -              obr= obi->obr;
 -
 -              if(re->excludeob && obr->ob == re->excludeob)
 -                      continue;
 -
 -              for(v=0;v<obr->totvlak;v++) {
 -                      if((v & 255)==0) vlr= obr->vlaknodes[v>>8].vlak;
 -                      else vlr++;
 -                      /* baking selected to active needs non-traceable too */
 -                      if((re->flag & R_BAKE_TRACE) || (vlr->mat->mode & MA_TRACEBLE)) {       
 -                              if(vlr->mat->material_type != MA_TYPE_WIRE) {
 -                                      VECCOPY(co1, vlr->v1->co);
 -                                      VECCOPY(co2, vlr->v2->co);
 -                                      VECCOPY(co3, vlr->v3->co);
 -
 -                                      if(obi->flag & R_TRANSFORMED) {
 -                                              Mat4MulVecfl(obi->mat, co1);
 -                                              Mat4MulVecfl(obi->mat, co2);
 -                                              Mat4MulVecfl(obi->mat, co3);
 -                                      }
 -
 -                                      DO_MINMAX(co1, min, max);
 -                                      DO_MINMAX(co2, min, max);
 -                                      DO_MINMAX(co3, min, max);
  
 -                                      if(vlr->v4) {
 -                                              VECCOPY(co4, vlr->v4->co);
 -                                              if(obi->flag & R_TRANSFORMED)
 -                                                      Mat4MulVecfl(obi->mat, co4);
 -                                              DO_MINMAX(co4, min, max);
 -                                      }
 +RayObject* makeraytree_object(Render *re, ObjectInstanceRen *obi)
 +{
 +      //TODO
 +      // out-of-memory safeproof
 +      // break render
 +      // update render stats
 +      ObjectRen *obr = obi->obr;
 +      
 +      if(obr->raytree == NULL)
 +      {
 +              RayObject *raytree;
 +              RayFace *face;
 +              int v;
 +              
 +              //Count faces
 +              int faces = 0;
 +              for(v=0;v<obr->totvlak;v++)
 +              {
 +                      VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
 +                      if(is_raytraceable_vlr(re, vlr))
 +                              faces++;
 +              }
 +              assert( faces > 0 );
  
 -                                      totface++;
 -                              }
 +              //Create Ray cast accelaration structure                
 +              raytree = obr->raytree = RE_rayobject_create( re->r.raytrace_tree_type, faces );
 +              face = obr->rayfaces = (RayFace*)MEM_callocN(faces*sizeof(RayFace), "ObjectRen faces");
 +              obr->rayobi = obi;
 +              
 +              for(v=0;v<obr->totvlak;v++)
 +              {
 +                      VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
 +                      if(is_raytraceable_vlr(re, vlr))
 +                      {
 +                              RE_rayface_from_vlak( face, obi, vlr );                         
 +                              RE_rayobject_add( raytree, RE_rayobject_unalignRayFace(face) );
 +                              face++;
                        }
                }
 +              RE_rayobject_done( raytree );
        }
  
 -      re->raytree= RE_ray_tree_create(re->r.ocres, totface, min, max,
 -              vlr_face_coords, vlr_check_intersect, vlr_get_transform, re);
  
 -      if(min[0] > max[0]) { /* empty raytree */
 -              RE_ray_tree_done(re->raytree);
 -              return; 
 +      if(obi->flag & R_TRANSFORMED)
 +      {
 +              obi->raytree = RE_rayobject_instance_create( obr->raytree, obi->mat, obi, obi->obr->rayobi );
        }
 +      
 +      if(obi->raytree) return obi->raytree;
 +      return obi->obr->raytree;
 +}
  
 -      for(obi=re->instancetable.first; obi; obi=obi->next) {
 -              obr= obi->obr;
 +static int has_special_rayobject(Render *re, ObjectInstanceRen *obi)
 +{
 +      if( (obi->flag & R_TRANSFORMED) )
 +      {
 +              ObjectRen *obr = obi->obr;
 +              int v, faces = 0;
 +              
 +              for(v=0;v<obr->totvlak;v++)
 +              {
 +                      VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
 +                      if(is_raytraceable_vlr(re, vlr))
 +                      {
 +                              faces++;
 +                              if(faces > 4)
 +                                      return 1;
 +                      }
 +              }
 +      }
 +      return 0;
 +}
 +/*
 + * create a single raytrace structure with all faces
 + */
 +static void makeraytree_single(Render *re)
 +{
 +      ObjectInstanceRen *obi;
 +      RayObject *raytree;
 +      RayFace *face;
 +      int faces = 0, obs = 0;
  
 -              if(re->excludeob && obr->ob == re->excludeob)
 -                      continue;
 +      for(obi=re->instancetable.first; obi; obi=obi->next)
 +      if(is_raytraceable(re, obi))
 +      {
 +              int v;
 +              ObjectRen *obr = obi->obr;
 +              obs++;
 +              
 +              if(has_special_rayobject(re, obi))
 +              {
 +                      faces++;
 +              }
 +              else
 +              {
 +                      for(v=0;v<obr->totvlak;v++)
 +                      {
 +                              VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
 +                              if(is_raytraceable_vlr(re, vlr))
 +                                      faces++;
 +                      }
 +              }
 +      }
 +      
 +      //Create raytree
 +      raytree = re->raytree = RE_rayobject_create( re->r.raytrace_tree_type, faces );
  
 -              for(v=0; v<obr->totvlak; v++, totv++) {
 -                      if((v & 255)==0) {
 -                              double time= PIL_check_seconds_timer();
 +      face    = re->rayfaces  = (RayFace*)MEM_callocN(faces*sizeof(RayFace), "Render ray faces");
 +      
 +      for(obi=re->instancetable.first; obi; obi=obi->next)
 +      if(is_raytraceable(re, obi))
 +      {
 +              if(has_special_rayobject(re, obi))
 +              {
 +                      RayObject *obj = makeraytree_object(re, obi);
 +                      RE_rayobject_add( re->raytree, obj );
 +              }
 +              else
 +              {
 +                      int v;
 +                      ObjectRen *obr = obi->obr;
 +
 +                      for(v=0;v<obr->totvlak;v++)
 +                      {
 +                              VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
 +                              if(is_raytraceable_vlr(re, vlr))
 +                              {
 +                                      RE_rayface_from_vlak(face, obi, vlr);
 +                                      if((obi->flag & R_TRANSFORMED))
 +                                      {
 +                                              Mat4MulVecfl(obi->mat, face->v1);
 +                                              Mat4MulVecfl(obi->mat, face->v2);
 +                                              Mat4MulVecfl(obi->mat, face->v3);
 +                                              if(RE_rayface_isQuad(face))
 +                                                      Mat4MulVecfl(obi->mat, face->v4);
 +                                      }
  
 -                              vlr= obr->vlaknodes[v>>8].vlak;
 -                              if(re->test_break(re->tbh))
 -                                      break;
 -                              if(time-lasttime>1.0f) {
 -                                      char str[32];
 -                                      sprintf(str, "Filling Octree: %d", totv);
 -                                      re->i.infostr= str;
 -                                      re->stats_draw(re->sdh, &re->i);
 -                                      re->i.infostr= NULL;
 -                                      lasttime= time;
 +                                      RE_rayobject_add( raytree, RE_rayobject_unalignRayFace(face) );
 +                                      face++;
                                }
                        }
 -                      else vlr++;
 -                      
 -                      if((re->flag & R_BAKE_TRACE) || (vlr->mat->mode & MA_TRACEBLE))
 -                              if(vlr->mat->material_type != MA_TYPE_WIRE)
 -                                      RE_ray_tree_add_face(re->raytree, RAY_OBJECT_SET(re, obi), vlr);
                }
        }
 +      RE_rayobject_done( raytree );   
 +}
  
 -      RE_ray_tree_done(re->raytree);
 +void makeraytree(Render *re)
 +{
 +      float min[3], max[3], sub[3];
 +      int i;
        
 -      re->i.infostr= NULL;
 +      re->i.infostr= "Make raytree";
        re->stats_draw(re->sdh, &re->i);
 +
 +      BENCH(makeraytree_single(re), tree_build);
 +              
 +      //Calculate raytree max_size
 +      //This is ONLY needed to kept a bogus behaviour of SUN and HEMI lights
 +      RE_rayobject_merge_bb( re->raytree, min, max );
 +      for(i=0; i<3; i++)
 +      {
 +              min[i] += 0.01f;
 +              max[i] += 0.01f;
 +              sub[i] = max[i]-min[i];
 +      }
 +      re->maxdist = sqrt( sub[0]*sub[0] + sub[1]*sub[1] + sub[2]*sub[2] );
 +
 +      re->i.infostr= "Raytree finished";
  }
  
- 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);
 +      ObjectInstanceRen *obi= (ObjectInstanceRen*)is->hit.ob;
 +      VlakRen *vlr= (VlakRen*)is->hit.face;
        int osatex= 0;
        
        /* set up view vector */
                shade_input_flip_normals(shi);
  
        shade_input_set_shade_texco(shi);
-       
-       if(is->mode==RE_RAY_SHADOW_TRA) {
+       if (shi->mat->material_type == MA_TYPE_VOLUME) {
+               if(ELEM(is->mode, RE_RAY_SHADOW, RE_RAY_SHADOW_TRA)) {
+                       shade_volume_shadow(shi, shr, is);
+               } else {
+                       shade_volume_outside(shi, shr);
+               }
+       }
+       else if(is->mode==RE_RAY_SHADOW_TRA) {
                /* temp hack to prevent recursion */
                if(shi->nodes==0 && shi->mat->nodetree && shi->mat->use_nodes) {
                        ntreeShaderExecTree(shi->mat->nodetree, shi, shr);
                        ntreeShaderExecTree(shi->mat->nodetree, shi, shr);
                        shi->mat= vlr->mat;             /* shi->mat is being set in nodetree */
                }
-               else
-                       shade_material_loop(shi, shr);
-               
+               else {
+                       int tempdepth;
+                       /* XXX dodgy business here, set ray depth to -1
+                        * to ignore raytrace in shade_material_loop()
+                        * this could really use a refactor --Matt */
+                       if (shi->volume_depth == 0) {
+                               tempdepth = shi->depth;
+                               shi->depth = -1;
+                               shade_material_loop(shi, shr);
+                               shi->depth = tempdepth;
+                       } else {
+                               shade_material_loop(shi, shr);
+                       }
+               }
                /* raytrace likes to separate the spec color */
                VECSUB(shr->diff, shr->combined, shr->spec);
        }       
@@@ -577,7 -450,7 +594,7 @@@ static void traceray(ShadeInput *origsh
        ShadeResult shr;
        Isect isec;
        float f, f1, fr, fg, fb;
 -      float ref[3], maxsize=RE_ray_tree_max_size(R.raytree);
 +      float ref[3];
        float dist_mir = origshi->mat->dist_mir;
  
        /* Warning, This is not that nice, and possibly a bit slow for every ray,
        /* end warning! - Campbell */
        
        VECCOPY(isec.start, start);
 -      if (dist_mir > 0.0) {
 -              isec.end[0]= start[0]+dist_mir*vec[0];
 -              isec.end[1]= start[1]+dist_mir*vec[1];
 -              isec.end[2]= start[2]+dist_mir*vec[2];
 -      } else {
 -              isec.end[0]= start[0]+maxsize*vec[0];
 -              isec.end[1]= start[1]+maxsize*vec[1];
 -              isec.end[2]= start[2]+maxsize*vec[2];
 -      }
 +      VECCOPY(isec.vec, vec );
 +      isec.labda = dist_mir > 0 ? dist_mir : RE_RAYTRACE_MAXDIST;
        isec.mode= RE_RAY_MIRROR;
 -      isec.faceorig= (RayFace*)vlr;
 -      isec.oborig= RAY_OBJECT_SET(&R, obi);
 +      isec.skip = RE_SKIP_VLR_NEIGHBOUR | RE_SKIP_VLR_RENDER_CHECK;
 +      isec.hint = 0;
 +
 +      isec.orig.ob   = obi;
 +      isec.orig.face = vlr;
 +      RE_RC_INIT(isec, shi);
  
 -      if(RE_ray_tree_intersect(R.raytree, &isec)) {
 +      if(RE_rayobject_raycast(R.raytree, &isec)) {
                float d= 1.0f;
                
                shi.mask= origshi->mask;
        else {
                ray_fadeout_endcolor(col, origshi, &shi, origshr, &isec, vec);
        }
 +      RE_RC_MERGE(&origshi->raycounter, &shi.raycounter);
  }
  
  /* **************** jitter blocks ********** */
@@@ -1339,6 -1214,7 +1356,6 @@@ void ray_trace(ShadeInput *shi, ShadeRe
        
        do_tra= ((shi->mat->mode & MA_TRANSP) && (shi->mat->mode & MA_RAYTRANSP) && shr->alpha!=1.0f);
        do_mir= ((shi->mat->mode & MA_RAYMIRROR) && shi->ray_mirror!=0.0f);
 -
        
        /* raytrace mirror amd refract like to separate the spec color */
        if(shi->combinedflag & SCE_PASS_SPEC)
                        }
                        
                        if(shi->combinedflag & SCE_PASS_REFLECT) {
+                               /* values in shr->spec can be greater then 1.0.
+                                * In this case the mircol uses a zero blending factor, so ignoring it is ok.
+                                * Fixes bug #18837 - when the spec is higher then 1.0,
+                                * diff can become a negative color - Campbell  */
                                
-                               f= fr*(1.0f-shr->spec[0]);      f1= 1.0f-i;
-                               diff[0]= f*mircol[0] + f1*diff[0];
+                               f1= 1.0f-i;
                                
-                               f= fg*(1.0f-shr->spec[1]);      f1= 1.0f-i;
-                               diff[1]= f*mircol[1] + f1*diff[1];
+                               diff[0] *= f1;
+                               diff[1] *= f1;
+                               diff[2] *= f1;
                                
-                               f= fb*(1.0f-shr->spec[2]);      f1= 1.0f-i;
-                               diff[2]= f*mircol[2] + f1*diff[2];
+                               if(shr->spec[0]<1.0f)   diff[0] += mircol[0] * (fr*(1.0f-shr->spec[0]));
+                               if(shr->spec[1]<1.0f)   diff[1] += mircol[1] * (fg*(1.0f-shr->spec[1]));
+                               if(shr->spec[2]<1.0f)   diff[2] += mircol[2] * (fb*(1.0f-shr->spec[2]));
                        }
                }
        }
@@@ -1433,9 -1314,8 +1455,9 @@@ static void ray_trace_shadow_tra(Isect 
           if it has col[3]>0.0f  continue. so exit when alpha is full */
        ShadeInput shi;
        ShadeResult shr;
 -
 -      if(RE_ray_tree_intersect(R.raytree, is)) {
 +      float initial_labda = is->labda;
 +      
 +      if(RE_rayobject_raycast(R.raytree, is)) {
                float d= 1.0f;
                /* we got a face */
                
                shi.nodes= origshi->nodes;
                
                shade_ray(is, &shi, &shr);
-               if (traflag & RAY_TRA)
-                       d= shade_by_transmission(is, &shi, &shr);
-               
-               /* mix colors based on shadfac (rgb + amount of light factor) */
-               addAlphaLight(is->col, shr.diff, shr.alpha, d*shi.mat->filter);
+               if (shi.mat->material_type == MA_TYPE_SURFACE) {
+                       if (traflag & RAY_TRA)
+                               d= shade_by_transmission(is, &shi, &shr);
+                       
+                       /* mix colors based on shadfac (rgb + amount of light factor) */
+                       addAlphaLight(is->col, shr.diff, shr.alpha, d*shi.mat->filter);
+               } else if (shi.mat->material_type == MA_TYPE_VOLUME) {
+                       addAlphaLight(is->col, shr.combined, shr.alpha, 1.0f);
+               }
                
                if(depth>0 && is->col[3]>0.0f) {
                        
                        /* adapt isect struct */
                        VECCOPY(is->start, shi.co);
 -                      is->oborig= RAY_OBJECT_SET(&R, shi.obi);
 -                      is->faceorig= (RayFace*)shi.vlr;
 +                      is->labda = initial_labda-is->labda;
 +                      is->orig.ob   = shi.obi;
 +                      is->orig.face = shi.vlr;
  
                        ray_trace_shadow_tra(is, origshi, depth-1, traflag | RAY_TRA);
                }
 +              
 +              RE_RC_MERGE(&origshi->raycounter, &shi.raycounter);
        }
  }
  
@@@ -1486,11 -1367,9 +1512,11 @@@ int ray_trace_shadow_rad(ShadeInput *sh
        Isect isec;
        ShadeInput shi;
        ShadeResult shr_t;
 -      float vec[3], accum[3], div= 0.0f, maxsize= RE_ray_tree_max_size(R.raytree);
 +      float vec[3], accum[3], div= 0.0f;
        int a;
        
 +      assert(0);
 +      
        if(only_one) {
                return 0;
        }
        
        accum[0]= accum[1]= accum[2]= 0.0f;
        isec.mode= RE_RAY_MIRROR;
 -      isec.faceorig= (RayFace*)ship->vlr;
 -      isec.oborig= RAY_OBJECT_SET(&R, ship->obi);
 +      isec.orig.ob   = ship->obi;
 +      isec.orig.face = ship->vlr;
 +      isec.hint = 0;
 +
 +      VECCOPY(isec.start, ship->co);
 +      
 +      RE_RC_INIT(isec, shi);
        
        for(a=0; a<8*8; a++) {
                
                        vec[1]-= vec[1];
                        vec[2]-= vec[2];
                }
 -              VECCOPY(isec.start, ship->co);
 -              isec.end[0]= isec.start[0] + maxsize*vec[0];
 -              isec.end[1]= isec.start[1] + maxsize*vec[1];
 -              isec.end[2]= isec.start[2] + maxsize*vec[2];
 -              
 -              if(RE_ray_tree_intersect(R.raytree, &isec)) {
 +
 +              VECCOPY(isec.vec, vec );
 +              isec.labda = RE_RAYTRACE_MAXDIST;
 +
 +              if(RE_rayobject_raycast(R.raytree, &isec)) {
                        float fac;
                        
                        /* Warning, This is not that nice, and possibly a bit slow for every ray,
@@@ -1693,7 -1568,6 +1719,7 @@@ static float *sphere_sampler(int type, 
  static void ray_ao_qmc(ShadeInput *shi, float *shadfac)
  {
        Isect isec;
 +      RayHint point_hint;
        QMCSampler *qsa=NULL;
        float samp3d[3];
        float up[3], side[3], dir[3], nrm[3];
        float dxyview[3], skyadded=0, div;
        int aocolor;
        
 -      isec.faceorig= (RayFace*)shi->vlr;
 -      isec.oborig= RAY_OBJECT_SET(&R, shi->obi);
 -      isec.face_last= NULL;
 -      isec.ob_last= 0;
 +      RE_RC_INIT(isec, *shi);
 +      isec.orig.ob   = shi->obi;
 +      isec.orig.face = shi->vlr;
-       isec.skip = RE_SKIP_VLR_NEIGHBOUR | RE_SKIP_VLR_RENDER_CHECK;
++      isec.skip = RE_SKIP_VLR_NEIGHBOUR | RE_SKIP_VLR_RENDER_CHECK | RE_SKIP_VLR_NON_SOLID_MATERIAL;
 +      isec.hint = 0;
 +
 +      isec.hit.ob   = 0;
 +      isec.hit.face = 0;
 +
 +      isec.last_hit = NULL;
 +      
        isec.mode= (R.wrld.aomode & WO_AODIST)?RE_RAY_SHADOW_TRA:RE_RAY_SHADOW;
        isec.lay= -1;
        
 +      VECCOPY(isec.start, shi->co);           
 +      RE_rayobject_hint_bb( R.raytree, &point_hint, isec.start, isec.start );
 +      isec.hint = &point_hint;
 +
 +      
        shadfac[0]= shadfac[1]= shadfac[2]= 0.0f;
        
        /* prevent sky colors to be added for only shadow (shadow becomes alpha) */
  
        QMC_initPixel(qsa, shi->thread);
        
 +      
        while (samples < max_samples) {
  
                /* sampling, returns quasi-random vector in unit hemisphere */
                
                Normalize(dir);
                        
 -              VECCOPY(isec.start, shi->co);
 -              isec.end[0] = shi->co[0] - maxdist*dir[0];
 -              isec.end[1] = shi->co[1] - maxdist*dir[1];
 -              isec.end[2] = shi->co[2] - maxdist*dir[2];
 +              isec.vec[0] = -dir[0];
 +              isec.vec[1] = -dir[1];
 +              isec.vec[2] = -dir[2];
 +              isec.labda = maxdist;
                
                prev = fac;
                
 -              if(RE_ray_tree_intersect_check(R.raytree, &isec, vlr_check_intersect_solid)) {
 +              if(RE_rayobject_raycast(R.raytree, &isec)) {
                        if (R.wrld.aomode & WO_AODIST) fac+= exp(-isec.labda*R.wrld.aodistfac); 
                        else fac+= 1.0f;
                }
  static void ray_ao_spheresamp(ShadeInput *shi, float *shadfac)
  {
        Isect isec;
 +      RayHint point_hint;
        float *vec, *nrm, div, bias, sh=0.0f;
        float maxdist = R.wrld.aodist;
        float dxyview[3];
        int j= -1, tot, actual=0, skyadded=0, aocolor, resol= R.wrld.aosamp;
        
 -      isec.faceorig= (RayFace*)shi->vlr;
 -      isec.oborig= RAY_OBJECT_SET(&R, shi->obi);
 -      isec.face_last= NULL;
 -      isec.ob_last= 0;
 +      RE_RC_INIT(isec, *shi);
 +      isec.orig.ob   = shi->obi;
 +      isec.orig.face = shi->vlr;
 +      isec.skip = RE_SKIP_VLR_NEIGHBOUR | RE_SKIP_VLR_RENDER_CHECK;
 +      isec.hint = 0;
 +
 +      isec.hit.ob   = 0;
 +      isec.hit.face = 0;
 +      
 +      isec.last_hit = NULL;
 +      
        isec.mode= (R.wrld.aomode & WO_AODIST)?RE_RAY_SHADOW_TRA:RE_RAY_SHADOW;
        isec.lay= -1;
  
 +      VECCOPY(isec.start, shi->co);           
 +      RE_rayobject_hint_bb( R.raytree, &point_hint, isec.start, isec.start );
 +      isec.hint = &point_hint;
  
        shadfac[0]= shadfac[1]= shadfac[2]= 0.0f;
  
                        
                        actual++;
                        
 -                      /* always set start/end, RE_ray_tree_intersect clips it */
 -                      VECCOPY(isec.start, shi->co);
 -                      isec.end[0] = shi->co[0] - maxdist*vec[0];
 -                      isec.end[1] = shi->co[1] - maxdist*vec[1];
 -                      isec.end[2] = shi->co[2] - maxdist*vec[2];
 +                      /* always set start/vec/labda */
 +                      isec.vec[0] = -vec[0];
 +                      isec.vec[1] = -vec[1];
 +                      isec.vec[2] = -vec[2];
 +                      isec.labda = maxdist;
                        
                        /* do the trace */
 -                      if(RE_ray_tree_intersect_check(R.raytree, &isec, vlr_check_intersect_solid)) {
 +                      if(RE_rayobject_raycast(R.raytree, &isec)) {
                                if (R.wrld.aomode & WO_AODIST) sh+= exp(-isec.labda*R.wrld.aodistfac); 
                                else sh+= 1.0f;
                        }
@@@ -2026,15 -1876,12 +2052,15 @@@ static void ray_shadow_qmc(ShadeInput *
        int samples=0;
        float samp3d[3];
  
 -      float fac=0.0f, vec[3];
 +      float fac=0.0f, vec[3], end[3];
        float colsq[4];
        float adapt_thresh = lar->adapt_thresh;
        int min_adapt_samples=4, max_samples = lar->ray_totsamp;
        float *co;
 -      int do_soft=1, full_osa=0;
 +      int do_soft=1, full_osa=0, i;
 +
 +      float min[3], max[3];
 +      RayHint bb_hint;
  
        float jitco[RE_MAX_OSA][3];
        int totjitco;
                qsa = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HAMMERSLEY, max_samples);
        
        QMC_initPixel(qsa, shi->thread);
 +
 +      INIT_MINMAX(min, max);
 +      for(i=0; i<totjitco; i++)
 +      {
 +              DO_MINMAX(jitco[i], min, max);
 +      }
 +      RE_rayobject_hint_bb( R.raytree, &bb_hint, min, max);
        
 +      isec->hint = &bb_hint;
 +      isec->skip = RE_SKIP_VLR_NEIGHBOUR | RE_SKIP_VLR_RENDER_CHECK;
        VECCOPY(vec, lampco);
        
 -      
        while (samples < max_samples) {
 -              isec->faceorig= (RayFace*)shi->vlr;
 -              isec->oborig= RAY_OBJECT_SET(&R, shi->obi);
 +
 +              isec->orig.ob   = shi->obi;
 +              isec->orig.face = shi->vlr;
  
                /* manually jitter the start shading co-ord per sample
                 * based on the pre-generated OSA texture sampling offsets, 
                                /* align samples to lamp vector */
                                Mat3MulVecfl(lar->mat, samp3d);
                        }
 -                      isec->end[0]= vec[0]+samp3d[0];
 -                      isec->end[1]= vec[1]+samp3d[1];
 -                      isec->end[2]= vec[2]+samp3d[2];
 +                      end[0] = vec[0]+samp3d[0];
 +                      end[1] = vec[1]+samp3d[1];
 +                      end[2] = vec[2]+samp3d[2];
                } else {
 -                      VECCOPY(isec->end, vec);
 +                      VECCOPY(end, vec);
                }
  
                if(shi->strand) {
                        float jitbias= 0.5f*(VecLength(shi->dxco) + VecLength(shi->dyco));
                        float v[3];
  
 -                      VECSUB(v, co, isec->end);
 +                      VECSUB(v, co, end);
                        Normalize(v);
  
                        co[0] -= jitbias*v[0];
                }
  
                VECCOPY(isec->start, co);
 +              isec->vec[0] = end[0]-isec->start[0];
 +              isec->vec[1] = end[1]-isec->start[1];
 +              isec->vec[2] = end[2]-isec->start[2];
 +              isec->labda = 1.0f; // * Normalize(isec->vec);
                
                /* trace the ray */
                if(isec->mode==RE_RAY_SHADOW_TRA) {
                        colsq[2] += isec->col[2]*isec->col[2];
                }
                else {
 -                      if( RE_ray_tree_intersect(R.raytree, isec) ) fac+= 1.0f;
 +                      if( RE_rayobject_raycast(R.raytree, isec) ) fac+= 1.0f;
                }
                
                samples++;
@@@ -2199,7 -2033,6 +2225,7 @@@ static void ray_shadow_jitter(ShadeInpu
        float *jitlamp;
        float fac=0.0f, div=0.0f, vec[3];
        int a, j= -1, mask;
 +      RayHint point_hint;
        
        if(isec->mode==RE_RAY_SHADOW_TRA) {
                shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 0.0f;
        if(a==4) mask |= (mask>>4)|(mask>>8);
        else if(a==9) mask |= (mask>>9);
        
 +      VECCOPY(isec->start, shi->co);          
 +      isec->orig.ob   = shi->obi;
 +      isec->orig.face = shi->vlr;
 +      RE_rayobject_hint_bb( R.raytree, &point_hint, isec->start, isec->start );
 +      isec->hint = &point_hint;
 +      
        while(a--) {
                
                if(R.r.mode & R_OSA) {
                        }
                }
                
 -              isec->faceorig= (RayFace*)shi->vlr;
 -              isec->oborig= RAY_OBJECT_SET(&R, shi->obi);
 -              
                vec[0]= jitlamp[0];
                vec[1]= jitlamp[1];
                vec[2]= 0.0f;
                Mat3MulVecfl(lar->mat, vec);
                
 -              /* set start and end, RE_ray_tree_intersect clips it */
 -              VECCOPY(isec->start, shi->co);
 -              isec->end[0]= lampco[0]+vec[0];
 -              isec->end[1]= lampco[1]+vec[1];
 -              isec->end[2]= lampco[2]+vec[2];
 +              /* set start and vec */
 +              isec->vec[0] = vec[0]+lampco[0]-isec->start[0];
 +              isec->vec[1] = vec[1]+lampco[1]-isec->start[1];
 +              isec->vec[2] = vec[2]+lampco[2]-isec->start[2];
 +              isec->labda = 1.0f;
 +              isec->skip = RE_SKIP_VLR_NEIGHBOUR | RE_SKIP_VLR_RENDER_CHECK;
                
                if(isec->mode==RE_RAY_SHADOW_TRA) {
                        /* isec.col is like shadfac, so defines amount of light (0.0 is full shadow) */
                        shadfac[2] += isec->col[2];
                        shadfac[3] += isec->col[3];
                }
 -              else if( RE_ray_tree_intersect(R.raytree, isec) ) fac+= 1.0f;
 +              else if( RE_rayobject_raycast(R.raytree, isec) ) fac+= 1.0f;
                
                div+= 1.0f;
                jitlamp+= 2;
  void ray_shadow(ShadeInput *shi, LampRen *lar, float *shadfac)
  {
        Isect isec;
 -      float lampco[3], maxsize;
 +      float lampco[3];
  
        /* setup isec */
 +      RE_RC_INIT(isec, *shi);
        if(shi->mat->mode & MA_SHADOW_TRA) isec.mode= RE_RAY_SHADOW_TRA;
        else isec.mode= RE_RAY_SHADOW;
 +      isec.hint = 0;
        
        if(lar->mode & (LA_LAYER|LA_LAYER_SHADOW))
                isec.lay= lar->lay;
  
        /* only when not mir tracing, first hit optimm */
        if(shi->depth==0) {
 -              isec.face_last= (RayFace*)lar->vlr_last[shi->thread];
 -              isec.ob_last= RAY_OBJECT_SET(&R, lar->obi_last[shi->thread]);
 +              isec.last_hit = lar->last_hit[shi->thread];
        }
        else {
 -              isec.face_last= NULL;
 -              isec.ob_last= 0;
 +              isec.last_hit = NULL;
        }
        
        if(lar->type==LA_SUN || lar->type==LA_HEMI) {
 -              maxsize= RE_ray_tree_max_size(R.raytree);
 -              lampco[0]= shi->co[0] - maxsize*lar->vec[0];
 -              lampco[1]= shi->co[1] - maxsize*lar->vec[1];
 -              lampco[2]= shi->co[2] - maxsize*lar->vec[2];
 +              /* jitter and QMC sampling add a displace vector to the lamp position
 +               * that's incorrect because a SUN lamp does not has an exact position
 +               * and the displace should be done at the ray vector instead of the
 +               * lamp position.
 +               * This is easily verified by noticing that shadows of SUN lights change
 +               * with the scene BB.
 +               * 
 +               * This was detected during SoC 2009 - Raytrace Optimization, but to keep
 +               * consistency with older render code it wasn't removed.
 +               * 
 +               * If the render code goes through some recode/serious bug-fix then this
 +               * is something to consider!
 +               */
 +              lampco[0]= shi->co[0] - R.maxdist*lar->vec[0];
 +              lampco[1]= shi->co[1] - R.maxdist*lar->vec[1];
 +              lampco[2]= shi->co[2] - R.maxdist*lar->vec[2];
        }
        else {
                VECCOPY(lampco, lar->co);
        } else {
                if(lar->ray_totsamp<2) {
                        
 -                      isec.faceorig= (RayFace*)shi->vlr;
 -                      isec.oborig= RAY_OBJECT_SET(&R, shi->obi);
 +                      isec.orig.ob   = shi->obi;
 +                      isec.orig.face = shi->vlr;
 +                      
                        shadfac[3]= 1.0f; // 1.0=full light
                        
                        /* set up isec vec */
                        VECCOPY(isec.start, shi->co);
 -                      VECCOPY(isec.end, lampco);
 +                      VECSUB(isec.vec, lampco, isec.start);
 +                      isec.labda = 1.0f;
  
                        if(isec.mode==RE_RAY_SHADOW_TRA) {
                                /* isec.col is like shadfac, so defines amount of light (0.0 is full shadow) */
                                ray_trace_shadow_tra(&isec, shi, DEPTH_SHADOW_TRA, 0);
                                QUATCOPY(shadfac, isec.col);
                        }
 -                      else if(RE_ray_tree_intersect(R.raytree, &isec)) shadfac[3]= 0.0f;
 +                      else if(RE_rayobject_raycast(R.raytree, &isec))
 +                              shadfac[3]= 0.0f;
                }
                else {
                        ray_shadow_jitter(shi, lar, lampco, shadfac, &isec);
                
        /* for first hit optim, set last interesected shadow face */
        if(shi->depth==0) {
 -              lar->vlr_last[shi->thread]= (VlakRen*)isec.face_last;
 -              lar->obi_last[shi->thread]= RAY_OBJECT_GET(&R, isec.ob_last);
 +              lar->last_hit[shi->thread] = isec.last_hit;
        }
  
  }
  static void ray_translucent(ShadeInput *shi, LampRen *lar, float *distfac, float *co)
  {
        Isect isec;
 -      float lampco[3], maxsize;
 +      float lampco[3];
 +      
 +      assert(0);
        
        /* setup isec */
 +      RE_RC_INIT(isec, *shi);
        isec.mode= RE_RAY_SHADOW_TRA;
 +      isec.hint = 0;
        
        if(lar->mode & LA_LAYER) isec.lay= lar->lay; else isec.lay= -1;
        
        if(lar->type==LA_SUN || lar->type==LA_HEMI) {
 -              maxsize= RE_ray_tree_max_size(R.raytree);
 -              lampco[0]= shi->co[0] - maxsize*lar->vec[0];
 -              lampco[1]= shi->co[1] - maxsize*lar->vec[1];
 -              lampco[2]= shi->co[2] - maxsize*lar->vec[2];
 +              lampco[0]= shi->co[0] - RE_RAYTRACE_MAXDIST*lar->vec[0];
 +              lampco[1]= shi->co[1] - RE_RAYTRACE_MAXDIST*lar->vec[1];
 +              lampco[2]= shi->co[2] - RE_RAYTRACE_MAXDIST*lar->vec[2];
        }
        else {
                VECCOPY(lampco, lar->co);
        }
        
 -      isec.faceorig= (RayFace*)shi->vlr;
 -      isec.oborig= RAY_OBJECT_SET(&R, shi->obi);
 +      isec.orig.ob   = shi->obi;
 +      isec.orig.face = shi->vlr;
        
        /* set up isec vec */
        VECCOPY(isec.start, shi->co);
        VECCOPY(isec.end, lampco);
        
 -      if(RE_ray_tree_intersect(R.raytree, &isec)) {
 +      if(RE_rayobject_raycast(R.raytree, &isec)) {
                /* we got a face */
                
                /* render co */
index 94d7651a03c4adf6a7c468c99cb6cc723df82a7c,5db81288c1ebb8e7272935db63ffb51116c05430..f3db64295a3c087a9656babf6a08d261798de1c6
@@@ -31,7 -31,6 +31,7 @@@
  #include <math.h>
  #include <float.h>
  #include <string.h>
 +#include <assert.h>
  
  /* External modules: */
  #include "MEM_guardedalloc.h"
@@@ -521,12 -520,6 +521,12 @@@ static void add_filt_passes(RenderLaye
                                }
                        }
                                break;
 +
 +                      case SCE_PASS_RAYHITS:
 +                              /*  */
 +                              col= &shr->rayhits;
 +                              pixsize= 4;
 +                              break;
                }
                if(col) {
                        fp= rpass->rect + pixsize*offset;
@@@ -603,10 -596,6 +603,10 @@@ static void add_passes(RenderLayer *rl
                                fp= rpass->rect + offset;
                                *fp= shr->mist;
                                break;
 +                      case SCE_PASS_RAYHITS:
 +                              col= shr->rayhits;
 +                              pixsize= 4;
 +                              break;
                }
                if(col) {
                        fp= rpass->rect + pixsize*offset;
@@@ -2238,7 -2227,6 +2238,7 @@@ static void bake_displacement(void *han
        }
  }
  
 +#if 0
  static int bake_check_intersect(Isect *is, int ob, RayFace *face)
  {
        BakeShade *bs = (BakeShade*)is->userdata;
        /* no direction checking for now, doesn't always improve the result
         * (INPR(shi->facenor, bs->dir) > 0.0f); */
  
-       return (R.objectinstance[ob].obr->ob != bs->actob);
+       return (R.objectinstance[ob & ~RE_RAY_TRANSFORM_OFFS].obr->ob != bs->actob);
  }
 +#endif
  
 -static int bake_intersect_tree(RayTree* raytree, Isect* isect, float *start, float *dir, float sign, float *hitco, float *dist)
 +static int bake_intersect_tree(RayObject* raytree, Isect* isect, float *start, float *dir, float sign, float *hitco, float *dist)
  {
 +      //TODO
 +      assert( 0 );
 +#if 0
        float maxdist;
        int hit;
  
        if(R.r.bake_maxdist > 0.0f)
                maxdist= R.r.bake_maxdist;
        else
 -              maxdist= RE_ray_tree_max_size(R.raytree) + R.r.bake_biasdist;
 +              maxdist= FLT_MAX + R.r.bake_biasdist;
        
 +      //TODO normalized direction?
        VECADDFAC(isect->start, start, dir, -R.r.bake_biasdist);
 +      isect->dir[0] = dir[0]*sign;
 +      isect->dir[1] = dir[1]*sign;
 +      isect->dir[2] = dir[2]*sign;
 +      isect->labda = maxdist;
  
 -      isect->end[0] = isect->start[0] + dir[0]*maxdist*sign;
 -      isect->end[1] = isect->start[1] + dir[1]*maxdist*sign;
 -      isect->end[2] = isect->start[2] + dir[2]*maxdist*sign;
 -
 -      hit = RE_ray_tree_intersect_check(R.raytree, isect, bake_check_intersect);
 +      hit = RE_rayobject_raycast(raytree, isect);
 +      //TODO bake_check_intersect
        if(hit) {
                hitco[0] = isect->start[0] + isect->labda*isect->vec[0];
                hitco[1] = isect->start[1] + isect->labda*isect->vec[1];
        }
  
        return hit;
 +#endif
 +      return 0;
  }
  
  static void bake_set_vlr_dxyco(BakeShade *bs, float *uv1, float *uv2, float *uv3)
@@@ -2400,9 -2380,8 +2400,9 @@@ static void do_bake_shade(void *handle
                for(sign=-1; sign<=1; sign+=2) {
                        memset(&isec, 0, sizeof(isec));
                        isec.mode= RE_RAY_MIRROR;
 -                      isec.faceorig= (RayFace*)vlr;
 -                      isec.oborig= RAY_OBJECT_SET(&R, obi);
 +
 +                      isec.orig.ob   = obi;
 +                      isec.orig.face = vlr;
                        isec.userdata= bs;
                        
                        if(bake_intersect_tree(R.raytree, &isec, shi->co, shi->vn, sign, co, &dist)) {
  
                /* if hit, we shade from the new point, otherwise from point one starting face */
                if(hit) {
 -                      vlr= (VlakRen*)minisec.face;
 -                      obi= RAY_OBJECT_GET(&R, minisec.ob);
 +                      obi= (ObjectInstanceRen*)minisec.hit.ob;
 +                      vlr= (VlakRen*)minisec.hit.face;
                        quad= (minisec.isect == 2);
                        VECCOPY(shi->co, minco);
                        
index 496d187cf05b9b751ec01b5bfe76c15f07b083c6,7541ce530739eba2d58957e502e2c364eac4ae1b..0d3c5772d8ad0e593ed991b1db9645514042427a
@@@ -29,7 -29,7 +29,7 @@@
  #include <math.h>
  #include <string.h>
  
- #include "MTC_matrixops.h"
  #include "BLI_arithb.h"
  #include "BLI_blenlib.h"
  
@@@ -44,7 -44,6 +44,7 @@@
  #include "BKE_node.h"
  
  /* local include */
 +#include "raycounter.h"
  #include "renderpipeline.h"
  #include "render_types.h"
  #include "renderdatabase.h"
@@@ -53,6 -52,7 +53,7 @@@
  #include "shading.h"
  #include "strand.h"
  #include "texture.h"
+ #include "volumetric.h"
  #include "zbuf.h"
  
  /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
@@@ -167,6 -167,11 +168,11 @@@ void shade_material_loop(ShadeInput *sh
                        if((shi->layflag & SCE_LAY_SKY) && (R.r.alphamode==R_ADDSKY))
                                shr->alpha= 1.0f;
        }       
+       
+       if(R.r.mode & R_RAYTRACE) {
+               if (R.render_volumes_inside.first)
+                       shade_volume_inside(shi, shr);
+       }
  }
  
  
@@@ -176,9 -181,6 +182,9 @@@ void shade_input_do_shade(ShadeInput *s
        float alpha;
        
        /* ------  main shading loop -------- */
 +#ifdef RE_RAYCOUNTER
 +      memset(&shi->raycounter, 0, sizeof(shi->raycounter));
 +#endif
        
        if(shi->mat->nodetree && shi->mat->use_nodes) {
                ntreeShaderExecTree(shi->mat->nodetree, shi, shr);
                /* copy all relevant material vars, note, keep this synced with render_types.h */
                shade_input_init_material(shi);
                
-               shade_material_loop(shi, shr);
+               if (shi->mat->material_type == MA_TYPE_VOLUME) {
+                       if(R.r.mode & R_RAYTRACE)
+                               shade_volume_outside(shi, shr);
+               } else { /* MA_TYPE_SURFACE, MA_TYPE_WIRE */
+                       shade_material_loop(shi, shr);
+               }
        }
        
        /* copy additional passes */
        if(shr->alpha!=1.0f || alpha!=1.0f) {
                float fac= alpha*(shr->alpha);
                shr->combined[3]= fac;
-               shr->combined[0]*= fac;
-               shr->combined[1]*= fac;
-               shr->combined[2]*= fac;
+               
+               if (shi->mat->material_type!= MA_TYPE_VOLUME)
+                       VecMulf(shr->combined, fac);
        }
-       else shr->combined[3]= 1.0f;
+       else
+               shr->combined[3]= 1.0f;
        
        /* add z */
        shr->z= -shi->co[2];
 +      
 +      /* RAYHITS */
 +/*
 +      if(1 || shi->passflag & SCE_PASS_RAYHITS)
 +      {
 +              shr->rayhits[0] = (float)shi->raycounter.faces.test;
 +              shr->rayhits[1] = (float)shi->raycounter.bb.hit;
 +              shr->rayhits[2] = 0.0;
 +              shr->rayhits[3] = 1.0;
 +              RE_RC_MERGE(&re_rc_counter[shi->thread], &shi->raycounter);
 +      }
 + */
  }
  
  /* **************************************************************************** */
@@@ -462,13 -458,13 +474,13 @@@ void shade_input_set_strand_texco(Shade
  
                if(texco & TEXCO_GLOB) {
                        VECCOPY(shi->gl, shi->co);
-                       MTC_Mat4MulVecfl(R.viewinv, shi->gl);
+                       Mat4MulVecfl(R.viewinv, shi->gl);
                        
                        if(shi->osatex) {
                                VECCOPY(shi->dxgl, shi->dxco);
-                               MTC_Mat3MulVecfl(R.imat, shi->dxco);
+                               Mat3MulVecfl(R.imat, shi->dxco);
                                VECCOPY(shi->dygl, shi->dyco);
-                               MTC_Mat3MulVecfl(R.imat, shi->dyco);
+                               Mat3MulVecfl(R.imat, shi->dyco);
                        }
                }
  
@@@ -714,6 -710,10 +726,10 @@@ void shade_input_calc_viewco(ShadeInpu
                }
        }
        
+       /* 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(view);
  }
@@@ -1021,15 -1021,15 +1037,15 @@@ void shade_input_set_shade_texco(ShadeI
                
                if(texco & TEXCO_GLOB) {
                        VECCOPY(shi->gl, shi->co);
-                       MTC_Mat4MulVecfl(R.viewinv, shi->gl);
+                       Mat4MulVecfl(R.viewinv, shi->gl);
                        if(shi->osatex) {
                                VECCOPY(shi->dxgl, shi->dxco);
                                // TXF: bug was here, but probably should be in convertblender.c, R.imat only valid if there is a world
-                               //MTC_Mat3MulVecfl(R.imat, shi->dxco);
-                               MTC_Mat4Mul3Vecfl(R.viewinv, shi->dxco);
+                               //Mat3MulVecfl(R.imat, shi->dxco);
+                               Mat4Mul3Vecfl(R.viewinv, shi->dxco);
                                VECCOPY(shi->dygl, shi->dyco);
-                               //MTC_Mat3MulVecfl(R.imat, shi->dyco);
-                               MTC_Mat4Mul3Vecfl(R.viewinv, shi->dyco);
+                               //Mat3MulVecfl(R.imat, shi->dyco);
+                               Mat4Mul3Vecfl(R.viewinv, shi->dyco);
                        }
                }
                
index 0000000000000000000000000000000000000000,15d8643fea441ffa8ee77e8c7ad939cdeb1cb4dd..ca19f2580aad88b17033b1b213aec95c6f02fd05
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,746 +1,759 @@@
 -int intersect_outside_volume(RayTree *tree, Isect *isect, float *offset, int limit, int depth)
+ /**
+  *
+  * ***** BEGIN GPL LICENSE BLOCK *****
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+  * as published by the Free Software Foundation; either version 2
+  * of the License, or (at your option) any later version.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software Foundation,
+  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  *
+  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+  * All rights reserved.
+  *
+  * The Original Code is: all of this file.
+  *
+  * Contributor(s): Matt Ebb.
+  *
+  * ***** END GPL LICENSE BLOCK *****
+  */
+ #include <math.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <float.h>
+ #include "MEM_guardedalloc.h"
+ #include "BLI_blenlib.h"
+ #include "BLI_arithb.h"
+ #include "BLI_threads.h"
+ #include "BLI_voxel.h"
+ #include "PIL_time.h"
+ #include "RE_shader_ext.h"
+ #include "RE_raytrace.h"
+ #include "DNA_material_types.h"
+ #include "render_types.h"
++#include "rendercore.h"
+ #include "renderdatabase.h"
+ #include "volumetric.h"
+ #include "volume_precache.h"
+ #if defined( _MSC_VER ) && !defined( __cplusplus )
+ # define inline __inline
+ #endif // defined( _MSC_VER ) && !defined( __cplusplus )
+ #include "BKE_global.h"
+ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+ /* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
+ /* only to be used here in this file, it's for speed */
+ extern struct Render R;
+ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+ /* *** utility code to set up an individual raytree for objectinstance, for checking inside/outside *** */
+ /* Recursive test for intersections, from a point inside the mesh, to outside
+  * Number of intersections (depth) determine if a point is inside or outside the mesh */
 -      if (RE_ray_tree_intersect(tree, isect)) {
++int intersect_outside_volume(RayObject *tree, Isect *isect, float *offset, int limit, int depth)
+ {
+       if (limit == 0) return depth;
+       
 -int point_inside_obi(RayTree *tree, ObjectInstanceRen *obi, float *co)
++      if (RE_rayobject_raycast(tree, isect)) {
+               float hitco[3];
+               
+               hitco[0] = isect->start[0] + isect->labda*isect->vec[0];
+               hitco[1] = isect->start[1] + isect->labda*isect->vec[1];
+               hitco[2] = isect->start[2] + isect->labda*isect->vec[2];
+               VecAddf(isect->start, hitco, offset);
+               return intersect_outside_volume(tree, isect, offset, limit-1, depth+1);
+       } else {
+               return depth;
+       }
+ }
+ /* Uses ray tracing to check if a point is inside or outside an ObjectInstanceRen */
 -      float maxsize = RE_ray_tree_max_size(tree);
++int point_inside_obi(RayObject *tree, ObjectInstanceRen *obi, float *co)
+ {
 -      isect.face_last= NULL;
+       Isect isect;
+       float vec[3] = {0.0f,0.0f,1.0f};
+       int final_depth=0, depth=0, limit=20;
+       
+       /* set up the isect */
+       memset(&isect, 0, sizeof(isect));
+       VECCOPY(isect.start, co);
++      VECCOPY(isect.vec, vec);
++      isect.labda = FLT_MAX;
++      
++      /*
+       isect.end[0] = co[0] + vec[0] * maxsize;
+       isect.end[1] = co[1] + vec[1] * maxsize;
+       isect.end[2] = co[2] + vec[2] * maxsize;
++      */
+       
+       /* and give it a little offset to prevent self-intersections */
+       VecMulf(vec, 1e-5);
+       VecAddf(isect.start, isect.start, vec);
+       
+       isect.mode= RE_RAY_MIRROR;
 -static int inside_check_func(Isect *is, int ob, RayFace *face)
++      isect.last_hit= NULL;
+       isect.lay= -1;
+       
+       final_depth = intersect_outside_volume(tree, &isect, vec, limit, depth);
+       
+       /* even number of intersections: point is outside
+        * odd number: point is inside */
+       if (final_depth % 2 == 0) return 0;
+       else return 1;
+ }
 -RayTree *create_raytree_obi(ObjectInstanceRen *obi, float *bbmin, float *bbmax)
++/*
++static int inside_check_func(Isect *is, int ob, RayObject *face)
+ {
+       return 1;
+ }
++
+ static void vlr_face_coords(RayFace *face, float **v1, float **v2, float **v3, float **v4)
+ {
+       VlakRen *vlr= (VlakRen*)face;
+       *v1 = (vlr->v1)? vlr->v1->co: NULL;
+       *v2 = (vlr->v2)? vlr->v2->co: NULL;
+       *v3 = (vlr->v3)? vlr->v3->co: NULL;
+       *v4 = (vlr->v4)? vlr->v4->co: NULL;
+ }
 -      /* create empty raytree */
++RayObject *create_raytree_obi(ObjectInstanceRen *obi, float *bbmin, float *bbmax)
+ {
+       int v;
+       VlakRen *vlr= NULL;
+       
 -      /* fill it with faces */
++      / * create empty raytree * /
+       RayTree *tree = RE_ray_tree_create(64, obi->obr->totvlak, bbmin, bbmax,
+               vlr_face_coords, inside_check_func, NULL, NULL);
+       
 -      RayTree *tree = pa->tree;
++      / * fill it with faces * /
+       for(v=0; v<obi->obr->totvlak; v++) {
+               if((v & 255)==0)
+                       vlr= obi->obr->vlaknodes[v>>8].vlak;
+               else
+                       vlr++;
+       
+               RE_ray_tree_add_face(tree, 0, vlr);
+       }
+       
+       RE_ray_tree_done(tree);
+       
+       return tree;
+ }
++*/
+ /* *** light cache filtering *** */
+ static float get_avg_surrounds(float *cache, int *res, int xx, int yy, int zz)
+ {
+       int x, y, z, x_, y_, z_;
+       int added=0;
+       float tot=0.0f;
+       
+       for (z=-1; z <= 1; z++) {
+               z_ = zz+z;
+               if (z_ >= 0 && z_ <= res[2]-1) {
+               
+                       for (y=-1; y <= 1; y++) {
+                               y_ = yy+y;
+                               if (y_ >= 0 && y_ <= res[1]-1) {
+                               
+                                       for (x=-1; x <= 1; x++) {
+                                               x_ = xx+x;
+                                               if (x_ >= 0 && x_ <= res[0]-1) {
+                                               
+                                                       if (cache[ V_I(x_, y_, z_, res) ] > 0.0f) {
+                                                               tot += cache[ V_I(x_, y_, z_, res) ];
+                                                               added++;
+                                                       }
+                                                       
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+       
+       tot /= added;
+       
+       return ((added>0)?tot:0.0f);
+ }
+ /* function to filter the edges of the light cache, where there was no volume originally.
+  * For each voxel which was originally external to the mesh, it finds the average values of
+  * the surrounding internal voxels and sets the original external voxel to that average amount.
+  * Works almost a bit like a 'dilate' filter */
+ static void lightcache_filter(VolumePrecache *vp)
+ {
+       int x, y, z;
+       for (z=0; z < vp->res[2]; z++) {
+               for (y=0; y < vp->res[1]; y++) {
+                       for (x=0; x < vp->res[0]; x++) {
+                               /* trigger for outside mesh */
+                               if (vp->data_r[ V_I(x, y, z, vp->res) ] < -0.5f)
+                                       vp->data_r[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_r, vp->res, x, y, z);
+                               if (vp->data_g[ V_I(x, y, z, vp->res) ] < -0.5f)
+                                       vp->data_g[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_g, vp->res, x, y, z);
+                               if (vp->data_b[ V_I(x, y, z, vp->res) ] < -0.5f)
+                                       vp->data_b[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_b, vp->res, x, y, z);
+                       }
+               }
+       }
+ }
+ static inline int ms_I(int x, int y, int z, int *n) //has a pad of 1 voxel surrounding the core for boundary simulation
+ { 
+       return z*(n[1]+2)*(n[0]+2) + y*(n[0]+2) + x;
+ }
+ /* *** multiple scattering approximation *** */
+ /* get the total amount of light energy in the light cache. used to normalise after multiple scattering */
+ static float total_ss_energy(VolumePrecache *vp)
+ {
+       int x, y, z;
+       int *res = vp->res;
+       float energy=0.f;
+       
+       for (z=0; z < res[2]; z++) {
+               for (y=0; y < res[1]; y++) {
+                       for (x=0; x < res[0]; x++) {
+                               if (vp->data_r[ V_I(x, y, z, res) ] > 0.f) energy += vp->data_r[ V_I(x, y, z, res) ];
+                               if (vp->data_g[ V_I(x, y, z, res) ] > 0.f) energy += vp->data_g[ V_I(x, y, z, res) ];
+                               if (vp->data_b[ V_I(x, y, z, res) ] > 0.f) energy += vp->data_b[ V_I(x, y, z, res) ];
+                       }
+               }
+       }
+       
+       return energy;
+ }
+ static float total_ms_energy(float *sr, float *sg, float *sb, int *res)
+ {
+       int x, y, z, i;
+       float energy=0.f;
+       
+       for (z=1;z<=res[2];z++) {
+               for (y=1;y<=res[1];y++) {
+                       for (x=1;x<=res[0];x++) {
+                       
+                               i = ms_I(x,y,z,res);
+                               if (sr[i] > 0.f) energy += sr[i];
+                               if (sg[i] > 0.f) energy += sg[i];
+                               if (sb[i] > 0.f) energy += sb[i];
+                       }
+               }
+       }
+       
+       return energy;
+ }
+ static void ms_diffuse(int b, float* x0, float* x, float diff, int *n)
+ {
+       int i, j, k, l;
+       const float dt = VOL_MS_TIMESTEP;
+       const float a = dt*diff*n[0]*n[1]*n[2];
+       
+       for (l=0; l<20; l++)
+       {
+               for (k=1; k<=n[2]; k++)
+               {
+                       for (j=1; j<=n[1]; j++)
+                       {
+                               for (i=1; i<=n[0]; i++)
+                               {
+                                       x[ms_I(i,j,k,n)] = (x0[ms_I(i,j,k,n)] + a*(
+                                                x[ms_I(i-1,j,k,n)]+x[ms_I(i+1,j,k,n)]+
+                                                x[ms_I(i,j-1,k,n)]+x[ms_I(i,j+1,k,n)]+
+                                                x[ms_I(i,j,k-1,n)]+x[ms_I(i,j,k+1,n)]))/(1+6*a);
+                               }
+                       }
+               }
+       }
+ }
+ void multiple_scattering_diffusion(Render *re, VolumePrecache *vp, Material *ma)
+ {
+       const float diff = ma->vol.ms_diff * 0.001f;    /* compensate for scaling for a nicer UI range */
+       const float simframes = ma->vol.ms_steps;
+       const int shade_type = ma->vol.shade_type;
+       float fac = ma->vol.ms_intensity;
+       
+       int x, y, z, m;
+       int *n = vp->res;
+       const int size = (n[0]+2)*(n[1]+2)*(n[2]+2);
+       double time, lasttime= PIL_check_seconds_timer();
+       float total;
+       float c=1.0f;
+       int i;
+       float origf;    /* factor for blending in original light cache */
+       float energy_ss, energy_ms;
+       float *sr0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
+       float *sr=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
+       float *sg0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
+       float *sg=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
+       float *sb0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
+       float *sb=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
+       total = (float)(n[0]*n[1]*n[2]*simframes);
+       
+       energy_ss = total_ss_energy(vp);
+       
+       /* Scattering as diffusion pass */
+       for (m=0; m<simframes; m++)
+       {
+               /* add sources */
+               for (z=1; z<=n[2]; z++)
+               {
+                       for (y=1; y<=n[1]; y++)
+                       {
+                               for (x=1; x<=n[0]; x++)
+                               {
+                                       i = V_I((x-1), (y-1), (z-1), n);
+                                       time= PIL_check_seconds_timer();
+                                       c++;
+                                                                               
+                                       if (vp->data_r[i] > 0.f)
+                                               sr[ms_I(x,y,z,n)] += vp->data_r[i];
+                                       if (vp->data_g[i] > 0.f)
+                                               sg[ms_I(x,y,z,n)] += vp->data_g[i];
+                                       if (vp->data_b[i] > 0.f)
+                                               sb[ms_I(x,y,z,n)] += vp->data_b[i];
+                                       
+                                       /* Displays progress every second */
+                                       if(time-lasttime>1.0f) {
+                                               char str[64];
+                                               sprintf(str, "Simulating multiple scattering: %d%%", (int)
+                                                               (100.0f * (c / total)));
+                                               re->i.infostr= str;
+                                               re->stats_draw(re->sdh, &re->i);
+                                               re->i.infostr= NULL;
+                                               lasttime= time;
+                                       }
+                               }
+                       }
+               }
+               SWAP(float *, sr, sr0);
+               SWAP(float *, sg, sg0);
+               SWAP(float *, sb, sb0);
+               /* main diffusion simulation */
+               ms_diffuse(0, sr0, sr, diff, n);
+               ms_diffuse(0, sg0, sg, diff, n);
+               ms_diffuse(0, sb0, sb, diff, n);
+               
+               if (re->test_break(re->tbh)) break;
+       }
+       
+       /* normalisation factor to conserve energy */
+       energy_ms = total_ms_energy(sr, sg, sb, n);
+       fac *= (energy_ss / energy_ms);
+       
+       /* blend multiple scattering back in the light cache */
+       if (shade_type == MA_VOL_SHADE_SINGLEPLUSMULTIPLE) {
+               /* conserve energy - half single, half multiple */
+               origf = 0.5f;
+               fac *= 0.5f;
+       } else {
+               origf = 0.0f;
+       }
+       for (z=1;z<=n[2];z++)
+       {
+               for (y=1;y<=n[1];y++)
+               {
+                       for (x=1;x<=n[0];x++)
+                       {
+                               int index=(x-1)*n[1]*n[2] + (y-1)*n[2] + z-1;
+                               vp->data_r[index] = origf * vp->data_r[index] + fac * sr[ms_I(x,y,z,n)];
+                               vp->data_g[index] = origf * vp->data_g[index] + fac * sg[ms_I(x,y,z,n)];
+                               vp->data_b[index] = origf * vp->data_b[index] + fac * sb[ms_I(x,y,z,n)];
+                       }
+               }
+       }
+       MEM_freeN(sr0);
+       MEM_freeN(sr);
+       MEM_freeN(sg0);
+       MEM_freeN(sg);
+       MEM_freeN(sb0);
+       MEM_freeN(sb);
+ }
+ #if 0 // debug stuff
+ static void *vol_precache_part_test(void *data)
+ {
+       VolPrecachePart *pa = data;
+       printf("part number: %d \n", pa->num);
+       printf("done: %d \n", pa->done);
+       printf("x min: %d   x max: %d \n", pa->minx, pa->maxx);
+       printf("y min: %d   y max: %d \n", pa->miny, pa->maxy);
+       printf("z min: %d   z max: %d \n", pa->minz, pa->maxz);
+       return NULL;
+ }
+ #endif
+ /* Iterate over the 3d voxel grid, and fill the voxels with scattering information
+  *
+  * It's stored in memory as 3 big float grids next to each other, one for each RGB channel.
+  * I'm guessing the memory alignment may work out better this way for the purposes
+  * of doing linear interpolation, but I haven't actually tested this theory! :)
+  */
+ static void *vol_precache_part(void *data)
+ {
+       VolPrecachePart *pa =  (VolPrecachePart *)data;
+       ObjectInstanceRen *obi = pa->obi;
 -static void precache_init_parts(Render *re, RayTree *tree, ShadeInput *shi, ObjectInstanceRen *obi, int totthread, int *parts)
++      RayObject *tree = pa->tree;
+       ShadeInput *shi = pa->shi;
+       float density, scatter_col[3] = {0.f, 0.f, 0.f};
+       float co[3];
+       int x, y, z;
+       const int res[3]= {pa->res[0], pa->res[1], pa->res[2]};
+       const float stepsize = vol_get_stepsize(shi, STEPSIZE_VIEW);
+       for (z= pa->minz; z < pa->maxz; z++) {
+               co[2] = pa->bbmin[2] + (pa->voxel[2] * (z + 0.5f));
+               
+               for (y= pa->miny; y < pa->maxy; y++) {
+                       co[1] = pa->bbmin[1] + (pa->voxel[1] * (y + 0.5f));
+                       
+                       for (x=pa->minx; x < pa->maxx; x++) {
+                               co[0] = pa->bbmin[0] + (pa->voxel[0] * (x + 0.5f));
+                               
+                               // don't bother if the point is not inside the volume mesh
+                               if (!point_inside_obi(tree, obi, co)) {
+                                       obi->volume_precache->data_r[ V_I(x, y, z, res) ] = -1.0f;
+                                       obi->volume_precache->data_g[ V_I(x, y, z, res) ] = -1.0f;
+                                       obi->volume_precache->data_b[ V_I(x, y, z, res) ] = -1.0f;
+                                       continue;
+                               }
+                               
+                               VecCopyf(shi->view, co);
+                               Normalize(shi->view);
+                               density = vol_get_density(shi, co);
+                               vol_get_scattering(shi, scatter_col, co, stepsize, density);
+                       
+                               obi->volume_precache->data_r[ V_I(x, y, z, res) ] = scatter_col[0];
+                               obi->volume_precache->data_g[ V_I(x, y, z, res) ] = scatter_col[1];
+                               obi->volume_precache->data_b[ V_I(x, y, z, res) ] = scatter_col[2];
+                       }
+               }
+       }
+       
+       pa->done = 1;
+       
+       return 0;
+ }
+ static void precache_setup_shadeinput(Render *re, ObjectInstanceRen *obi, Material *ma, ShadeInput *shi)
+ {
+       memset(shi, 0, sizeof(ShadeInput)); 
+       shi->depth= 1;
+       shi->mask= 1;
+       shi->mat = ma;
+       shi->vlr = NULL;
+       memcpy(&shi->r, &shi->mat->r, 23*sizeof(float));        // note, keep this synced with render_types.h
+       shi->har= shi->mat->har;
+       shi->obi= obi;
+       shi->obr= obi->obr;
+       shi->lay = re->scene->lay;
+ }
 -      RayTree *tree;
++static void precache_init_parts(Render *re, RayObject *tree, ShadeInput *shi, ObjectInstanceRen *obi, int totthread, int *parts)
+ {
+       VolumePrecache *vp = obi->volume_precache;
+       int i=0, x, y, z;
+       float voxel[3];
+       int sizex, sizey, sizez;
+       float *bbmin=obi->obr->boundbox[0], *bbmax=obi->obr->boundbox[1];
+       int *res;
+       int minx, maxx;
+       int miny, maxy;
+       int minz, maxz;
+       
+       if (!vp) return;
+       BLI_freelistN(&re->volume_precache_parts);
+       
+       /* currently we just subdivide the box, number of threads per side */
+       parts[0] = parts[1] = parts[2] = totthread;
+       res = vp->res;
+       
+       VecSubf(voxel, bbmax, bbmin);
+       
+       voxel[0] /= res[0];
+       voxel[1] /= res[1];
+       voxel[2] /= res[2];
+       for (x=0; x < parts[0]; x++) {
+               sizex = ceil(res[0] / (float)parts[0]);
+               minx = x * sizex;
+               maxx = minx + sizex;
+               maxx = (maxx>res[0])?res[0]:maxx;
+               
+               for (y=0; y < parts[1]; y++) {
+                       sizey = ceil(res[1] / (float)parts[1]);
+                       miny = y * sizey;
+                       maxy = miny + sizey;
+                       maxy = (maxy>res[1])?res[1]:maxy;
+                       
+                       for (z=0; z < parts[2]; z++) {
+                               VolPrecachePart *pa= MEM_callocN(sizeof(VolPrecachePart), "new precache part");
+                               
+                               sizez = ceil(res[2] / (float)parts[2]);
+                               minz = z * sizez;
+                               maxz = minz + sizez;
+                               maxz = (maxz>res[2])?res[2]:maxz;
+                                               
+                               pa->done = 0;
+                               pa->working = 0;
+                               
+                               pa->num = i;
+                               pa->tree = tree;
+                               pa->shi = shi;
+                               pa->obi = obi;
+                               VECCOPY(pa->bbmin, bbmin);
+                               VECCOPY(pa->voxel, voxel);
+                               VECCOPY(pa->res, res);
+                               
+                               pa->minx = minx; pa->maxx = maxx;
+                               pa->miny = miny; pa->maxy = maxy;
+                               pa->minz = minz; pa->maxz = maxz;
+                               
+                               
+                               BLI_addtail(&re->volume_precache_parts, pa);
+                               
+                               i++;
+                       }
+               }
+       }
+ }
+ static VolPrecachePart *precache_get_new_part(Render *re)
+ {
+       VolPrecachePart *pa, *nextpa=NULL;
+       
+       for (pa = re->volume_precache_parts.first; pa; pa=pa->next)
+       {
+               if (pa->done==0 && pa->working==0) {
+                       nextpa = pa;
+                       break;
+               }
+       }
+       return nextpa;
+ }
+ static int precache_resolution(VolumePrecache *vp, float *bbmin, float *bbmax, int res)
+ {
+       float dim[3], div;
+       
+       VecSubf(dim, bbmax, bbmin);
+       
+       div = MAX3(dim[0], dim[1], dim[2]);
+       dim[0] /= div;
+       dim[1] /= div;
+       dim[2] /= div;
+       
+       vp->res[0] = dim[0] * (float)res;
+       vp->res[1] = dim[1] * (float)res;
+       vp->res[2] = dim[2] * (float)res;
+       
+       if ((vp->res[0] < 1) || (vp->res[1] < 1) || (vp->res[2] < 1))
+               return 0;
+       
+       return 1;
+ }
+ /* Precache a volume into a 3D voxel grid.
+  * The voxel grid is stored in the ObjectInstanceRen, 
+  * in camera space, aligned with the ObjectRen's bounding box.
+  * Resolution is defined by the user.
+  */
+ void vol_precache_objectinstance_threads(Render *re, ObjectInstanceRen *obi, Material *ma)
+ {
+       VolumePrecache *vp;
+       VolPrecachePart *nextpa, *pa;
 -      tree = create_raytree_obi(obi, bbmin, bbmax);
++      RayObject *tree;
+       ShadeInput shi;
+       ListBase threads;
+       float *bbmin=obi->obr->boundbox[0], *bbmax=obi->obr->boundbox[1];
+       int parts[3], totparts;
+       
+       int caching=1, counter=0;
+       int totthread = re->r.threads;
+       
+       double time, lasttime= PIL_check_seconds_timer();
+       
+       R = *re;
+       /* create a raytree with just the faces of the instanced ObjectRen, 
+        * used for checking if the cached point is inside or outside. */
 -              RE_ray_tree_free(tree);
 -              tree= NULL;
++      //tree = create_raytree_obi(obi, bbmin, bbmax);
++      tree = makeraytree_object(&R, obi);
+       if (!tree) return;
++      INIT_MINMAX(bbmin, bbmax);
++      RE_rayobject_merge_bb( tree, bbmin, bbmax);
+       vp = MEM_callocN(sizeof(VolumePrecache), "volume light cache");
+       
+       if (!precache_resolution(vp, bbmin, bbmax, ma->vol.precache_resolution)) {
+               MEM_freeN(vp);
+               vp = NULL;
+               return;
+       }
+       vp->data_r = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data red channel");
+       vp->data_g = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data green channel");
+       vp->data_b = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data blue channel");
+       obi->volume_precache = vp;
+       /* Need a shadeinput to calculate scattering */
+       precache_setup_shadeinput(re, obi, ma, &shi);
+       
+       precache_init_parts(re, tree, &shi, obi, totthread, parts);
+       totparts = parts[0] * parts[1] * parts[2];
+       
+       BLI_init_threads(&threads, vol_precache_part, totthread);
+       
+       while(caching) {
+               if(BLI_available_threads(&threads) && !(re->test_break(re->tbh))) {
+                       nextpa = precache_get_new_part(re);
+                       if (nextpa) {
+                               nextpa->working = 1;
+                               BLI_insert_thread(&threads, nextpa);
+                       }
+               }
+               else PIL_sleep_ms(50);
+               caching=0;
+               counter=0;
+               for(pa= re->volume_precache_parts.first; pa; pa= pa->next) {
+                       
+                       if(pa->done) {
+                               counter++;
+                               BLI_remove_thread(&threads, pa);
+                       } else
+                               caching = 1;
+               }
+               
+               if (re->test_break(re->tbh) && BLI_available_threads(&threads)==totthread)
+                       caching=0;
+               
+               time= PIL_check_seconds_timer();
+               if(time-lasttime>1.0f) {
+                       char str[64];
+                       sprintf(str, "Precaching volume: %d%%", (int)(100.0f * ((float)counter / (float)totparts)));
+                       re->i.infostr= str;
+                       re->stats_draw(re->sdh, &re->i);
+                       re->i.infostr= NULL;
+                       lasttime= time;
+               }
+       }
+       
+       BLI_end_threads(&threads);
+       BLI_freelistN(&re->volume_precache_parts);
+       
+       if(tree) {
 -      RayTree *tree;
++              //TODO: makeraytree_object creates a tree and saves it on OBI, if we free this tree we should also clear other pointers to it
++              //RE_rayobject_free(tree);
++              //tree= NULL;
+       }
+       
+       lightcache_filter(obi->volume_precache);
+       
+       if (ELEM(ma->vol.shade_type, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SINGLEPLUSMULTIPLE))
+       {
+               multiple_scattering_diffusion(re, vp, ma);
+       }
+ }
+ static int using_lightcache(Material *ma)
+ {
+       return (((ma->vol.shadeflag & MA_VOL_PRECACHESHADING) && (ma->vol.shade_type == MA_VOL_SHADE_SINGLE))
+               || (ELEM(ma->vol.shade_type, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SINGLEPLUSMULTIPLE)));
+ }
+ /* loop through all objects (and their associated materials)
+  * marked for pre-caching in convertblender.c, and pre-cache them */
+ void volume_precache(Render *re)
+ {
+       ObjectInstanceRen *obi;
+       VolumeOb *vo;
+       for(vo= re->volumes.first; vo; vo= vo->next) {
+               if (using_lightcache(vo->ma)) {
+                       for(obi= re->instancetable.first; obi; obi= obi->next) {
+                               if (obi->obr == vo->obr) {
+                                       vol_precache_objectinstance_threads(re, obi, vo->ma);
+                               }
+                       }
+               }
+       }
+       
+       re->i.infostr= NULL;
+       re->stats_draw(re->sdh, &re->i);
+ }
+ void free_volume_precache(Render *re)
+ {
+       ObjectInstanceRen *obi;
+       
+       for(obi= re->instancetable.first; obi; obi= obi->next) {
+               if (obi->volume_precache != NULL) {
+                       MEM_freeN(obi->volume_precache->data_r);
+                       MEM_freeN(obi->volume_precache->data_g);
+                       MEM_freeN(obi->volume_precache->data_b);
+                       MEM_freeN(obi->volume_precache);
+                       obi->volume_precache = NULL;
+               }
+       }
+       
+       BLI_freelistN(&re->volumes);
+ }
+ int point_inside_volume_objectinstance(ObjectInstanceRen *obi, float *co)
+ {
 -      tree = create_raytree_obi(obi, obi->obr->boundbox[0], obi->obr->boundbox[1]);
++      RayObject *tree;
+       int inside=0;
+       
 -      RE_ray_tree_free(tree);
 -      tree= NULL;
++      tree = makeraytree_object(&R, obi); //create_raytree_obi(obi, obi->obr->boundbox[0], obi->obr->boundbox[1]);
+       if (!tree) return 0;
+       
+       inside = point_inside_obi(tree, obi, co);
+       
++      //TODO: makeraytree_object creates a tree and saves it on OBI, if we free this tree we should also clear other pointers to it
++      //RE_rayobject_free(tree);
++      //tree= NULL;
+       
+       return inside;
+ }
index 0000000000000000000000000000000000000000,bc425c8a1a393d2abcf6d38ebab7ad2925188cc3..2808d266d92352607fd1bac54397714b00cfe328
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,752 +1,749 @@@
 -      float maxsize = RE_ray_tree_max_size(R.raytree);
 -      
+ /**
+  *
+  * ***** BEGIN GPL LICENSE BLOCK *****
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+  * as published by the Free Software Foundation; either version 2
+  * of the License, or (at your option) any later version.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software Foundation,
+  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  *
+  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+  * All rights reserved.
+  *
+  * The Original Code is: all of this file.
+  *
+  * Contributor(s): Matt Ebb, Raul Fernandez Hernandez (Farsthary)
+  *
+  * ***** END GPL LICENSE BLOCK *****
+  */
+ #include <math.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <float.h>
+ #include "MEM_guardedalloc.h"
+ #include "BLI_blenlib.h"
+ #include "BLI_arithb.h"
+ #include "BLI_rand.h"
+ #include "BLI_voxel.h"
+ #include "RE_shader_ext.h"
+ #include "RE_raytrace.h"
+ #include "DNA_material_types.h"
+ #include "DNA_group_types.h"
+ #include "DNA_lamp_types.h"
+ #include "DNA_meta_types.h"
+ #include "BKE_global.h"
+ #include "render_types.h"
+ #include "pixelshading.h"
+ #include "shading.h"
+ #include "texture.h"
+ #include "volumetric.h"
+ #include "volume_precache.h"
+ #if defined( _MSC_VER ) && !defined( __cplusplus )
+ # define inline __inline
+ #endif // defined( _MSC_VER ) && !defined( __cplusplus )
+ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+ /* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
+ /* only to be used here in this file, it's for speed */
+ extern struct Render R;
+ /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+ /* luminance rec. 709 */
+ inline float luminance(float* col)
+ {
+       return (0.212671f*col[0] + 0.71516f*col[1] + 0.072169f*col[2]);
+ }
+ /* tracing */
+ static int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco, Isect *isect, int intersect_type)
+ {
 -      isect->oborig= RAY_OBJECT_SET(&R, shi->obi);
 -      isect->face_last= NULL;
 -      isect->ob_last= 0;
+       /* XXX TODO - get raytrace max distance from object instance's bounding box */
+       /* need to account for scaling only, but keep coords in camera space...
+        * below code is WIP and doesn't work!
+       VecSubf(bb_dim, shi->obi->obr->boundbox[1], shi->obi->obr->boundbox[2]);
+       Mat3MulVecfl(shi->obi->nmat, bb_dim);
+       maxsize = VecLength(bb_dim);
+       */
+       
+       VECCOPY(isect->start, co);
++      VECCOPY(isect->vec, vec );
++      isect->labda = FLT_MAX;
++      /*
+       isect->end[0] = co[0] + vec[0] * maxsize;
+       isect->end[1] = co[1] + vec[1] * maxsize;
+       isect->end[2] = co[2] + vec[2] * maxsize;
++      */
+       
+       isect->mode= RE_RAY_MIRROR;
 -      if (intersect_type == VOL_BOUNDS_DEPTH) isect->faceorig= (RayFace*)shi->vlr;
 -      else if (intersect_type == VOL_BOUNDS_SS) isect->faceorig= NULL;
++      isect->orig.ob = (void*)shi->obi;
++      isect->last_hit = NULL;
+       isect->lay= -1;
+       
 -      if(RE_ray_tree_intersect(R.raytree, isect))
++      if (intersect_type == VOL_BOUNDS_DEPTH) isect->orig.face = (void*)shi->vlr;
++      else if (intersect_type == VOL_BOUNDS_SS) isect->orig.face= NULL;
+       
 -      float maxsize = RE_ray_tree_max_size(R.raytree);
++      if(RE_rayobject_raycast(R.raytree, isect))
+       {
+               hitco[0] = isect->start[0] + isect->labda*isect->vec[0];
+               hitco[1] = isect->start[1] + isect->labda*isect->vec[1];
+               hitco[2] = isect->start[2] + isect->labda*isect->vec[2];
+               return 1;
+       } else {
+               return 0;
+       }
+ }
+ static void shade_intersection(ShadeInput *shi, float *col, Isect *is)
+ {
+       ShadeInput shi_new;
+       ShadeResult shr_new;
+       
+       memset(&shi_new, 0, sizeof(ShadeInput)); 
+       
+       shi_new.mask= shi->mask;
+       shi_new.osatex= shi->osatex;
+       shi_new.thread= shi->thread;
+       shi_new.depth = shi->depth + 1;
+       shi_new.volume_depth= shi->volume_depth + 1;
+       shi_new.xs= shi->xs;
+       shi_new.ys= shi->ys;
+       shi_new.lay= shi->lay;
+       shi_new.passflag= SCE_PASS_COMBINED; /* result of tracing needs no pass info */
+       shi_new.combinedflag= 0xFFFFFF;          /* ray trace does all options */
+       shi_new.light_override= shi->light_override;
+       shi_new.mat_override= shi->mat_override;
+       
+       VECCOPY(shi_new.camera_co, is->start);
+       
+       memset(&shr_new, 0, sizeof(ShadeResult));
+       
+       /* hardcoded limit of 100 for now - prevents problems in weird geometry */
+       if (shi->volume_depth < 100) {
+               shade_ray(is, &shi_new, &shr_new);
+       }
+       
+       VecCopyf(col, shr_new.combined);
+       col[3] = shr_new.alpha;
+ }
+ static void vol_trace_behind(ShadeInput *shi, VlakRen *vlr, float *co, float *col)
+ {
+       Isect isect;
 -      isect.end[0] = isect.start[0] + shi->view[0] * maxsize;
 -      isect.end[1] = isect.start[1] + shi->view[1] * maxsize;
 -      isect.end[2] = isect.start[2] + shi->view[2] * maxsize;
 -      
 -      isect.faceorig= (RayFace *)vlr;
+       
+       VECCOPY(isect.start, co);
 -      isect.oborig= RAY_OBJECT_SET(&R, shi->obi);
 -      isect.face_last= NULL;
 -      isect.ob_last= 0;
++      VECCOPY(isect.vec, shi->view);
++      isect.labda = FLT_MAX;
+       
+       isect.mode= RE_RAY_MIRROR;
 -      if(RE_ray_tree_intersect(R.raytree, &isect)) {
++      isect.orig.ob = (void*) shi->obi;
++      isect.orig.face = (void*)vlr;
++      isect.last_hit = NULL;
+       isect.lay= -1;
+       
+       /* check to see if there's anything behind the volume, otherwise shade the sky */
 -                      VlakRen *vlr = (VlakRen *)is.face;
++      if(RE_rayobject_raycast(R.raytree, &isect)) {
+               shade_intersection(shi, col, &isect);
+       } else {
+               shadeSkyView(col, co, shi->view, NULL, shi->thread);
+               shadeSunView(col, shi->view);
+       }
+ }
+ /* input shader data */
+ float vol_get_stepsize(struct ShadeInput *shi, int context)
+ {
+       if (shi->mat->vol.stepsize_type == MA_VOL_STEP_RANDOMIZED) {
+               /* range between 0.75 and 1.25 */
+               const float rnd = 0.5f * BLI_thread_frand(shi->thread) + 0.75f;
+       
+               if (context == STEPSIZE_VIEW)
+                       return shi->mat->vol.stepsize * rnd;
+               else if (context == STEPSIZE_SHADE)
+                       return shi->mat->vol.shade_stepsize * rnd;
+       }
+       else {  // MA_VOL_STEP_CONSTANT
+               
+               if (context == STEPSIZE_VIEW)
+                       return shi->mat->vol.stepsize;
+               else if (context == STEPSIZE_SHADE)
+                       return shi->mat->vol.shade_stepsize;
+       }
+       
+       return shi->mat->vol.stepsize;
+ }
+ /* trilinear interpolation */
+ static void vol_get_precached_scattering(ShadeInput *shi, float *scatter_col, float *co)
+ {
+       VolumePrecache *vp = shi->obi->volume_precache;
+       float bbmin[3], bbmax[3], dim[3];
+       float sample_co[3];
+       
+       if (!vp) return;
+       
+       /* convert input coords to 0.0, 1.0 */
+       VECCOPY(bbmin, shi->obi->obr->boundbox[0]);
+       VECCOPY(bbmax, shi->obi->obr->boundbox[1]);
+       VecSubf(dim, bbmax, bbmin);
+       sample_co[0] = ((co[0] - bbmin[0]) / dim[0]);
+       sample_co[1] = ((co[1] - bbmin[1]) / dim[1]);
+       sample_co[2] = ((co[2] - bbmin[2]) / dim[2]);
+       scatter_col[0] = voxel_sample_trilinear(vp->data_r, vp->res, sample_co);
+       scatter_col[1] = voxel_sample_trilinear(vp->data_g, vp->res, sample_co);
+       scatter_col[2] = voxel_sample_trilinear(vp->data_b, vp->res, sample_co);
+ }
+ /* Meta object density, brute force for now 
+  * (might be good enough anyway, don't need huge number of metaobs to model volumetric objects */
+ static float metadensity(Object* ob, float* co)
+ {
+       float mat[4][4], imat[4][4], dens = 0.f;
+       MetaBall* mb = (MetaBall*)ob->data;
+       MetaElem* ml;
+       
+       /* transform co to meta-element */
+       float tco[3] = {co[0], co[1], co[2]};
+       Mat4MulMat4(mat, ob->obmat, R.viewmat);
+       Mat4Invert(imat, mat);
+       Mat4MulVecfl(imat, tco);
+       
+       for (ml = mb->elems.first; ml; ml=ml->next) {
+               float bmat[3][3], dist2;
+               
+               /* element rotation transform */
+               float tp[3] = {ml->x - tco[0], ml->y - tco[1], ml->z - tco[2]};
+               QuatToMat3(ml->quat, bmat);
+               Mat3Transp(bmat);       // rot.only, so inverse == transpose
+               Mat3MulVecfl(bmat, tp);
+               
+               /* MB_BALL default */
+               switch (ml->type) {
+                       case MB_ELIPSOID:
+                               tp[0] /= ml->expx, tp[1] /= ml->expy, tp[2] /= ml->expz;
+                               break;
+                       case MB_CUBE:
+                               tp[2] = (tp[2] > ml->expz) ? (tp[2] - ml->expz) : ((tp[2] < -ml->expz) ? (tp[2] + ml->expz) : 0.f);
+                               // no break, xy as plane
+                       case MB_PLANE:
+                               tp[1] = (tp[1] > ml->expy) ? (tp[1] - ml->expy) : ((tp[1] < -ml->expy) ? (tp[1] + ml->expy) : 0.f);
+                               // no break, x as tube
+                       case MB_TUBE:
+                               tp[0] = (tp[0] > ml->expx) ? (tp[0] - ml->expx) : ((tp[0] < -ml->expx) ? (tp[0] + ml->expx) : 0.f);
+               }
+               
+               /* ml->rad2 is not set */
+               dist2 = 1.f - ((tp[0]*tp[0] + tp[1]*tp[1] + tp[2]*tp[2]) / (ml->rad*ml->rad));
+               if (dist2 > 0.f)
+                       dens += (ml->flag & MB_NEGATIVE) ? -ml->s*dist2*dist2*dist2 : ml->s*dist2*dist2*dist2;
+       }
+       
+       dens -= mb->thresh;
+       return (dens < 0.f) ? 0.f : dens;
+ }
+ float vol_get_density(struct ShadeInput *shi, float *co)
+ {
+       float density = shi->mat->vol.density;
+       float density_scale = shi->mat->vol.density_scale;
+               
+       do_volume_tex(shi, co, MAP_DENSITY, NULL, &density);
+       
+       // if meta-object, modulate by metadensity without increasing it
+       if (shi->obi->obr->ob->type == OB_MBALL) {
+               const float md = metadensity(shi->obi->obr->ob, co);
+               if (md < 1.f) density *= md;
+       }
+       
+       return density * density_scale;
+ }
+ /* scattering multiplier, values above 1.0 are non-physical, 
+  * but can be useful to tweak lighting */
+ float vol_get_scattering_fac(ShadeInput *shi, float *co)
+ {
+       float scatter = shi->mat->vol.scattering;
+       float col[3] = {0.0, 0.0, 0.0};
+       
+       do_volume_tex(shi, co, MAP_SCATTERING, col, &scatter);
+       
+       return scatter;
+ }
+ /* compute emission component, amount of radiance to add per segment
+  * can be textured with 'emit' */
+ void vol_get_emission(ShadeInput *shi, float *emission_col, float *co, float density)
+ {
+       float emission = shi->mat->vol.emission;
+       VECCOPY(emission_col, shi->mat->vol.emission_col);
+       
+       do_volume_tex(shi, co, MAP_EMISSION+MAP_EMISSION_COL, emission_col, &emission);
+       
+       emission_col[0] = emission_col[0] * emission * density;
+       emission_col[1] = emission_col[1] * emission * density;
+       emission_col[2] = emission_col[2] * emission * density;
+ }
+ void vol_get_absorption(ShadeInput *shi, float *absorb_col, float *co)
+ {
+       float absorption = shi->mat->vol.absorption;
+       VECCOPY(absorb_col, shi->mat->vol.absorption_col);
+       
+       do_volume_tex(shi, co, MAP_ABSORPTION+MAP_ABSORPTION_COL, absorb_col, &absorption);
+       
+       absorb_col[0] = (1.0f - absorb_col[0]) * absorption;
+       absorb_col[1] = (1.0f - absorb_col[1]) * absorption;
+       absorb_col[2] = (1.0f - absorb_col[2]) * absorption;
+ }
+ /* phase function - determines in which directions the light 
+  * is scattered in the volume relative to incoming direction 
+  * and view direction */
+ float vol_get_phasefunc(ShadeInput *shi, short phasefunc_type, float g, float *w, float *wp)
+ {
+       const float costheta = Inpf(w, wp);
+       const float scale = M_PI;
+       
+       /*
+        * Scale constant is required, since Blender's shading system doesn't normalise for
+        * energy conservation - eg. scaling by 1/pi for a lambert shader.
+        * This makes volumes darker than other solid objects, for the same lighting intensity.
+        * To correct this, scale up the phase function values
+        * until Blender's shading system supports this better. --matt
+        */
+       
+       switch (phasefunc_type) {
+               case MA_VOL_PH_MIEHAZY:
+                       return scale * (0.5f + 4.5f * powf(0.5 * (1.f + costheta), 8.f)) / (4.f*M_PI);
+               case MA_VOL_PH_MIEMURKY:
+                       return scale * (0.5f + 16.5f * powf(0.5 * (1.f + costheta), 32.f)) / (4.f*M_PI);
+               case MA_VOL_PH_RAYLEIGH:
+                       return scale * 3.f/(16.f*M_PI) * (1 + costheta * costheta);
+               case MA_VOL_PH_HG:
+                       return scale * (1.f / (4.f * M_PI) * (1.f - g*g) / powf(1.f + g*g - 2.f * g * costheta, 1.5f));
+               case MA_VOL_PH_SCHLICK:
+               {
+                       const float k = 1.55f * g - .55f * g * g * g;
+                       const float kcostheta = k * costheta;
+                       return scale * (1.f / (4.f * M_PI) * (1.f - k*k) / ((1.f - kcostheta) * (1.f - kcostheta)));
+               }
+               case MA_VOL_PH_ISOTROPIC:
+               default:
+                       return scale * (1.f / (4.f * M_PI));
+       }
+ }
+ /* Compute transmittance = e^(-attenuation) */
+ void vol_get_transmittance_seg(ShadeInput *shi, float *tr, float stepsize, float *co, float density)
+ {
+       /* input density = density at co */
+       float tau[3] = {0.f, 0.f, 0.f};
+       float absorb[3];
+       const float scatter_dens = vol_get_scattering_fac(shi, co) * density * stepsize;
+       vol_get_absorption(shi, absorb, co);
+       
+       /* homogenous volume within the sampled distance */
+       tau[0] += scatter_dens * absorb[0];
+       tau[1] += scatter_dens * absorb[1];
+       tau[2] += scatter_dens * absorb[2];
+       
+       tr[0] *= exp(-tau[0]);
+       tr[1] *= exp(-tau[1]);
+       tr[2] *= exp(-tau[2]);
+ }
+ /* Compute transmittance = e^(-attenuation) */
+ static void vol_get_transmittance(ShadeInput *shi, float *tr, float *co, float *endco)
+ {
+       float p[3] = {co[0], co[1], co[2]};
+       float step_vec[3] = {endco[0] - co[0], endco[1] - co[1], endco[2] - co[2]};
+       //const float ambtau = -logf(shi->mat->vol.depth_cutoff);       // never zero
+       float tau[3] = {0.f, 0.f, 0.f};
+       float t0 = 0.f;
+       float t1 = Normalize(step_vec);
+       float pt0 = t0;
+       
+       t0 += shi->mat->vol.shade_stepsize * ((shi->mat->vol.stepsize_type == MA_VOL_STEP_CONSTANT) ? 0.5f : BLI_thread_frand(shi->thread));
+       p[0] += t0 * step_vec[0];
+       p[1] += t0 * step_vec[1];
+       p[2] += t0 * step_vec[2];
+       VecMulf(step_vec, shi->mat->vol.shade_stepsize);
+       for (; t0 < t1; pt0 = t0, t0 += shi->mat->vol.shade_stepsize) {
+               float absorb[3];
+               const float d = vol_get_density(shi, p);
+               const float stepd = (t0 - pt0) * d;
+               const float scatter_dens = vol_get_scattering_fac(shi, p) * stepd;
+               vol_get_absorption(shi, absorb, p);
+               
+               tau[0] += scatter_dens * absorb[0];
+               tau[1] += scatter_dens * absorb[1];
+               tau[2] += scatter_dens * absorb[2];
+               
+               //if (luminance(tau) >= ambtau) break;
+               VecAddf(p, p, step_vec);
+       }
+       
+       /* return transmittance */
+       tr[0] = expf(-tau[0]);
+       tr[1] = expf(-tau[1]);
+       tr[2] = expf(-tau[2]);
+ }
+ void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float *lacol)
+ {
+       float visifac, lv[3], lampdist;
+       float tr[3]={1.0,1.0,1.0};
+       float hitco[3], *atten_co;
+       float p;
+       float scatter_fac;
+       float shade_stepsize = vol_get_stepsize(shi, STEPSIZE_SHADE);
+       
+       if (lar->mode & LA_LAYER) if((lar->lay & shi->obi->lay)==0) return;
+       if ((lar->lay & shi->lay)==0) return;
+       if (lar->energy == 0.0) return;
+       
+       if ((visifac= lamp_get_visibility(lar, co, lv, &lampdist)) == 0.f) return;
+       
+       VecCopyf(lacol, &lar->r);
+       
+       if(lar->mode & LA_TEXTURE) {
+               shi->osatex= 0;
+               do_lamp_tex(lar, lv, shi, lacol, LA_TEXTURE);
+       }
+       VecMulf(lacol, visifac);
+       if (ELEM(lar->type, LA_SUN, LA_HEMI))
+               VECCOPY(lv, lar->vec);
+       VecMulf(lv, -1.0f);
+       
+       if (shi->mat->vol.shade_type != MA_VOL_SHADE_NONE) {
+               Isect is;
+               
+               /* find minimum of volume bounds, or lamp coord */
+               if (vol_get_bounds(shi, co, lv, hitco, &is, VOL_BOUNDS_SS)) {
+                       float dist = VecLenf(co, hitco);
 -              VlakRen *vlr = (VlakRen *)is.face;
++                      VlakRen *vlr = (VlakRen *)is.hit.face;
+                       
+                       /* simple internal shadowing */
+                       if (vlr->mat->material_type == MA_TYPE_SURFACE) {
+                               lacol[0] = lacol[1] = lacol[2] = 0.0f;
+                               return;
+                       }
+                       if (ELEM(lar->type, LA_SUN, LA_HEMI))
+                               /* infinite lights, can never be inside volume */
+                               atten_co = hitco;
+                       else if ( lampdist < dist ) {
+                               atten_co = lar->co;
+                       } else
+                               atten_co = hitco;
+                       
+                       vol_get_transmittance(shi, tr, co, atten_co);
+                       
+                       VecMulVecf(lacol, lacol, tr);
+               }
+               else {
+                       /* Point is on the outside edge of the volume,
+                        * therefore no attenuation, full transmission.
+                        * Radiance from lamp remains unchanged */
+               }
+       }
+       
+       p = vol_get_phasefunc(shi, shi->mat->vol.phasefunc_type, shi->mat->vol.phasefunc_g, shi->view, lv);
+       VecMulf(lacol, p);
+       
+       scatter_fac = vol_get_scattering_fac(shi, co);
+       VecMulf(lacol, scatter_fac);
+ }
+ /* single scattering only for now */
+ void vol_get_scattering(ShadeInput *shi, float *scatter_col, float *co, float stepsize, float density)
+ {
+       ListBase *lights;
+       GroupObject *go;
+       LampRen *lar;
+       
+       scatter_col[0] = scatter_col[1] = scatter_col[2] = 0.f;
+       
+       lights= get_lights(shi);
+       for(go=lights->first; go; go= go->next)
+       {
+               float lacol[3] = {0.f, 0.f, 0.f};
+               lar= go->lampren;
+               
+               if (lar) {
+                       vol_shade_one_lamp(shi, co, lar, lacol);
+                       VecAddf(scatter_col, scatter_col, lacol);
+               }
+       }
+ }
+       
+ /*
+ The main volumetric integrator, using an emission/absorption/scattering model.
+ Incoming radiance = 
+ outgoing radiance from behind surface * beam transmittance/attenuation
+ + added radiance from all points along the ray due to participating media
+       --> radiance for each segment = 
+               (radiance added by scattering + radiance added by emission) * beam transmittance/attenuation
+ */
+ static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float *endco)
+ {
+       float tr[3] = {1.0f, 1.0f, 1.0f};
+       float radiance[3] = {0.f, 0.f, 0.f}, d_radiance[3] = {0.f, 0.f, 0.f};
+       float stepsize = vol_get_stepsize(shi, STEPSIZE_VIEW);
+       int nsteps, s;
+       float emit_col[3], scatter_col[3] = {0.0, 0.0, 0.0};
+       float stepvec[3], step_sta[3], step_end[3], step_mid[3];
+       float density;
+       const float depth_cutoff = shi->mat->vol.depth_cutoff;
+       /* ray marching */
+       nsteps = (int)((VecLenf(co, endco) / stepsize) + 0.5);
+       
+       VecSubf(stepvec, endco, co);
+       VecMulf(stepvec, 1.0f / nsteps);
+       VecCopyf(step_sta, co);
+       VecAddf(step_end, step_sta, stepvec);
+       
+       /* get radiance from all points along the ray due to participating media */
+       for (s = 0; s < nsteps; s++) {
+               density = vol_get_density(shi, step_sta);
+               
+               /* there's only any use in shading here if there's actually some density to shade! */
+               if (density > 0.01f) {
+               
+                       /* transmittance component (alpha) */
+                       vol_get_transmittance_seg(shi, tr, stepsize, co, density);
+                       step_mid[0] = step_sta[0] + (stepvec[0] * 0.5);
+                       step_mid[1] = step_sta[1] + (stepvec[1] * 0.5);
+                       step_mid[2] = step_sta[2] + (stepvec[2] * 0.5);
+               
+                       /* incoming light via emission or scattering (additive) */
+                       vol_get_emission(shi, emit_col, step_mid, density);
+                       
+                       if (shi->obi->volume_precache)
+                               vol_get_precached_scattering(shi, scatter_col, step_mid);
+                       else
+                               vol_get_scattering(shi, scatter_col, step_mid, stepsize, density);
+                       
+                       VecMulf(scatter_col, density);
+                       VecAddf(d_radiance, emit_col, scatter_col);
+                       
+                       /*   Lv += Tr * (Lve() + Ld) */
+                       VecMulVecf(d_radiance, tr, d_radiance);
+                       VecMulf(d_radiance, stepsize);
+                       
+                       VecAddf(radiance, radiance, d_radiance);        
+               }
+               VecCopyf(step_sta, step_end);
+               VecAddf(step_end, step_end, stepvec);
+               
+               /* luminance rec. 709 */
+               if ((0.2126*tr[0] + 0.7152*tr[1] + 0.0722*tr[2]) < depth_cutoff) break; 
+       }
+       
+       /* multiply original color (behind volume) with beam transmittance over entire distance */
+       VecMulVecf(col, tr, col);       
+       VecAddf(col, col, radiance);
+       
+       /* alpha <-- transmission luminance */
+       col[3] = 1.0f -(0.2126*tr[0] + 0.7152*tr[1] + 0.0722*tr[2]);
+ }
+ /* the main entry point for volume shading */
+ static void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr, int inside_volume)
+ {
+       float hitco[3], col[4] = {0.f,0.f,0.f,0.f};
+       float *startco, *endco;
+       int trace_behind = 1;
+       const int ztransp= ((shi->depth==0) && (shi->mat->mode & MA_TRANSP) && (shi->mat->mode & MA_ZTRANSP));
+       Isect is;
+       /* check for shading an internal face a volume object directly */
+       if (inside_volume == VOL_SHADE_INSIDE)
+               trace_behind = 0;
+       else if (inside_volume == VOL_SHADE_OUTSIDE) {
+               if (shi->flippednor)
+                       inside_volume = VOL_SHADE_INSIDE;
+       }
+       
+       if (ztransp && inside_volume == VOL_SHADE_INSIDE) {
+               MatInside *mi;
+               int render_this=0;
+               
+               /* don't render the backfaces of ztransp volume materials.
+                
+                * volume shading renders the internal volume from between the
+                * near view intersection of the solid volume to the
+                * intersection on the other side, as part of the shading of
+                * the front face.
+                
+                * Because ztransp renders both front and back faces independently
+                * this will double up, so here we prevent rendering the backface as well, 
+                * which would otherwise render the volume in between the camera and the backface
+                * --matt */
+               
+               for (mi=R.render_volumes_inside.first; mi; mi=mi->next) {
+                       /* weak... */
+                       if (mi->ma == shi->mat) render_this=1;
+               }
+               if (!render_this) return;
+       }
+       
+       if (inside_volume == VOL_SHADE_INSIDE)
+       {
+               startco = shi->camera_co;
+               endco = shi->co;
+               
+               if (trace_behind) {
+                       if (!ztransp)
+                               /* trace behind the volume object */
+                               vol_trace_behind(shi, shi->vlr, endco, col);
+               } else {
+                       /* we're tracing through the volume between the camera 
+                        * and a solid surface, so use that pre-shaded radiance */
+                       QUATCOPY(col, shr->combined);
+               }
+               
+               /* shade volume from 'camera' to 1st hit point */
+               volumeintegrate(shi, col, startco, endco);
+       }
+       /* trace to find a backface, the other side bounds of the volume */
+       /* (ray intersect ignores front faces here) */
+       else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH))
+       {
 -                              vol_trace_behind(shi, (VlakRen *)is.face, endco, col);
++              VlakRen *vlr = (VlakRen *)is.hit.face;
+               
+               startco = shi->co;
+               endco = hitco;
+               
+               if (!ztransp) {
+                       /* if it's another face in the same material */
+                       if (vlr->mat == shi->mat) {
+                               /* trace behind the 2nd (raytrace) hit point */
++                              vol_trace_behind(shi, (VlakRen *)is.hit.face, endco, col);
+                       } else {
+                               shade_intersection(shi, col, &is);
+                       }
+               }
+               
+               /* shade volume from 1st hit point to 2nd hit point */
+               volumeintegrate(shi, col, startco, endco);
+       }
+       
+       if (ztransp)
+               col[3] = col[3]>1.f?1.f:col[3];
+       else
+               col[3] = 1.f;
+       
+       VecCopyf(shr->combined, col);
+       shr->alpha = col[3];
+       
+       VECCOPY(shr->diff, shr->combined);
+ }
+ /* Traces a shadow through the object, 
+  * pretty much gets the transmission over a ray path */
+ void shade_volume_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct Isect *last_is)
+ {
+       float hitco[3];
+       float tr[3] = {1.0,1.0,1.0};
+       Isect is;
+       float shade_stepsize = vol_get_stepsize(shi, STEPSIZE_SHADE);
+       float *startco, *endco;
+       float density=0.f;
+       memset(shr, 0, sizeof(ShadeResult));
+       
+       /* if 1st hit normal is facing away from the camera, 
+        * then we're inside the volume already. */
+       if (shi->flippednor) {
+               startco = last_is->start;
+               endco = shi->co;
+       }
+       /* trace to find a backface, the other side bounds of the volume */
+       /* (ray intersect ignores front faces here) */
+       else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH)) {
+               startco = shi->co;
+               endco = hitco;
+       }
+       else {
+               shr->combined[0] = shr->combined[1] = shr->combined[2] = 0.f;
+               shr->alpha = shr->combined[3] = 1.f;
+               return;
+       }
+       
+       density = vol_get_density(shi, startco);
+       vol_get_transmittance(shi, tr, startco, endco);
+       
+       VecCopyf(shr->combined, tr);
+       shr->combined[3] = 1.0f -(0.2126*tr[0] + 0.7152*tr[1] + 0.0722*tr[2]);
+       shr->alpha = shr->combined[3];
+ }
+ /* delivers a fully filled in ShadeResult, for all passes */
+ void shade_volume_outside(ShadeInput *shi, ShadeResult *shr)
+ {
+       memset(shr, 0, sizeof(ShadeResult));
+       volume_trace(shi, shr, VOL_SHADE_OUTSIDE);
+ }
+ void shade_volume_inside(ShadeInput *shi, ShadeResult *shr)
+ {
+       MatInside *m;
+       Material *mat_backup;
+       ObjectInstanceRen *obi_backup;
+       float prev_alpha = shr->alpha;
+       
+       //if (BLI_countlist(&R.render_volumes_inside) == 0) return;
+       
+       /* XXX: extend to multiple volumes perhaps later */
+       mat_backup = shi->mat;
+       obi_backup = shi->obi;
+       
+       m = R.render_volumes_inside.first;
+       shi->mat = m->ma;
+       shi->obi = m->obi;
+       shi->obr = m->obi->obr;
+       
+       volume_trace(shi, shr, VOL_SHADE_INSIDE);
+       shr->alpha += prev_alpha;
+       CLAMP(shr->alpha, 0.f, 1.f);
+       
+       shi->mat = mat_backup;
+       shi->obi = obi_backup;
+       shi->obr = obi_backup->obr;
+ }
index 46786b159c07206593f311cd269bf2ce464ebd2a,9a268f8be17ae785a85199f9f767b03d7b5bfe2f..9664c6f28ffda4075a48fb2892c251f480d998b3
@@@ -208,10 -208,7 +208,10 @@@ void WM_exit(bContext *C
        
        fastshade_free_render();        /* shaded view */
        ED_preview_free_dbase();        /* frees a Main dbase, before free_blender! */
 -      wm_free_reports(C);                     /* before free_blender! - since the ListBases get freed there */
 +
 +      if(C && CTX_wm_manager(C))
 +              wm_free_reports(C);                     /* before free_blender! - since the ListBases get freed there */
 +              
        free_blender();                         /* blender.c, does entire library and spacetypes */
  //    free_matcopybuf();
        free_anim_copybuf();
  
        CTX_free(C);
        
+       SYS_DeleteSystem(SYS_GetSystem());
        if(MEM_get_memory_blocks_in_use()!=0) {
                printf("Error Totblock: %d\n", MEM_get_memory_blocks_in_use());
                MEM_printmemlist();
        }
  #endif 
        
-       
-       SYS_DeleteSystem(SYS_GetSystem());
-       
        exit(G.afbreek==1);
  }