Improved extension mechanism.
[kaya/ydirson.git] / lib / ext / expblur.cpp
blob076de0fd49c96a20caec733699758f011c1bfe62
1 #include <QImage>
2 #include <cmath>
3 #include <QPainter>
5 #include "extensions.h"
7 /*
8 struct ruby_object {
9 bool allocated;
10 Smoke* smoke;
11 int classId;
12 void* ptr;
13 };*/
15 template<int aprec, int zprec>
16 static inline void blurinner(unsigned char *bptr, int &zR,
17 int &zG, int &zB, int &zA, int alpha);
19 template<int aprec,int zprec>
20 static inline void blurrow(QImage & im, int line, int alpha);
22 template<int aprec, int zprec>
23 static inline void blurcol(QImage & im, int col, int alpha);
26 * expblur(QImage &img, int radius)
28 * In-place blur of image 'img' with kernel
29 * of approximate radius 'radius'.
31 * Blurs with two sided exponential impulse
32 * response.
34 * aprec = precision of alpha parameter
35 * in fixed-point format 0.aprec
37 * zprec = precision of state parameters
38 * zR,zG,zB and zA in fp format 8.zprec
40 template<int aprec,int zprec>
41 static void expblur(QImage &img, int radius )
43 if (radius < 1)
44 return;
46 /* Calculate the alpha such that 90% of
47 the kernel is within the radius.
48 (Kernel extends to infinity)
50 int alpha = (int)((1<<aprec)*(1.0f-expf(-2.3f/(radius+1.f))));
52 for(int row=0;row<img.height();row++) {
53 blurrow<aprec,zprec>(img,row,alpha);
56 for(int col=0;col<img.width();col++) {
57 blurcol<aprec,zprec>(img,col,alpha);
59 return;
62 template<int aprec, int zprec>
63 static inline void blurinner(unsigned char *bptr,
64 int &zR, int &zG, int &zB, int &zA, int alpha)
66 int R,G,B,A;
67 R = *bptr;
68 G = *(bptr+1);
69 B = *(bptr+2);
70 A = *(bptr+3);
72 zR += (alpha * ((R<<zprec)-zR))>>aprec;
73 zG += (alpha * ((G<<zprec)-zG))>>aprec;
74 zB += (alpha * ((B<<zprec)-zB))>>aprec;
75 zA += (alpha * ((A<<zprec)-zA))>>aprec;
77 *bptr = zR>>zprec;
78 *(bptr+1) = zG>>zprec;
79 *(bptr+2) = zB>>zprec;
80 *(bptr+3) = zA>>zprec;
83 template<int aprec,int zprec>
84 static inline void blurrow( QImage & im, int line, int alpha)
86 int zR,zG,zB,zA;
88 QRgb *ptr = (QRgb *)im.scanLine(line);
90 zR = *((unsigned char *)ptr )<<zprec;
91 zG = *((unsigned char *)ptr + 1)<<zprec;
92 zB = *((unsigned char *)ptr + 2)<<zprec;
93 zA = *((unsigned char *)ptr + 3)<<zprec;
95 for(int index=1; index<im.width(); index++) {
96 blurinner<aprec,zprec>((unsigned char *)&ptr[index],
97 zR, zG, zB, zA, alpha);
99 for(int index=im.width()-2; index>=0; index--) {
100 blurinner<aprec,zprec>((unsigned char *)&ptr[index],
101 zR, zG, zB, zA, alpha);
107 template<int aprec, int zprec>
108 static inline void blurcol(QImage & im, int col, int alpha)
110 int zR,zG,zB,zA;
112 QRgb *ptr = (QRgb *)im.bits();
113 ptr+=col;
115 zR = *((unsigned char *)ptr )<<zprec;
116 zG = *((unsigned char *)ptr + 1)<<zprec;
117 zB = *((unsigned char *)ptr + 2)<<zprec;
118 zA = *((unsigned char *)ptr + 3)<<zprec;
120 for(int index=im.width(); index<(im.height()-1)*im.width();
121 index+=im.width()) {
122 blurinner<aprec,zprec>((unsigned char *)&ptr[index],
123 zR, zG, zB, zA, alpha);
126 for(int index=(im.height()-2)*im.width(); index>=0;
127 index-=im.width()) {
128 blurinner<aprec,zprec>((unsigned char *)&ptr[index],
129 zR, zG, zB, zA, alpha);
134 void Extensions::exp_blur(QImage* img, int radius) const {
135 return expblur<15,7>(*img, radius);
140 static ruby_object* get_object(VALUE val) {
141 if (TYPE(val) != T_DATA) {
142 return 0;
145 ruby_object* o = 0;
146 Data_Get_Struct(val, ruby_object, o);
147 return o;
150 extern "C" VALUE test_expblur(VALUE self, VALUE val, VALUE radius) {
151 ruby_object* o = get_object(val);
152 if (o) {
153 QImage* img = (QImage*)o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QImage"));
154 expblur<15,7>(*img, NUM2INT(radius));
157 return Qnil;
160 extern "C" void Init_expblur() {
161 rb_define_method(Qnil, "expblur", (VALUE (*)(...))test_expblur, 2);