summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 20a7078)
raw | patch | inline | side by side (parent: 20a7078)
author | kiirala <kiirala@users.sourceforge.net> | |
Wed, 3 Jan 2007 14:12:44 +0000 (14:12 +0000) | ||
committer | kiirala <kiirala@users.sourceforge.net> | |
Wed, 3 Jan 2007 14:12:44 +0000 (14:12 +0000) |
src/display/Makefile_insert | patch | blob | history | |
src/display/nr-filter.cpp | patch | blob | history | |
src/display/pixblock-transform.cpp | [new file with mode: 0644] | patch | blob |
src/display/pixblock-transform.h | [new file with mode: 0644] | patch | blob |
index a6cecaffbdc1cf790054347628b197cca599635e..4d51a789107923f664a5de1fa80c1c2160faf660 100644 (file)
display/nr-filter-slot.h \
display/nr-filter-types.h \
display/pixblock-scaler.cpp \
- display/pixblock-scaler.h
+ display/pixblock-scaler.h \
+ display/pixblock-transform.cpp \
+ display/pixblock-transform.h
display_bezier_utils_test_SOURCES = display/bezier-utils-test.cpp
display_bezier_utils_test_LDADD = libnr/libnr.a -lglib-2.0
index 592623c495e0855a741be4b342e3aaced2bfd146..f00a1ef6b3c922183250b0d911be3f33388a40f5 100644 (file)
*/
#include <glib.h>
+#include <cmath>
#include "display/nr-filter.h"
#include "display/nr-filter-primitive.h"
#include "display/nr-filter-slot.h"
#include "display/nr-filter-types.h"
#include "display/pixblock-scaler.h"
+#include "display/pixblock-transform.h"
#include "display/nr-arena-item.h"
#include "libnr/nr-pixblock.h"
//#include "display/nr-arena-shape.h"
+__attribute__ ((const))
+inline static int _max4(const double a, const double b,
+ const double c, const double d) {
+ double ret = a;
+ if (b > ret) ret = b;
+ if (c > ret) ret = c;
+ if (d > ret) ret = d;
+ return (int)round(ret);
+}
+
+__attribute__ ((const))
+inline static int _min4(const double a, const double b,
+ const double c, const double d) {
+ double ret = a;
+ if (b < ret) ret = b;
+ if (c < ret) ret = c;
+ if (d < ret) ret = d;
+ return (int)round(ret);
+}
+
namespace NR {
Filter::Filter()
}
Matrix trans = *item->ctm;
+ Matrix paraller_trans = trans;
+ bool notparaller = false;
FilterSlot slot(_slot_count, item);
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 effects region is not paraller to viewport,
+ // we must first undo the rotation / shear.
+ // It will be redone after filtering.
+ // If there is only rotation and uniform scaling (zoom), let's skip this,
+ // as it will not make a difference with gaussian blur.
+ if ((fabs(trans[1]) > 1e-6 || fabs(trans[2]) > 1e-6) &&
+ !(fabs(trans[0] - trans[3]) < 1e-6 && fabs(trans[1] + trans[2]) < 1e-6)) {
+ notparaller = true;
+
+ // TODO: if filter resolution is specified, scaling should be set
+ // according to that
+ double scaling_factor = sqrt(trans.expansionX() * trans.expansionX() +
+ trans.expansionY() * trans.expansionY());
+ scale scaling(scaling_factor, scaling_factor);
+ scale scaling_inv(1.0 / scaling_factor, 1.0 / scaling_factor);
+ trans *= scaling_inv;
+ paraller_trans.set_identity();
+ paraller_trans *= scaling;
+
+ Matrix itrans = trans.inverse();
+ int x0 = pb->area.x0;
+ int y0 = pb->area.y0;
+ int x1 = pb->area.x1;
+ int y1 = pb->area.y1;
+ int min_x = _min4(itrans[0] * x0 + itrans[2] * y0 + itrans[4],
+ itrans[0] * x0 + itrans[2] * y1 + itrans[4],
+ itrans[0] * x1 + itrans[2] * y0 + itrans[4],
+ itrans[0] * x1 + itrans[2] * y1 + itrans[4]);
+ int max_x = _max4(itrans[0] * x0 + itrans[2] * y0 + itrans[4],
+ itrans[0] * x0 + itrans[2] * y1 + itrans[4],
+ itrans[0] * x1 + itrans[2] * y0 + itrans[4],
+ itrans[0] * x1 + itrans[2] * y1 + itrans[4]);
+ int min_y = _min4(itrans[1] * x0 + itrans[3] * y0 + itrans[5],
+ itrans[1] * x0 + itrans[3] * y1 + itrans[5],
+ itrans[1] * x1 + itrans[3] * y0 + itrans[5],
+ itrans[1] * x1 + itrans[3] * y1 + itrans[5]);
+ int max_y = _max4(itrans[1] * x0 + itrans[3] * y0 + itrans[5],
+ itrans[1] * x0 + itrans[3] * y1 + itrans[5],
+ itrans[1] * x1 + itrans[3] * y0 + itrans[5],
+ itrans[1] * x1 + itrans[3] * y1 + itrans[5]);
+
+ nr_pixblock_setup_fast(in, pb->mode,
+ min_x, min_y,
+ max_x, max_y, true);
+ if (in->data.px == NULL) // memory allocation failed
+ return 0;
+ transform_nearest(in, pb, itrans);
+ } else if (_x_pixels >= 0) {
+ // If filter resolution is not set to automatic, we should
+ // scale the input image to correct resolution
/* If filter resolution is zero, the object should not be rendered */
if (_x_pixels == 0 || _y_pixels == 0) {
int size = (pb->area.x1 - pb->area.x0)
scale_bicubic(in, pb);
scale res_scaling(x_len / (double)(pb->area.x1 - pb->area.x0),
y_len / (double)(pb->area.y1 - pb->area.y0));
- trans *= res_scaling;
+ paraller_trans *= res_scaling;
} else {
// If filter resolution is automatic, just make copy of input image
nr_pixblock_setup_fast(in, pb->mode,
in = NULL; // in is now handled by FilterSlot, we should not touch it
// TODO: loop through ALL the primitives and render them one at a time
- _primitive[0]->render(slot, trans);
+ _primitive[0]->render(slot, paraller_trans);
NRPixBlock *out = slot.get(_output_slot);
// Clear the pixblock, where the output will be put
* 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) {
+ if (notparaller) {
+ transform_nearest(pb, out, trans);
+ } else if (_x_pixels < 0) {
+ // If the filter resolution is automatic, just copy our final image
+ // to output pixblock, otherwise use bicubic scaling
nr_blit_pixblock_pixblock(pb, out);
} else {
scale_bicubic(pb, out);
diff --git a/src/display/pixblock-transform.cpp b/src/display/pixblock-transform.cpp
--- /dev/null
@@ -0,0 +1,98 @@
+#define __NR_PIXBLOCK_SCALER_CPP__
+
+/*
+ * Functions for blitting pixblocks using matrix transformation
+ *
+ * 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;
+
+#include "libnr/nr-pixblock.h"
+#include "libnr/nr-matrix.h"
+
+namespace NR {
+
+struct RGBA {
+ int r, g, b, a;
+};
+
+/**
+ * Sanity check function for indexing pixblocks.
+ * Catches reading and writing outside the pixblock area.
+ * When enabled, decreases filter rendering speed massively.
+ */
+inline void _check_index(NRPixBlock const * const pb, int const location, int const line)
+{
+ if(true) {
+ int max_loc = pb->rs * (pb->area.y1 - pb->area.y0);
+ if (location < 0 || (location + 4) >= max_loc)
+ g_warning("Location %d out of bounds (0 ... %d) at line %d", location, max_loc, line);
+ }
+}
+
+void transform_nearest(NRPixBlock *to, NRPixBlock *from, Matrix &trans)
+{
+ if (NR_PIXBLOCK_BPP(from) != 4 || NR_PIXBLOCK_BPP(to) != 4) {
+ g_warning("A non-32-bpp image passed to transform_nearest: 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;
+
+ Matrix itrans = trans.inverse();
+
+ // Loop through every pixel of destination image, a line at a time
+ for (int to_y = 0 ; to_y < to_height ; to_y++) {
+ for (int to_x = 0 ; to_x < to_width ; to_x++) {
+ RGBA result = {0,0,0,0};
+
+ int from_x = (int)round(itrans[0] * (to_x + to->area.x0)
+ + itrans[2] * (to_y + to->area.y0)
+ + itrans[4]);
+ from_x -= from->area.x0;
+ int from_y = (int)round(itrans[1] * (to_x + to->area.x0)
+ + itrans[3] * (to_y + to->area.y0)
+ + itrans[5]);
+ from_y -= from->area.y0;
+
+ if (from_x >= 0 && from_x < from_width
+ && from_y >= 0 && from_y < from_height) {
+ _check_index(from, from_y * from->rs + from_x * 4, __LINE__);
+ result.r = NR_PIXBLOCK_PX(from)[from_y * from->rs + from_x * 4];
+ result.g = NR_PIXBLOCK_PX(from)[from_y * from->rs + from_x * 4 + 1];
+ result.b = NR_PIXBLOCK_PX(from)[from_y * from->rs + from_x * 4 + 2];
+ result.a = NR_PIXBLOCK_PX(from)[from_y * from->rs + from_x * 4 + 3];
+ }
+
+ _check_index(to, to_y * to->rs + to_x * 4, __LINE__);
+ NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4] = result.r;
+ NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 1] = result.g;
+ NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 2] = result.b;
+ NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 3] = result.a;
+ }
+ }
+}
+
+} /* namespace NR */
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/display/pixblock-transform.h b/src/display/pixblock-transform.h
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef __NR_PIXBLOCK_TRANSFORM_H__
+#define __NR_PIXBLOCK_TRANSFORM_H__
+
+/*
+ * Functions for blitting pixblocks using matrix transfomation
+ *
+ * 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"
+#include "libnr/nr-matrix.h"
+
+namespace NR {
+
+void transform_nearest(NRPixBlock *to, NRPixBlock *from, Matrix &trans);
+
+} /* namespace NR */
+
+#endif // __NR_PIXBLOCK_TRANSFORM_H__
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :