Code

Added a bunch of comments to filter effects rendering code
authorkiirala <kiirala@users.sourceforge.net>
Tue, 18 Jul 2006 10:35:54 +0000 (10:35 +0000)
committerkiirala <kiirala@users.sourceforge.net>
Tue, 18 Jul 2006 10:35:54 +0000 (10:35 +0000)
src/display/nr-filter-primitive.cpp
src/display/nr-filter-slot.h
src/display/nr-filter.cpp
src/display/pixblock-scaler.cpp
src/display/pixblock-scaler.h

index 556812db59b8bd45f9afdf4430c65a1bf9097375..9ea721d3beb44ad3313abba7b3fc5adea2c1d12a 100644 (file)
@@ -23,6 +23,8 @@ FilterPrimitive::FilterPrimitive()
     _input = NR_FILTER_SLOT_NOT_SET;
     _output = NR_FILTER_SLOT_NOT_SET;
 
+    // These defaults are according to SVG standard.
+    // NB: SVGLength.set takes prescaled percent values: 1 means 100%
     _region_x.set(SVGLength::PERCENT, 0, 0);
     _region_y.set(SVGLength::PERCENT, 0, 0);
     _region_width.set(SVGLength::PERCENT, 1, 0);
@@ -34,6 +36,7 @@ FilterPrimitive::~FilterPrimitive()
     // Nothing to do here
 }
 
