Code

A modification of pixops_mix that allows for input images that extend beyond the...
authorJasper van de Gronde <th.v.d.gronde@hccnet.nl>
Wed, 4 Aug 2010 15:39:04 +0000 (17:39 +0200)
committerJasper van de Gronde <th.v.d.gronde@hccnet.nl>
Wed, 4 Aug 2010 15:39:04 +0000 (17:39 +0200)
src/display/nr-filter-pixops.h

index b2db7067ad0243bf96d764eebe68ed7ee9d5c78d..22b1a55cd51e2dc3ed455eee325cfe279698299d 100644 (file)
@@ -2,6 +2,7 @@
 #define __NR_FILTER_PIXOPS_H__
 
 #include "libnr/nr-pixblock.h"
+#include <algorithm>
 
 /*
  * Per-pixel image manipulation functions.
@@ -41,96 +42,47 @@ void pixops_mix(NRPixBlock &out, NRPixBlock &in1, NRPixBlock &in2) {
     unsigned char *out_data = NR_PIXBLOCK_PX(&out);
     unsigned char zero_rgba[4] = {0, 0, 0, 0};
 
-    if (in1.area.y0 < in2.area.y0) {
-        // in1 begins before in2 on y-axis
-        for (int y = in1.area.y0 ; y < in2.area.y0 ; y++) {
-            int out_line = (y - out.area.y0) * out.rs;
-            int in_line = (y - in1.area.y0) * in1.rs;
-            for (int x = in1.area.x0 ; x < in1.area.x1 ; x++) {
-                blend(out_data + out_line + 4 * (x - out.area.x0),
-                      in1_data + in_line + 4 * (x - in1.area.x0),
-                      zero_rgba);
-            }
-        }
-    } else if (in1.area.y0 > in2.area.y0) {
-        // in2 begins before in1 on y-axis
-        for (int y = in2.area.y0 ; y < in1.area.y0 ; y++) {
-            int out_line = (y - out.area.y0) * out.rs;
-            int in_line = (y - in2.area.y0) * in2.rs;
-            for (int x = in2.area.x0 ; x < in2.area.x1 ; x++) {
-                blend(out_data + out_line + 4 * (x - out.area.x0),
-                      zero_rgba,
-                      in2_data + in_line + 4 * (x - in2.area.x0));
-            }
-        }
-    }
-
-    for (int y = std::max(in1.area.y0, in2.area.y0) ;
-         y < std::min(in1.area.y1, in2.area.y1) ; ++y) {
-        int out_line = (y - out.area.y0) * out.rs;
-        int in1_line = (y - in1.area.y0) * in1.rs;
-        int in2_line = (y - in2.area.y0) * in2.rs;
+    // Possible scenarios (omitting cases where an interval is empty and those which are the same by interchanging 1 and 2):
+    // 01020, 01320, 01310 (no overlap, partial overlap, full overlap)
+    int out_y0 = out.area.y0;
+    int out_y1 = std::max(out.area.y1,out_y0); // Enforce sanity
+    int in1_y0 = std::min(std::max(in1.area.y0,out_y0),out_y1);
+    int in2_y0 = std::min(std::max(in2.area.y0,out_y0),out_y1);
+    int in1_y1 = std::min(std::max(in1.area.y1,in1_y0),out_y1);
+    int in2_y1 = std::min(std::max(in2.area.y1,in2_y0),out_y1);
+    int min_in_y0 = std::min(in1_y0,in2_y0);
+    int max_in_y0 = std::max(in1_y0,in2_y0);
+    int min_in_y1 = std::min(in1_y1,in2_y1);
+    int max_in_y1 = std::max(in1_y1,in2_y1);
+    int const yBound[6] = {out_y0, min_in_y0, std::min(max_in_y0,min_in_y1), std::max(max_in_y0,min_in_y1), max_in_y1, out_y1};
+    bool const in1_zero_y[5] = {true, in1_y0>yBound[1], in1_y0>yBound[2] || in1_y1<=yBound[2], in1_y1<=yBound[3], true};
+    bool const in2_zero_y[5] = {true, in2_y0>yBound[1], in2_y0>yBound[2] || in2_y1<=yBound[2], in2_y1<=yBound[3], true};
 
-        if (in1.area.x0 < in2.area.x0) {
-            // in1 begins before in2 on x-axis
-            for (int x = in1.area.x0 ; x < in2.area.x0 ; ++x) {
-                blend(out_data + out_line + 4 * (x - out.area.x0),
-                      in1_data + in1_line + 4 * (x - in1.area.x0),
-                      zero_rgba);
-            }
-        } else if (in1.area.x0 > in2.area.x0) {
-            // in2 begins before in1 on x-axis
-            for (int x = in2.area.x0 ; x < in1.area.x0 ; ++x) {
-                blend(out_data + out_line + 4 * (x - out.area.x0),
-                      zero_rgba,
-                      in2_data + in2_line + 4 * (x - in2.area.x0));
-            }
-        }
+    int out_x0 = out.area.x0;
+    int out_x1 = std::max(out.area.x1,out_x0);
+    int in1_x0 = std::min(std::max(in1.area.x0,out_x0),out_x1);
+    int in2_x0 = std::min(std::max(in2.area.x0,out_x0),out_x1);
+    int in1_x1 = std::min(std::max(in1.area.x1,in1_x0),out_x1);
+    int in2_x1 = std::min(std::max(in2.area.x1,in2_x0),out_x1);
+    int min_in_x0 = std::min(in1_x0,in2_x0);
+    int max_in_x0 = std::max(in1_x0,in2_x0);
+    int min_in_x1 = std::min(in1_x1,in2_x1);
+    int max_in_x1 = std::max(in1_x1,in2_x1);
+    int const xBound[6] = {out_x0, min_in_x0, std::min(max_in_x0,min_in_x1), std::max(max_in_x0,min_in_x1), max_in_x1, out_x1};
+    bool const in1_zero_x[5] = {true, in1_x0>xBound[1], in1_x0>xBound[2] || in1_x1<=xBound[2], in1_x1<=xBound[3], true};
+    bool const in2_zero_x[5] = {true, in2_x0>xBound[1], in2_x0>xBound[2] || in2_x1<=xBound[2], in2_x1<=xBound[3], true};
 
-        for (int x = std::max(in1.area.x0, in2.area.x0) ;
-             x < std::min(in1.area.x1, in2.area.x1) ; ++x) {
-            blend(out_data + out_line + 4 * (x - out.area.x0),
-                  in1_data + in1_line + 4 * (x - in1.area.x0),
-                  in2_data + in2_line + 4 * (x - in2.area.x0));
-        }
-
-        if (in1.area.x1 > in2.area.x1) {
-            // in1 ends after in2 on x-axis
-            for (int x = in2.area.x1 ; x < in1.area.x1 ; ++x) {
-                blend(out_data + out_line + 4 * (x - out.area.x0),
-                      in1_data + in1_line + 4 * (x - in1.area.x0),
-                      zero_rgba);
-            }
-        } else if (in1.area.x1 < in2.area.x1) {
-            // in2 ends after in1 on x-axis
-            for (int x = in1.area.x1 ; x < in2.area.x1 ; ++x) {
-                blend(out_data + out_line + 4 * (x - out.area.x0),
-                      zero_rgba,
-                      in2_data + in2_line + 4 * (x - in2.area.x0));
-            }
-        }
-    }
-
-    if (in1.area.y1 > in2.area.y1) {
-        // in1 ends after in2 on y-axis
-        for (int y = in2.area.y1 ; y < in1.area.y1 ; y++) {
-            int out_line = (y - out.area.y0) * out.rs;
-            int in_line = (y - in1.area.y0) * in1.rs;
-            for (int x = in1.area.x0 ; x < in1.area.x1 ; x++) {
-                blend(out_data + out_line + 4 * (x - out.area.x0),
-                      in1_data + in_line + 4 * (x - in1.area.x0),
-                      zero_rgba);
-            }
-        }
-    } else if (in1.area.y1 < in2.area.y1) {
-        // in2 ends after in1 on y-axis
-        for (int y = in1.area.y1 ; y < in2.area.y1 ; y++) {
+    for (int yr = 0 ; yr < 5 ; yr++) {
+        for(int y = yBound[yr] ; y < yBound[yr+1] ; y++) {
             int out_line = (y - out.area.y0) * out.rs;
-            int in_line = (y - in2.area.y0) * in2.rs;
-            for (int x = in2.area.x0 ; x < in2.area.x1 ; x++) {
-                blend(out_data + out_line + 4 * (x - out.area.x0),
-                      zero_rgba,
-                      in2_data + in_line + 4 * (x - in2.area.x0));
+            int in1_line = (y - in1.area.y0) * in1.rs;
+            int in2_line = (y - in2.area.y0) * in2.rs;
+            for (int xr = 0 ; xr < 5 ; xr++) {
+                for(int x = xBound[xr] ; x < xBound[xr+1] ; x++) {
+                    blend(out_data + out_line + 4 * (x - out.area.x0),
+                        (in1_zero_x[xr]||in1_zero_y[yr]) ? zero_rgba : (in1_data + in1_line + 4 * (x - in1.area.x0)),
+                        (in2_zero_x[xr]||in2_zero_y[yr]) ? zero_rgba : (in2_data + in2_line + 4 * (x - in2.area.x0)));
+                }
             }
         }
     }