Merging r48981 through r48984 from trunk into soc-2011-tomato
[blender.git] / source / blender / blenkernel / intern / mask.c
index 7eb06a1b9caa9196dff5de993ee422e5aa9b2a5c..d86e2c72ebede9121a43e1a7b0f8882112285ff7 100644 (file)
 
 #include "raskter.h"
 
+#ifdef USE_MANGO_MASK_CACHE_HACK
+
+#include "BLI_threads.h"
+
+typedef struct MaskRasterCache {
+       float *buffer;
+       int width, height;
+       short do_aspect_correct;
+       short do_mask_aa;
+       short do_feather;
+
+       ListBase layers;
+} MaskRasterCache;
+#endif
+
 static MaskSplinePoint *mask_spline_point_next(MaskSpline *spline, MaskSplinePoint *points_array, MaskSplinePoint *point)
 {
        if (point == &points_array[spline->tot_point - 1]) {
@@ -411,7 +426,7 @@ typedef struct FeatherEdgesBucket {
 
 static void feather_bucket_add_edge(FeatherEdgesBucket *bucket, int start, int end)
 {
-       const int alloc_delta = 32;
+       const int alloc_delta = 20;
 
        if (bucket->tot_segment >= bucket->alloc_segment) {
                if (!bucket->segments) {
@@ -463,16 +478,24 @@ static void feather_bucket_check_intersect(float (*feather_points)[2], int tot_f
                                }
                        }
                        else {
-                               for (k = 0; k <= check_a; k++) {
-                                       copy_v2_v2(feather_points[k], p);
+                               if (cur_b < check_a) {
+                                       /* special case when intersection happens with first segment */
+                                       for (k = cur_b; k <= check_a; k++) {
+                                               copy_v2_v2(feather_points[k], p);
+                                       }
                                }
+                               else {
+                                       for (k = 0; k <= check_a; k++) {
+                                               copy_v2_v2(feather_points[k], p);
+                                       }
 
-                               if (cur_b != 0) {
                                        for (k = cur_b; k < tot_feather_point; k++) {
                                                copy_v2_v2(feather_points[k], p);
                                        }
                                }
                        }
+
+                       break;
                }
        }
 }
@@ -1337,6 +1360,7 @@ void BKE_mask_layer_free(MaskLayer *masklay)
        MEM_freeN(masklay);
 }
 
+
 void BKE_mask_layer_free_list(ListBase *masklayers)
 {
        MaskLayer *masklay = masklayers->first;
@@ -1349,11 +1373,44 @@ void BKE_mask_layer_free_list(ListBase *masklayers)
 
                masklay = masklay_next;
        }
+
+}
+
+#ifdef USE_MANGO_MASK_CACHE_HACK
+void BKE_mask_raster_cache_free(Mask *mask)
+{
+       MaskRasterCache *cache = mask->raster_cache;
+
+       if (cache) {
+               MaskLayer *layer;
+
+               layer = cache->layers.first;
+               while (layer) {
+                       MaskLayer *layer_next = layer->next;
+
+                       BKE_mask_layer_free(layer);
+                       layer = layer_next;
+               }
+
+               MEM_freeN(cache->buffer);
+               MEM_freeN(cache);
+
+               mask->raster_cache = NULL;
+       }
 }
+#endif
 
 void BKE_mask_free(Mask *mask)
 {
        BKE_mask_layer_free_list(&mask->masklayers);
+
+#ifdef USE_MANGO_MASK_CACHE_HACK
+       if (mask->raster_cache) {
+               BKE_mask_raster_cache_free(mask);
+
+               mask->raster_cache = NULL;
+       }
+#endif
 }
 
 void BKE_mask_unlink(Main *bmain, Mask *mask)
@@ -2366,16 +2423,157 @@ int BKE_mask_get_duration(Mask *mask)
        return MAX2(1, mask->efra - mask->sfra);
 }
 
+#ifdef USE_MANGO_MASK_CACHE_HACK
+static int mask_point_compare(MaskSplinePoint *point_a, MaskSplinePoint *point_b)
+{
+       if (point_a->tot_uw != point_b->tot_uw) {
+               return FALSE;
+       }
+
+       if (memcmp(&point_a->bezt, &point_b->bezt, sizeof(BezTriple))) {
+               return FALSE;
+       }
+
+       if (memcmp(&point_a->uw, &point_b->uw, 2 * point_a->tot_uw * sizeof(float))) {
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+static int mask_points_compare(MaskSplinePoint *points_a, MaskSplinePoint *points_b, int tot_point)
+{
+       MaskSplinePoint *point_a = points_a;
+       MaskSplinePoint *point_b = points_b;
+       int a = tot_point;
+
+       /* deform points can be NULL */
+       if (point_a == NULL || point_b == NULL) {
+               return ((point_a == NULL) && (point_b == NULL));
+       }
+
+       while (a--) {
+               if (!mask_point_compare(point_a, point_b)) {
+                       return FALSE;
+               }
+
+               point_a++;
+               point_b++;
+       }
+
+       return TRUE;
+}
+
+static int mask_spline_compare(MaskSpline *spline_a, MaskSpline *spline_b)
+{
+       if (spline_a->flag != spline_b->flag ||
+           spline_a->tot_point != spline_b->tot_point ||
+           spline_a->weight_interp != spline_b->weight_interp)
+       {
+               return FALSE;
+       }
+
+       if (!mask_points_compare(spline_a->points, spline_b->points, spline_a->tot_point)) {
+               return FALSE;
+       }
+
+       return mask_points_compare(spline_a->points_deform, spline_b->points_deform, spline_a->tot_point);
+}
+
+static int mask_splines_compare(ListBase *base_a, ListBase *base_b)
+{
+       MaskSpline *spline_a, *spline_b;
+
+       for (spline_a = base_a->first, spline_b = base_b->first;
+            spline_a && spline_b;
+            spline_a = spline_a->next, spline_b = spline_b->next)
+       {
+               if (!mask_spline_compare(spline_a, spline_b)) {
+                       return FALSE;
+               }
+       }
+
+       if (spline_a || spline_b)
+               return FALSE;
+
+       return TRUE;
+}
+
+static int mask_layer_compare(MaskLayer *layer_a, MaskLayer *layer_b)
+{
+       if (layer_a->alpha != layer_b->alpha ||
+           layer_a->blend != layer_b->blend ||
+           layer_a->blend_flag != layer_b->blend_flag ||
+           layer_a->flag != layer_b->flag ||
+           layer_a->restrictflag != layer_b->restrictflag)
+       {
+               return FALSE;
+       }
+
+       if (strcmp(layer_a->name, layer_b->name))
+               return FALSE;
+
+       return mask_splines_compare(&layer_a->splines, &layer_b->splines);
+}
+
+static int mask_layers_compare(ListBase *base_a, ListBase *base_b)
+{
+       MaskLayer *layer_a, *layer_b;
+
+       for (layer_a = base_a->first, layer_b = base_b->first;
+            layer_a && layer_b;
+            layer_a = layer_a->next, layer_b = layer_b->next)
+       {
+               if (!mask_layer_compare(layer_a, layer_b)) {
+                       return FALSE;
+               }
+       }
+
+       if (layer_a || layer_b)
+               return FALSE;
+
+       return TRUE;
+}
+#endif
+
 /* rasterization */
-void BKE_mask_rasterize_layers(ListBase *masklayers, int width, int height, float *buffer,
+
+/* XXX: mask is only passed here to access rasterization cache
+ *      this MUST be removed as soon as tile-based rasterization would be here
+ */
+void BKE_mask_rasterize_layers(Mask *mask, ListBase *masklayers, int width, int height, float *buffer,
                                const short do_aspect_correct, const short do_mask_aa,
                                const short do_feather)
 {
+       MaskRasterCache *cache = mask->raster_cache;
        MaskLayer *masklay;
 
        /* temp blending buffer */
        const int buffer_size = width * height;
-       float *buffer_tmp = MEM_mallocN(sizeof(float) * buffer_size, __func__);
+       float *buffer_tmp;
+
+#ifdef USE_MANGO_MASK_CACHE_HACK
+       BLI_lock_thread(LOCK_CUSTOM1);
+
+       if (cache &&
+           cache->width == width &&
+           cache->height == height &&
+           cache->do_aspect_correct == do_aspect_correct &&
+           cache->do_mask_aa == do_mask_aa &&
+           cache->do_feather == do_feather &&
+           mask_layers_compare(&cache->layers, &mask->masklayers))
+       {
+               memcpy(buffer, cache->buffer, sizeof(float) * buffer_size);
+
+               BLI_unlock_thread(LOCK_CUSTOM1);
+
+               return;
+       }
+
+       BLI_unlock_thread(LOCK_CUSTOM1);
+#endif
+
+       buffer_tmp = MEM_mallocN(sizeof(float) * buffer_size, __func__);
 
        for (masklay = masklayers->first; masklay; masklay = masklay->next) {
                MaskSpline *spline;
@@ -2501,6 +2699,30 @@ void BKE_mask_rasterize_layers(ListBase *masklayers, int width, int height, floa
                clamp_vn_vn(buffer, buffer_size);
        }
        MEM_freeN(buffer_tmp);
+
+#ifdef USE_MANGO_MASK_CACHE_HACK
+       BLI_lock_thread(LOCK_CUSTOM1);
+
+       BKE_mask_raster_cache_free(mask);
+
+       cache = MEM_callocN(sizeof(MaskRasterCache), "mask raster cache");
+
+       cache->buffer = MEM_mallocN(sizeof(float) * buffer_size, "mask raster cache buffer");
+
+       BKE_mask_layer_copy_list(&cache->layers, masklayers);
+
+       memcpy(cache->buffer, buffer, sizeof(float) * buffer_size);
+
+       cache->width = width;
+       cache->height = height;
+       cache->do_aspect_correct = do_aspect_correct;
+       cache->do_mask_aa = do_mask_aa;
+       cache->do_feather = do_feather;
+
+       mask->raster_cache = cache;
+
+       BLI_unlock_thread(LOCK_CUSTOM1);
+#endif
 }
 
 #ifdef __PLX_RASKTER_MT__
@@ -2578,5 +2800,5 @@ void BKE_mask_rasterize(Mask *mask, int width, int height, float *buffer,
                         const short do_aspect_correct, const short do_mask_aa,
                         const short do_feather)
 {
-       BKE_mask_rasterize_layers(&mask->masklayers, width, height, buffer, do_aspect_correct, do_mask_aa, do_feather);
+       BKE_mask_rasterize_layers(mask, &mask->masklayers, width, height, buffer, do_aspect_correct, do_mask_aa, do_feather);
 }