+/** Wrapper function for rendering with C-style matrices. */
 int FilterPrimitive::render(FilterSlot &slot, NRMatrix const *trans) {
     if(trans) {
         return this->render(slot, *trans);
index 74cf7e003a1cf869576eec371d108ae26cbd6697..13ce1afe20fff919619db5fc2b9d8ac4d2f97826 100644 (file)
@@ -20,13 +20,35 @@ namespace NR {
 
 class FilterSlot {
 public:
+    /** Creates a new FilterSlot object, with two slots. */
     FilterSlot();
+    /** Creates a new FilterSlot object, with specified amount of slots */
     FilterSlot(int slots);
+    /** Destroys the FilterSlot object and all its contents */
     ~FilterSlot();
 
+    /** Returns the pixblock in specified slot.
+     * Parameter 'slot' may be either an positive integer or one of
+     * pre-defined filter slot types: NR_FILTER_SLOT_NOT_SET,
+     * NR_FILTER_SOURCEGRAPHIC, NR_FILTER_SOURCEALPHA,
+     * NR_FILTER_BACKGROUNDIMAGE, NR_FILTER_BACKGROUNDALPHA,
+     * NR_FILTER_FILLPAINT, NR_FILTER_SOURCEPAINT.
+     * If the defined filter slot is not set before, this function
+     * returns NULL. Also, that filter slot is created in process.
+     */
     NRPixBlock *get(int slot);
+
+    /** Sets or re-sets the pixblock associated with given slot.
+     * If there was a pixblock already assigned with this slot,
+     * that pixblock is destroyed.
+     * Pixblocks passed to this function should be considered
+     * managed by this FilterSlot object.
+     * Pixblocks passed to this function should be reserved with
+     * c++ -style new-operator.
+     */
     void set(int slot, NRPixBlock *pb);
 
+    /** Returns the number of slots in use. */
     int get_slot_count();
 
 private:
@@ -36,6 +58,9 @@ private:
 
     int _last_out;
 
+    /** Returns the table index of given slot. If that slot dows not exist,
+     * it is created. Table index can be used to read the correct
+     * pixblock from _slot */
     int _get_index(int slot);
 };
 
index 6c57f3200a5a6a03518b0c44c609afdeee78b8b8..db1e9d8db596df27c093c8ce74d83e165534365f 100644 (file)
@@ -54,13 +54,19 @@ Filter::Filter(int n)
 
 void Filter::_common_init() {
     _slot_count = 1;
+    // Having "not set" here as value means the output of last filter
+    // primitive will be used as output of this filter
     _output_slot = NR_FILTER_SLOT_NOT_SET;
 
+    // These are the default values for filter region,
+    // as specified in SVG standard
+    // NB: SVGLength.set takes prescaled percent values: -.10 means -10%
     _region_x.set(SVGLength::PERCENT, -.10, 0);
     _region_y.set(SVGLength::PERCENT, -.10, 0);
     _region_width.set(SVGLength::PERCENT, 1.20, 0);
     _region_height.set(SVGLength::PERCENT, 1.20, 0);
 
+    // Filter resolution, negative value here stands for "automatic"
     _x_pixels = -1.0;
     _y_pixels = -1.0;
 
@@ -80,6 +86,9 @@ int Filter::render(NRArenaItem const *item, NRPixBlock *pb)
     Matrix trans = *item->ctm;
     FilterSlot slot(_slot_count);
     NRPixBlock *in = new NRPixBlock;
+
+    // First, if filter resolution is not set to automatic, we should
+    // scale the input image to correct resolution
     if (_x_pixels >= 0) {
         /* If filter resolution is zero, the object should not be rendered */
         if (_x_pixels == 0 || _y_pixels == 0) {
@@ -89,8 +98,14 @@ int Filter::render(NRArenaItem const *item, NRPixBlock *pb)
             memset(NR_PIXBLOCK_PX(pb), 0, size);
             return 0;
         }
+        // Resolution is specified as pixel length of our internal buffer.
+        // Though, we might not be rendering the whole object at time,
+        // so we need to calculate the correct pixel size
         int x_len = (int)round(((pb->area.x1 - pb->area.x0) * _x_pixels) / (item->bbox.x1 - item->bbox.x0));
         if (x_len < 1) x_len = 1;
+        // If y-resolution is also set, count y-area in the same way as x-area
+        // Otherwise, make y-area so, that aspect ratio of input pixblock and
+        // internal pixblock are the same.
         int y_len;
         if (_y_pixels > 0) {
             y_len = (int)round(((pb->area.y1 - pb->area.y0) * _y_pixels) / (item->bbox.y1 - item->bbox.y0));
@@ -104,6 +119,7 @@ int Filter::render(NRArenaItem const *item, NRPixBlock *pb)
                           y_len / (double)(pb->area.y1 - pb->area.y0));
         trans *= res_scaling;
     } else {
+        // If filter resolution is automatic, just make copy of input image
         nr_pixblock_setup_fast(in, pb->mode,
                                pb->area.x0, pb->area.y0,
                                pb->area.x1, pb->area.y1, true);
@@ -112,27 +128,38 @@ int Filter::render(NRArenaItem const *item, NRPixBlock *pb)
     slot.set(NR_FILTER_SOURCEGRAPHIC, in);
     in = NULL; // in is now handled by FilterSlot, we should not touch it
 
+    // TODO: loop through the primitives and render them one at a time
     _primitive[0]->render(slot, trans);
 
     NRPixBlock *out = slot.get(_output_slot);
 
+    // Clear the pixblock, where the output will be put
+    // -> the original image does not show through
     int size = (pb->area.x1 - pb->area.x0)
         * (pb->area.y1 - pb->area.y0)
         * NR_PIXBLOCK_BPP(pb);
     memset(NR_PIXBLOCK_PX(pb), 0, size);
-        
+
+    // If the filter resolution is automatic, just copy our final image
+    // to output pixblock, otherwise use bicubic scaling
     if (_x_pixels < 0) {
         nr_blit_pixblock_pixblock(pb, out);
     } else {
         scale_bicubic(pb, out);
     }
 
+    // Take note of the amount of used image slots
+    // -> next time this filter is rendered, we can reserve enough slots
+    // immediately
     _slot_count = slot.get_slot_count();
     return 0;
 }
 
 int Filter::get_enlarge(Matrix const &m)
 {
+    // Just sum the enlargement factor of all filter elements.
+    // TODO: this both sucks and blows for filters like feOffset
+    // -> ditch this method and design a better one...
     int enlarge = 0;
     for ( int i = 0 ; i < _primitive_count ; i++ ) {
         if(_primitive[i]) enlarge += _primitive[i]->get_enlarge(m);
@@ -182,11 +209,17 @@ void Filter::bbox_enlarge(NRRectL &bbox)
     }
 }
 
+/* Constructor table holds pointers to static methods returning filter
+ * primitives. This table is indexed with FilterPrimitiveType, so that
+ * for example method in _constructor[NR_FILTER_GAUSSIANBLUR]
+ * returns a filter object of type NR::FilterGaussian.
+ */
 typedef FilterPrimitive*(*FilterConstructor)();
 static FilterConstructor _constructor[NR_FILTER_ENDPRIMITIVETYPE];
 
 void Filter::_create_constructor_table()
 {
+    // Constructor table won't change in run-time, so no need to recreate
     static bool created = false;
     if(created) return;
 
@@ -207,8 +240,13 @@ void Filter::_create_constructor_table()
     _constructor[NR_FILTER_SPECULARLIGHTING] = NULL;
     _constructor[NR_FILTER_TILE] = NULL;
     _constructor[NR_FILTER_TURBULENCE] = NULL;
+    created = true;
 }
 
+/** Helper method for enlarging table of filter primitives. When new
+ * primitives are added, but we have no space for them, this function
+ * makes some more space.
+ */
 void Filter::_enlarge_primitive_table() {
     FilterPrimitive **new_tbl = new FilterPrimitive*[_primitive_table_size * 2];
     for (int i = 0 ; i < _primitive_count ; i++) {
index 3b8461383d4eacf1ff4957e3ca2e59b44028175a..3be52c3f30878ab6f2bb5485129712e206acaa20 100644 (file)
@@ -1,5 +1,16 @@
 #define __NR_PIXBLOCK_SCALER_CPP__
 
+/*
+ * Functions for blitting pixblocks using scaling
+ *
+ * Author:
+ *   Niko Kiirala <niko@kiirala.com>
+ *
+ * Copyright (C) 2006 Niko Kiirala
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
 #include <glib.h>
 #include <cmath>
 using std::floor;
@@ -12,7 +23,20 @@ struct RGBA {
     int r, g, b, a;
 };
 
-inline int sampley(unsigned const char a, unsigned const char b, unsigned const char c, unsigned const char d, const double len) {
+/** Calculates cubically interpolated value of the four given pixel values.
+ * The pixel values should be from four vertically adjacent pixels.
+ * If we are calculating a pixel, whose y-coordinate in source image is
+ * i, these pixel values a, b, c and d should come from lines
+ * floor(i) - 1, floor(i), floor(i) + 1, floor(i) + 2, respectively.
+ * Parameter len should be set to i.
+ * Returns the interpolated value in fixed point format with 8 bit
+ * decimal part. (24.8 assuming 32-bit int)
+ */
+__attribute__ ((const))
+inline int sampley(unsigned const char a, unsigned const char b,
+                   unsigned const char c, unsigned const char d,
+                   const double len)
+{
     double lenf = len - floor(len);
     int sum = 0;
     sum += (int)((((-1.0 / 3.0) * lenf + 4.0 / 5.0) * lenf - 7.0 / 15.0)
@@ -26,6 +50,17 @@ inline int sampley(unsigned const char a, unsigned const char b, unsigned const
     return sum;
 }
 
+/** Calculates cubically interpolated value of the four given pixel values.
+ * The pixel values should be interpolated values from sampley, from four
+ * horizontally adjacent vertical lines. The parameters a, b, c and d
+ * should be in fixed point format with 8-bit decimal part.
+ * If we are calculating a pixel, whose x-coordinate in source image is
+ * i, these vertical  lines from where a, b, c and d are calculated, should be
+ * floor(i) - 1, floor(i), floor(i) + 1, floor(i) + 2, respectively.
+ * Parameter len should be set to i.
+ * Returns the interpolated value in 8-bit format, ready to be written
+ * to output buffer.
+ */
 inline unsigned char samplex(const int a, const int b, const int c, const int d, const double len) {
     double lenf = len - floor(len);
     int sum = 0;
@@ -34,7 +69,7 @@ inline unsigned char samplex(const int a, const int b, const int c, const int d,
     sum += (int)(c * ((((1 - lenf) - 9.0 / 5.0) * (1 - lenf) - 1.0 / 5.0) * (1 - lenf) + 1.0));
     sum += (int)(d * (((-1.0 / 3.0) * (1 - lenf) + 4.0 / 5.0) * (1 - lenf) - 7.0 / 15.0) * (1 - lenf));
     if (sum < 0) sum = 0;
-    if (sum > 255*256) sum = 255 * 256;
+    if (sum >= 256*256) sum = 255 * 256;
     return (unsigned char)(sum / 256);
 }
 
@@ -54,16 +89,27 @@ inline void _check_index(NRPixBlock const * const pb, int const location, int co
 
 void scale_bicubic(NRPixBlock *to, NRPixBlock *from)
 {
+    if (NR_PIXBLOCK_BPP(from) != 4 || NR_PIXBLOCK_BPP(to) != 4) {
+        g_warning("A non-32-bpp image passed to scale_bicubic: scaling aborted.");
+        return;
+    }
+
+    // Precalculate sizes of source and destination pixblocks
     int from_width = from->area.x1 - from->area.x0;
     int from_height = from->area.y1 - from->area.y0;
     int to_width = to->area.x1 - to->area.x0;
     int to_height = to->area.y1 - to->area.y0;
 
+    // from_step: when advancing one pixel in destination image,
+    // how much we should advance in source image
     double from_stepx = (double)from_width / (double)to_width;
     double from_stepy = (double)from_height / (double)to_height;
 
+    // Loop through every pixel of destination image, a line at a time
     for (int to_y = 0 ; to_y < to_height ; to_y++) {
         double from_y = to_y * from_stepy + from_stepy / 2;
+        // Pre-calculate beginning of the four horizontal lines, from
+        // which we should read
         int from_line[4];
         for (int i = 0 ; i < 4 ; i++) {
             if ((int)floor(from_y) + i - 1 >= 0) {
@@ -76,6 +122,9 @@ void scale_bicubic(NRPixBlock *to, NRPixBlock *from)
                 from_line[i] = 0;
             }
         }
+        // Loop through this horizontal line in destination image
+        // For every pixel, calculate the color of pixel with
+        // bicubic interpolation and set the pixel value in destination image
         for (int to_x = 0 ; to_x < to_width ; to_x++) {
             double from_x = to_x * from_stepx + from_stepx / 2;
             RGBA line[4];
index 1e30d0a34a7fe9907c66801ed7b6e4e7328bb660..907429257bf2f1e8dc45f04c21e1f676305589ab 100644 (file)
@@ -1,10 +1,27 @@
 #ifndef __NR_PIXBLOCK_SCALER_H__
 #define __NR_PIXBLOCK_SCALER_H__
 
+/*
+ * Functions for blitting pixblocks using scaling
+ *
+ * Author:
+ *   Niko Kiirala <niko@kiirala.com>
+ *
+ * Copyright (C) 2006 Niko Kiirala
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
 #include "libnr/nr-pixblock.h"
 
 namespace NR {
 
+/** Blits the second pixblock to the first.
+ * Image in source pixblock is scaled to the size of destination pixblock
+ * using bicubic interpolation.
+ * Source pixblock is not modified in process.
+ * Only works for 32-bpp images.
+ */
 void scale_bicubic(NRPixBlock *to, NRPixBlock *from);
 
 } /* namespace NR */