Code

fix by kur9kin for endless loop from bug 212332
[inkscape.git] / src / display / nr-filter-specularlighting.cpp
index 565fa5e057b5101ef8c70672d141765d321963ef..677f93dded1f355c39c02c59dc459aeecdaca389 100644 (file)
@@ -18,6 +18,7 @@
 #include "display/nr-filter-specularlighting.h"
 #include "display/nr-filter-getalpha.h"
 #include "display/nr-filter-slot.h"
+#include "display/nr-filter-units.h"
 #include "display/nr-filter-utils.h"
 #include "display/nr-light.h"
 #include "libnr/nr-blit.h"
@@ -28,7 +29,7 @@
 
 namespace NR {
 
-FilterSpecularLighting::FilterSpecularLighting() 
+FilterSpecularLighting::FilterSpecularLighting()
 {
     light_type = NO_LIGHT;
     specularConstant = 1;
@@ -46,8 +47,8 @@ FilterSpecularLighting::~FilterSpecularLighting()
 
 //Investigating Phong Lighting model we should not take N.H but
 //R.E which equals to 2*N.H^2 - 1
-//replace the second line by 
-//gdouble scal = scalar_product((N), (H)); scal = 2 * scal * scal - 1;\
+//replace the second line by
+//gdouble scal = scalar_product((N), (H)); scal = 2 * scal * scal - 1;
 //to get the expected formula
 #define COMPUTE_INTER(inter, H, N, ks, speculaExponent) \
 do {\
@@ -58,12 +59,17 @@ do {\
         (inter) = (ks) * std::pow(scal, (specularExponent));\
 }while(0)
 
-int FilterSpecularLighting::render(FilterSlot &slot, Matrix const &trans) {
-    NRPixBlock *in = filter_get_alpha(slot.get(_input));
+int FilterSpecularLighting::render(FilterSlot &slot, FilterUnits const &units) {
+    NRPixBlock *in = slot.get(_input);
+    if (!in) {
+        g_warning("Missing source image for feSpecularLighting (in=%d)", _input);
+        return 1;
+    }
+
     NRPixBlock *out = new NRPixBlock;
 
     //Fvector *L = NULL; //vector to the light
-    
+
     int w = in->area.x1 - in->area.x0;
     int h = in->area.y1 - in->area.y0;
     int x0 = in->area.x0;
@@ -74,12 +80,12 @@ int FilterSpecularLighting::render(FilterSlot &slot, Matrix const &trans) {
     int dx = 1; //TODO setup
     int dy = 1; //TODO setup
     //surface scale
-    //TODO for the time being, assumes userSpaceOnUse
+    Matrix trans = units.get_matrix_primitiveunits2pb();
     gdouble ss = surfaceScale * trans[0];
     gdouble ks = specularConstant; //diffuse lighting constant
     Fvector L, N, LC, H;
     gdouble inter;
-    
+
     nr_pixblock_setup_fast(out, in->mode,
             in->area.x0, in->area.y0, in->area.x1, in->area.y1,
             true);
@@ -87,7 +93,7 @@ int FilterSpecularLighting::render(FilterSlot &slot, Matrix const &trans) {
     unsigned char *data_o = NR_PIXBLOCK_PX (out);
     //No light, nothing to do
     switch (light_type) {
-        case DISTANT_LIGHT:  
+        case DISTANT_LIGHT:
             //the light vector is constant
             {
             DistantLight *dl = new DistantLight(light.distant, lighting_color);
@@ -113,9 +119,9 @@ int FilterSpecularLighting::render(FilterSlot &slot, Matrix const &trans) {
             PointLight *pl = new PointLight(light.point, lighting_color, trans);
             pl->light_components(LC);
         //TODO we need a reference to the filter to determine primitiveUnits
-        //slot._arena_item->filter seems to be ok on simple examples
-        //for now assume userSpaceOnUse
         //if objectBoundingBox is used, use a different matrix for light_vector
+        // UPDATE: trans is now correct matrix from primitiveUnits to
+        // pixblock coordinates
             //finish the work
             for (i = 0, j = 0; i < w*h; i++) {
                 compute_surface_normal(N, ss, in, i / w, i % w, dx, dy);
@@ -125,7 +131,7 @@ int FilterSpecularLighting::render(FilterSlot &slot, Matrix const &trans) {
                         ss * (double) data_i[4*i+3]/ 255);
                 normalized_sum(H, L, EYE_VECTOR);
                 COMPUTE_INTER(inter, N, H, ks, specularExponent);
-                
+
                 data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_RED]);
                 data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_GREEN]);
                 data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_BLUE]);
@@ -139,9 +145,9 @@ int FilterSpecularLighting::render(FilterSlot &slot, Matrix const &trans) {
             {
             SpotLight *sl = new SpotLight(light.spot, lighting_color, trans);
         //TODO we need a reference to the filter to determine primitiveUnits
-        //slot._arena_item->filter seems to be ok on simple examples
-        //for now assume userSpaceOnUse
         //if objectBoundingBox is used, use a different matrix for light_vector
+        // UPDATE: trans is now correct matrix from primitiveUnits to
+        // pixblock coordinates
             //finish the work
             for (i = 0, j = 0; i < w*h; i++) {
                 compute_surface_normal(N, ss, in, i / w, i % w, dx, dy);
@@ -152,7 +158,7 @@ int FilterSpecularLighting::render(FilterSlot &slot, Matrix const &trans) {
                 sl->light_components(LC, L);
                 normalized_sum(H, L, EYE_VECTOR);
                 COMPUTE_INTER(inter, N, H, ks, specularExponent);
-                
+
                 data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_RED]);
                 data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_GREEN]);
                 data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_BLUE]);
@@ -171,14 +177,18 @@ int FilterSpecularLighting::render(FilterSlot &slot, Matrix const &trans) {
             out->empty = false;
             }
     }
-        
+
     //finishing
     slot.set(_output, out);
-    nr_pixblock_release(in);
-    delete in;
+    //nr_pixblock_release(in);
+    //delete in;
     return 0;
 }
 
+FilterTraits FilterSpecularLighting::get_input_traits() {
+    return TRAIT_PARALLER;
+}
+
 } /* namespace NR */
 
 /*