1 /*
2 select0r.c
3
4 This frei0r plugin makes a color based alpha selection
5 Version 0.4 apr 2012
6
7 Copyright (C) 2010 Marko Cebokli http://lea.hamradio.si/~s57uuu
8
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23
24 */
25
26 // apr 2012 added slope parameter
27
28 //compile: gcc -c -fPIC -Wall select0r.c -o select0r.o
29 //link: gcc -shared -o select0r.so select0r.o
30
31 //#include <stdio.h> /* for debug printf only +/
32 #include <frei0r.h>
33 #include <stdlib.h>
34 #include <math.h>
35 #include <assert.h>
36
37 typedef struct
38 {
39 float r;
40 float g;
41 float b;
42 float a;
43 } float_rgba;
44
45 typedef struct
46 {
47 float x;
48 float y;
49 float z;
50 } triplet;
51
52 double PI=3.14159265358979;
53
54 //-----------------------------------------------------------
55 //inline functions for subspace metrics
56 //distance from center point for different shapes
57 //for cartesian and cylindric (wraparound hue) spaces
58 //cx,cy,cz: center of subspace
59 //dx,dy,dz: size of subspace
60 //dx, dy and dz must be inverse (1/x) values! (avoid division)
61 //x,y,z: point from which distance is determined
62 // returns square of distance
63 // r==1 is edge of subspace
64 //box shape
dist_box(float cx,float cy,float cz,float dx,float dy,float dz,float x,float y,float z)65 static inline float dist_box(float cx, float cy, float cz, float dx, float dy, float dz, float x, float y, float z)
66 {
67 float ax,ay,az,r;
68
69 ax=fabsf(x-cx)*dx;
70 ay=fabsf(y-cy)*dy;
71 az=fabsf(z-cz)*dz;
72 r=ax;
73 if (ay>r) r=ay;
74 if (az>r) r=az;
75 r=r*r;
76 return r;
77 }
78 //ellipsoid shape
dist_eli(float cx,float cy,float cz,float dx,float dy,float dz,float x,float y,float z)79 static inline float dist_eli(float cx, float cy, float cz, float dx, float dy, float dz, float x, float y, float z)
80 {
81 float ax,ay,az,r;
82
83 ax=(x-cx)*dx;
84 ay=(y-cy)*dy;
85 az=(z-cz)*dz;
86 r=ax*ax+ay*ay+az*az;
87 return r;
88 }
89 //octahedron shape
dist_oct(float cx,float cy,float cz,float dx,float dy,float dz,float x,float y,float z)90 static inline float dist_oct(float cx, float cy, float cz, float dx, float dy, float dz, float x, float y, float z)
91 {
92 float ax,ay,az,r;
93
94 ax=fabsf(x-cx)*dx;
95 ay=fabsf(y-cy)*dy;
96 az=fabsf(z-cz)*dz;
97 r=ax+ay+az;
98 r=r*r;
99 return r;
100 }
101 //box shape, cylindrical space
dist_box_c(float chue,float cy,float cz,float dhue,float dy,float dz,float hue,float y,float z)102 static inline float dist_box_c(float chue, float cy, float cz, float dhue, float dy, float dz, float hue, float y, float z)
103 {
104 float ax,ay,az,r;
105
106 // wrap hue term -0.5 .. 0.5
107 ax = 0.5 - fabsf(fabsf(hue - chue) - 0.5);
108 ax=ax*dhue;
109 ay=fabsf(y-cy)*dy;
110 az=fabsf(z-cz)*dz;
111 r=ax;
112 if (ay>r) r=ay;
113 if (az>r) r=az;
114 r=r*r;
115 return r;
116 }
117 //ellipsoid shape, cylindrical space
dist_eli_c(float chue,float cy,float cz,float dhue,float dy,float dz,float hue,float y,float z)118 static inline float dist_eli_c(float chue, float cy, float cz, float dhue, float dy, float dz, float hue, float y, float z)
119 {
120 float ax,ay,az,r;
121
122 ax = 0.5 - fabsf(fabsf(hue - chue) - 0.5);
123 ax=ax*dhue;
124 ay=(y-cy)*dy;
125 az=(z-cz)*dz;
126 r=ax*ax+ay*ay+az*az;
127 return r;
128 }
129 //octahedron shape, cylindrical space
dist_oct_c(float chue,float cy,float cz,float dhue,float dy,float dz,float hue,float y,float z)130 static inline float dist_oct_c(float chue, float cy, float cz, float dhue, float dy, float dz, float hue, float y, float z)
131 {
132 float ax,ay,az,r;
133
134 ax = 0.5 - fabsf(fabsf(hue - chue) - 0.5);
135 ax=ax*dhue;
136 ay=fabsf(y-cy)*dy;
137 az=fabsf(z-cz)*dz;
138 r=ax+ay+az;
139 r=r*r;
140 return r;
141 }
142
143 //----------------------------------------------------------
144 //inline RGB to ABI conversion function
rgb2abi(float k32,float r,float g,float b,float * a,float * bb,float * i)145 static inline void rgb2abi(float k32, float r, float g, float b, float *a, float *bb, float *i)
146 {
147 *a=r-0.5*g-0.5*b;
148 *bb=k32*(g-b);
149 *i=0.3333*(r+g+b);
150 }
151
152 //----------------------------------------------------------
153 //inline RGB to HCI conversion function
rgb2hci(float ipi2,float k32,float r,float g,float b,float * h,float * c,float * i)154 static inline void rgb2hci(float ipi2, float k32, float r, float g, float b, float *h, float *c, float *i)
155 {
156 float a,bb;
157 a=r-0.5*g-0.5*b;
158 bb=k32*(g-b);
159 *h=atan2(bb,a)*ipi2;
160 *c=hypotf(a,bb);
161 *i=0.3333*(r+g+b);
162 }
163
164 //------------------------------------------------------
165 //thresholding inline functions (hard and soft)
thres(float a)166 static inline float thres(float a)
167 {
168 return (a<1.0) ? 1.0 : 0.0;
169 }
170
fat(float a)171 static inline float fat(float a)
172 {
173 a=a*a*a*a;
174 return (a<1.0) ? 1.0-a : 0.0;
175 }
176
norm(float a)177 static inline float norm(float a)
178 {
179 a=a*a;
180 return (a<1.0) ? 1.0-a : 0.0;
181 }
182
skiny(float a)183 static inline float skiny(float a)
184 {
185 return (a<1.0) ? 1.0-a : 0.0;
186 }
187
slope(float a,float is)188 static inline float slope(float a, float is)
189 {
190 a = (a<1.0) ? 1.0 : 1.0-is*(a-1);
191 return (a>=0) ? a : 0.0;
192 }
193
194 //----------------------------------------------------------
195 //RGB selection
196 //d = deltas (size of subspace)
197 //n = nudges
198 //ss = subspace shape [0..2] box, ellipsoid, octahedron
199 //thr: 0=thresholded 1=linear fat 2=lin norm 3=lin skiny
200 //avoids switch () inside inner loop for speed - this means
201 //a big, repetitive switch statement outside....
sel_rgb(float_rgba * slika,int w,int h,float_rgba key,triplet d,triplet n,float slp,int ss,int thr)202 void sel_rgb(float_rgba *slika, int w, int h, float_rgba key, triplet d, triplet n, float slp, int ss, int thr)
203 {
204 float kr,kg,kb,dd;
205 int i,s;
206 float ddx,ddy,ddz;
207 float islp;
208
209 //add nudge
210 kr=key.r+n.x;
211 kg=key.g+n.y;
212 kb=key.b+n.z;
213 ddx = (d.x!=0) ? 1.0/d.x : 1.0E6;
214 ddy = (d.y!=0) ? 1.0/d.y : 1.0E6;
215 ddz = (d.z!=0) ? 1.0/d.z : 1.0E6;
216
217 islp = (slp>0.000001) ? 0.2/slp : 200000.0;
218
219 s=10*ss+thr; //to avoid nested switch statements
220
221 switch (s)
222 {
223 case 0: //box, thresholded
224 for (i=0;i<w*h;i++)
225 {
226 dd = dist_box(kr, kg, kb, ddx, ddy, ddz, slika[i].r, slika[i].g, slika[i].b);
227 slika[i].a = thres(dd);
228 }
229 break;
230 case 1: //box, linear fat
231 for (i=0;i<w*h;i++)
232 {
233 dd = dist_box(kr, kg, kb, ddx, ddy, ddz, slika[i].r, slika[i].g, slika[i].b);
234 slika[i].a = fat(dd);
235 }
236 break;
237 case 2: //box, linear normal
238 for (i=0;i<w*h;i++)
239 {
240 dd = dist_box(kr, kg, kb, ddx, ddy, ddz, slika[i].r, slika[i].g, slika[i].b);
241 slika[i].a = norm(dd);
242 }
243 break;
244 case 3: //box, linear skiny
245 for (i=0;i<w*h;i++)
246 {
247 dd = dist_box(kr, kg, kb, ddx, ddy, ddz, slika[i].r, slika[i].g, slika[i].b);
248 slika[i].a = skiny(dd);
249 }
250 break;
251 case 4: //box, linear slope
252 for (i=0;i<w*h;i++)
253 {
254 dd = dist_box(kr, kg, kb, ddx, ddy, ddz, slika[i].r, slika[i].g, slika[i].b);
255 slika[i].a = slope(dd, islp);
256 }
257 break;
258
259 case 10: //ellipsoid, thresholded
260 for (i=0;i<w*h;i++)
261 {
262 dd = dist_eli(kr, kg, kb, ddx, ddy, ddz, slika[i].r, slika[i].g, slika[i].b);
263 slika[i].a = thres(dd);
264 }
265 break;
266 case 11: //ellipsoid, linear fat
267 for (i=0;i<w*h;i++)
268 {
269 dd = dist_eli(kr, kg, kb, ddx, ddy, ddz, slika[i].r, slika[i].g, slika[i].b);
270 slika[i].a = fat(dd);
271 }
272 break;
273 case 12: //ellipsoid, linear normal
274 for (i=0;i<w*h;i++)
275 {
276 dd = dist_eli(kr, kg, kb, ddx, ddy, ddz, slika[i].r, slika[i].g, slika[i].b);
277 slika[i].a = norm(dd);
278 }
279 break;
280 case 13: //ellipsoid, linear skiny
281 for (i=0;i<w*h;i++)
282 {
283 dd = dist_eli(kr, kg, kb, ddx, ddy, ddz, slika[i].r, slika[i].g, slika[i].b);
284 slika[i].a = skiny(dd);
285 }
286 break;
287 case 14: //ellipsoid, linear slope
288 for (i=0;i<w*h;i++)
289 {
290 dd = dist_eli(kr, kg, kb, ddx, ddy, ddz, slika[i].r, slika[i].g, slika[i].b);
291 slika[i].a = slope(dd, islp);
292 }
293 break;
294
295 case 20: //octahedron, thresholded
296 for (i=0;i<w*h;i++)
297 {
298 dd = dist_oct(kr, kg, kb, ddx, ddy, ddz, slika[i].r, slika[i].g, slika[i].b);
299 slika[i].a = thres(dd);
300 }
301 break;
302 case 21: //octahedron, linear fat
303 for (i=0;i<w*h;i++)
304 {
305 dd = dist_oct(kr, kg, kb, ddx, ddy, ddz, slika[i].r, slika[i].g, slika[i].b);
306 slika[i].a = fat(dd);
307 }
308 break;
309 case 22: //octahedron, linear normal
310 for (i=0;i<w*h;i++)
311 {
312 dd = dist_oct(kr, kg, kb, ddx, ddy, ddz, slika[i].r, slika[i].g, slika[i].b);
313 slika[i].a = norm(dd);
314 }
315 break;
316 case 23: //octahedron, linear skiny
317 for (i=0;i<w*h;i++)
318 {
319 dd = dist_oct(kr, kg, kb, ddx, ddy, ddz, slika[i].r, slika[i].g, slika[i].b);
320 slika[i].a = skiny(dd);
321 }
322 break;
323 case 24: //octahedron, linear slope
324 for (i=0;i<w*h;i++)
325 {
326 dd = dist_oct(kr, kg, kb, ddx, ddy, ddz, slika[i].r, slika[i].g, slika[i].b);
327 slika[i].a = slope(dd, islp);
328 }
329 break;
330 default:
331 break;
332 }
333 }
334
335 //----------------------------------------------------------
336 //ABI selection
337 //d = deltas (size of subspace)
338 //n = nudges
339 //ss = subspace shape [0..2] box, ellipsoid, octahedron
340 //thr: 0=thresholded 1=linear fat 2=lin norm 3=lin skiny
341 //avoids switch () inside inner loop for speed - this means
342 //a big, repetitive switch statement outside....
sel_abi(float_rgba * slika,int w,int h,float_rgba key,triplet d,triplet n,float slp,int ss,int thr)343 void sel_abi(float_rgba *slika, int w, int h, float_rgba key, triplet d, triplet n, float slp, int ss, int thr)
344 {
345 float ka,kb,ki,k32,dd;
346 int i,s;
347 float dda,ddb,ddi,sa,sb,si;
348 float islp;
349
350 dda = (d.x!=0) ? 1.0/d.x : 1.0E6;
351 ddb = (d.y!=0) ? 1.0/d.y : 1.0E6;
352 ddi = (d.z!=0) ? 1.0/d.z : 1.0E6;
353
354 //convert key to ABI and add nudge
355 k32=sqrtf(3.0)/2.0;
356 ka=key.r-0.5*key.g-0.5*key.b+n.x;
357 kb=k32*(key.g-key.b)+n.y;
358 ki=0.3333*(key.r+key.g+key.b)+n.z;
359
360 islp = (slp>0.000001) ? 0.2/slp : 200000.0;
361
362 s=10*ss+thr; //to avoid nested switch statements
363
364 switch (s)
365 {
366 case 0: //box, thresholded
367 for (i=0;i<w*h;i++)
368 {
369 rgb2abi(k32,slika[i].r,slika[i].g,slika[i].b,&sa,&sb,&si);
370 dd = dist_box(ka, kb, ki, dda, ddb, ddi, sa, sb, si);
371 slika[i].a = thres(dd);
372 }
373 break;
374 case 1: //box, linear fat
375 for (i=0;i<w*h;i++)
376 {
377 rgb2abi(k32,slika[i].r,slika[i].g,slika[i].b,&sa,&sb,&si);
378 dd = dist_box(ka, kb, ki, dda, ddb, ddi, sa, sb, si);
379 slika[i].a = fat(dd);
380 }
381 break;
382 case 2: //box, linear normal
383 for (i=0;i<w*h;i++)
384 {
385 rgb2abi(k32,slika[i].r,slika[i].g,slika[i].b,&sa,&sb,&si);
386 dd = dist_box(ka, kb, ki, dda, ddb, ddi, sa, sb, si);
387 slika[i].a = norm(dd);
388 }
389 break;
390 case 3: //box, linear skiny
391 for (i=0;i<w*h;i++)
392 {
393 rgb2abi(k32,slika[i].r,slika[i].g,slika[i].b,&sa,&sb,&si);
394 dd = dist_box(ka, kb, ki, dda, ddb, ddi, sa, sb, si);
395 slika[i].a = skiny(dd);
396 }
397 break;
398 case 4: //box, linear slope
399 for (i=0;i<w*h;i++)
400 {
401 rgb2abi(k32,slika[i].r,slika[i].g,slika[i].b,&sa,&sb,&si);
402 dd = dist_box(ka, kb, ki, dda, ddb, ddi, sa, sb, si);
403 slika[i].a = slope(dd, islp);
404 }
405 break;
406
407 case 10: //ellipsoid, thresholded
408 for (i=0;i<w*h;i++)
409 {
410 rgb2abi(k32,slika[i].r,slika[i].g,slika[i].b,&sa,&sb,&si);
411 dd = dist_eli(ka, kb, ki, dda, ddb, ddi, sa, sb, si);
412 slika[i].a = thres(dd);
413 }
414 break;
415 case 11: //ellipsoid, linear fat
416 for (i=0;i<w*h;i++)
417 {
418 rgb2abi(k32,slika[i].r,slika[i].g,slika[i].b,&sa,&sb,&si);
419 dd = dist_eli(ka, kb, ki, dda, ddb, ddi, sa, sb, si);
420 slika[i].a = fat(dd);
421 }
422 break;
423 case 12: //ellipsoid, linear normal
424 for (i=0;i<w*h;i++)
425 {
426 rgb2abi(k32,slika[i].r,slika[i].g,slika[i].b,&sa,&sb,&si);
427 dd = dist_eli(ka, kb, ki, dda, ddb, ddi, sa, sb, si);
428 slika[i].a = norm(dd);
429 }
430 break;
431 case 13: //ellipsoid, linear skiny
432 for (i=0;i<w*h;i++)
433 {
434 rgb2abi(k32,slika[i].r,slika[i].g,slika[i].b,&sa,&sb,&si);
435 dd = dist_eli(ka, kb, ki, dda, ddb, ddi, sa, sb, si);
436 slika[i].a = skiny(dd);
437 }
438 break;
439 case 14: //ellipsoid, linear slope
440 for (i=0;i<w*h;i++)
441 {
442 rgb2abi(k32,slika[i].r,slika[i].g,slika[i].b,&sa,&sb,&si);
443 dd = dist_eli(ka, kb, ki, dda, ddb, ddi, sa, sb, si);
444 slika[i].a = slope(dd, islp);
445 }
446 break;
447
448 case 20: //octahedron, thresholded
449 for (i=0;i<w*h;i++)
450 {
451 rgb2abi(k32,slika[i].r,slika[i].g,slika[i].b,&sa,&sb,&si);
452 dd = dist_oct(ka, kb, ki, dda, ddb, ddi, sa, sb, si);
453 slika[i].a = thres(dd);
454 }
455 break;
456 case 21: //octahedron, linear fat
457 for (i=0;i<w*h;i++)
458 {
459 rgb2abi(k32,slika[i].r,slika[i].g,slika[i].b,&sa,&sb,&si);
460 dd = dist_oct(ka, kb, ki, dda, ddb, ddi, sa, sb, si);
461 slika[i].a = fat(dd);
462 }
463 break;
464 case 22: //octahedron, linear normal
465 for (i=0;i<w*h;i++)
466 {
467 rgb2abi(k32,slika[i].r,slika[i].g,slika[i].b,&sa,&sb,&si);
468 dd = dist_oct(ka, kb, ki, dda, ddb, ddi, sa, sb, si);
469 slika[i].a = norm(dd);
470 }
471 break;
472 case 23: //octahedron, linear skiny
473 for (i=0;i<w*h;i++)
474 {
475 rgb2abi(k32,slika[i].r,slika[i].g,slika[i].b,&sa,&sb,&si);
476 dd = dist_oct(ka, kb, ki, dda, ddb, ddi, sa, sb, si);
477 slika[i].a = skiny(dd);
478 }
479 break;
480 case 24: //octahedron, linear slope
481 for (i=0;i<w*h;i++)
482 {
483 rgb2abi(k32,slika[i].r,slika[i].g,slika[i].b,&sa,&sb,&si);
484 dd = dist_oct(ka, kb, ki, dda, ddb, ddi, sa, sb, si);
485 slika[i].a = slope(dd, islp);
486 }
487 break;
488 default:
489 break;
490 }
491 }
492
493 //----------------------------------------------------------
494 //HCI selection
495 //d = deltas (size of subspace)
496 //n = nudges
497 //ss = subspace shape [0..2] box, ellipsoid, octahedron
498 //thr: 0=thresholded 1=linear fat 2=lin norm 3=lin skiny
499 //avoids switch () inside inner loop for speed - this means
500 //a big, repetitive switch statement outside....
sel_hci(float_rgba * slika,int w,int h,float_rgba key,triplet d,triplet n,float slp,int ss,int thr)501 void sel_hci(float_rgba *slika, int w, int h, float_rgba key, triplet d, triplet n, float slp, int ss, int thr)
502 {
503 float ka,kb,ki,kh,kc,k32,dd;
504 int i,s;
505 float ddh,ddc,ddi,sh,sc,si,ipi2;
506 float islp;
507
508 ipi2=0.5/PI;
509 ddh = (d.x!=0) ? 1.0/d.x : 1.0E6;
510 ddc = (d.y!=0) ? 1.0/d.y : 1.0E6;
511 ddi = (d.z!=0) ? 1.0/d.z : 1.0E6;
512
513 //convert key to HCI and add nudge
514 k32=sqrtf(3.0)/2.0;
515 ka=key.r-0.5*key.g-0.5*key.b;
516 kb=k32*(key.g-key.b);
517 ki=0.3333*(key.r+key.g+key.b)+n.z;
518 kh=atan2f(kb,ka)*ipi2+n.x;
519 kc=hypotf(ka,kb)+n.y;
520
521 islp = (slp>0.000001) ? 0.2/slp : 200000.0;
522
523 s=10*ss+thr; //to avoid nested switch statements
524
525 switch (s)
526 {
527 case 0: //box, thresholded
528 for (i=0;i<w*h;i++)
529 {
530 rgb2hci(ipi2,k32,slika[i].r,slika[i].g,slika[i].b,&sh,&sc,&si);
531 dd = dist_box_c(kh, kc, ki, ddh, ddc, ddi, sh, sc, si);
532 slika[i].a = thres(dd);
533 }
534 break;
535 case 1: //box, linear fat
536 for (i=0;i<w*h;i++)
537 {
538 rgb2hci(ipi2,k32,slika[i].r,slika[i].g,slika[i].b,&sh,&sc,&si);
539 dd = dist_box_c(kh, kc, ki, ddh, ddc, ddi, sh, sc, si);
540 slika[i].a = fat(dd);
541 }
542 break;
543 case 2: //box, linear normal
544 for (i=0;i<w*h;i++)
545 {
546 rgb2hci(ipi2,k32,slika[i].r,slika[i].g,slika[i].b,&sh,&sc,&si);
547 dd = dist_box_c(kh, kc, ki, ddh, ddc, ddi, sh, sc, si);
548 slika[i].a = norm(dd);
549 }
550 break;
551 case 3: //box, linear skiny
552 for (i=0;i<w*h;i++)
553 {
554 rgb2hci(ipi2,k32,slika[i].r,slika[i].g,slika[i].b,&sh,&sc,&si);
555 dd = dist_box_c(kh, kc, ki, ddh, ddc, ddi, sh, sc, si);
556 slika[i].a = skiny(dd);
557 }
558 break;
559 case 4: //box, linear slope
560 for (i=0;i<w*h;i++)
561 {
562 rgb2hci(ipi2,k32,slika[i].r,slika[i].g,slika[i].b,&sh,&sc,&si);
563 dd = dist_box_c(kh, kc, ki, ddh, ddc, ddi, sh, sc, si);
564 slika[i].a = slope(dd, islp);
565 }
566 break;
567
568 case 10: //ellipsoid, thresholded
569 for (i=0;i<w*h;i++)
570 {
571 rgb2hci(ipi2,k32,slika[i].r,slika[i].g,slika[i].b,&sh,&sc,&si);
572 dd = dist_eli_c(kh, kc, ki, ddh, ddc, ddi, sh, sc, si);
573 slika[i].a = thres(dd);
574 }
575 break;
576 case 11: //ellipsoid, linear fat
577 for (i=0;i<w*h;i++)
578 {
579 rgb2hci(ipi2,k32,slika[i].r,slika[i].g,slika[i].b,&sh,&sc,&si);
580 dd = dist_eli_c(kh, kc, ki, ddh, ddc, ddi, sh, sc, si);
581 slika[i].a = fat(dd);
582 }
583 break;
584 case 12: //ellipsoid, linear normal
585 for (i=0;i<w*h;i++)
586 {
587 rgb2hci(ipi2,k32,slika[i].r,slika[i].g,slika[i].b,&sh,&sc,&si);
588 dd = dist_eli_c(kh, kc, ki, ddh, ddc, ddi, sh, sc, si);
589 slika[i].a = norm(dd);
590 }
591 break;
592 case 13: //ellipsoid, linear skiny
593 for (i=0;i<w*h;i++)
594 {
595 rgb2hci(ipi2,k32,slika[i].r,slika[i].g,slika[i].b,&sh,&sc,&si);
596 dd = dist_eli_c(kh, kc, ki, ddh, ddc, ddi, sh, sc, si);
597 slika[i].a = skiny(dd);
598 }
599 break;
600 case 14: //ellipsoid, linear slope
601 for (i=0;i<w*h;i++)
602 {
603 rgb2hci(ipi2,k32,slika[i].r,slika[i].g,slika[i].b,&sh,&sc,&si);
604 dd = dist_eli_c(kh, kc, ki, ddh, ddc, ddi, sh, sc, si);
605 slika[i].a = slope(dd, islp);
606 }
607 break;
608
609 case 20: //octahedron, thresholded
610 for (i=0;i<w*h;i++)
611 {
612 rgb2hci(ipi2,k32,slika[i].r,slika[i].g,slika[i].b,&sh,&sc,&si);
613 dd = dist_oct_c(kh, kc, ki, ddh, ddc, ddi, sh, sc, si);
614 slika[i].a = thres(dd);
615 }
616 break;
617 case 21: //octahedron, linear fat
618 for (i=0;i<w*h;i++)
619 {
620 rgb2hci(ipi2,k32,slika[i].r,slika[i].g,slika[i].b,&sh,&sc,&si);
621 dd = dist_oct_c(kh, kc, ki, ddh, ddc, ddi, sh, sc, si);
622 slika[i].a = fat(dd);
623 }
624 break;
625 case 22: //octahedron, linear normal
626 for (i=0;i<w*h;i++)
627 {
628 rgb2hci(ipi2,k32,slika[i].r,slika[i].g,slika[i].b,&sh,&sc,&si);
629 dd = dist_oct_c(kh, kc, ki, ddh, ddc, ddi, sh, sc, si);
630 slika[i].a = norm(dd);
631 }
632 break;
633 case 23: //octahedron, linear skiny
634 for (i=0;i<w*h;i++)
635 {
636 rgb2hci(ipi2,k32,slika[i].r,slika[i].g,slika[i].b,&sh,&sc,&si);
637 dd = dist_oct_c(kh, kc, ki, ddh, ddc, ddi, sh, sc, si);
638 slika[i].a = skiny(dd);
639 }
640 break;
641 case 24: //octahedron, linear slope
642 for (i=0;i<w*h;i++)
643 {
644 rgb2hci(ipi2,k32,slika[i].r,slika[i].g,slika[i].b,&sh,&sc,&si);
645 dd = dist_oct_c(kh, kc, ki, ddh, ddc, ddi, sh, sc, si);
646 slika[i].a = slope(dd, islp);
647 }
648 break;
649 default:
650 break;
651 }
652 }
653
654 //----------------------------------------
655 //struktura za instanco efekta
656 typedef struct
657 {
658 int h;
659 int w;
660 f0r_param_color_t col;
661 int subsp;
662 int sshape;
663 float del1,del2,del3;
664 float slp;
665 float nud1,nud2,nud3;
666 int soft;
667 int inv;
668 int op;
669 } inst;
670
671 //-----------------------------------------------------
672 //stretch [0...1] to parameter range [min...max] linear
map_value_forward(double v,float min,float max)673 float map_value_forward(double v, float min, float max)
674 {
675 return min+(max-min)*v;
676 }
677
678 //-----------------------------------------------------
679 //collapse from parameter range [min...max] to [0...1] linear
map_value_backward(float v,float min,float max)680 double map_value_backward(float v, float min, float max)
681 {
682 return (v-min)/(max-min);
683 }
684
685 //***********************************************
686 // OBVEZNE FREI0R FUNKCIJE
687
688 //-----------------------------------------------
f0r_init()689 int f0r_init()
690 {
691 return 1;
692 }
693
694 //------------------------------------------------
f0r_deinit()695 void f0r_deinit()
696 {
697 }
698
699 //-----------------------------------------------
f0r_get_plugin_info(f0r_plugin_info_t * info)700 void f0r_get_plugin_info(f0r_plugin_info_t* info)
701 {
702
703 info->name="select0r";
704 info->author="Marko Cebokli";
705 info->plugin_type=F0R_PLUGIN_TYPE_FILTER;
706 info->color_model=F0R_COLOR_MODEL_RGBA8888;
707 info->frei0r_version=FREI0R_MAJOR_VERSION;
708 info->major_version=0;
709 info->minor_version=6;
710 info->num_params=10;
711 info->explanation="Color based alpha selection";
712 }
713
714 //--------------------------------------------------
f0r_get_param_info(f0r_param_info_t * info,int param_index)715 void f0r_get_param_info(f0r_param_info_t* info, int param_index)
716 {
717 switch(param_index)
718 {
719 case 0:
720 info->name = "Color to select";
721 info->type = F0R_PARAM_COLOR;
722 info->explanation = "";
723 break;
724 case 1:
725 info->name = "Invert selection";
726 info->type = F0R_PARAM_BOOL;
727 info->explanation = "";
728 break;
729 case 2:
730 info->name = "Delta R / A / Hue";
731 info->type = F0R_PARAM_DOUBLE;
732 info->explanation = "";
733 break;
734 case 3:
735 info->name = "Delta G / B / Chroma";
736 info->type = F0R_PARAM_DOUBLE;
737 info->explanation = "";
738 break;
739 case 4:
740 info->name = "Delta B / I / I";
741 info->type = F0R_PARAM_DOUBLE;
742 info->explanation = "";
743 break;
744 case 5:
745 info->name = "Slope";
746 info->type = F0R_PARAM_DOUBLE;
747 info->explanation = "";
748 break;
749 case 6:
750 info->name = "Selection subspace";
751 info->type = F0R_PARAM_DOUBLE;
752 info->explanation = "";
753 break;
754 case 7:
755 info->name = "Subspace shape";
756 info->type = F0R_PARAM_DOUBLE;
757 info->explanation = "";
758 break;
759 case 8:
760 info->name = "Edge mode";
761 info->type = F0R_PARAM_DOUBLE;
762 info->explanation = "";
763 break;
764 case 9:
765 info->name = "Operation";
766 info->type = F0R_PARAM_DOUBLE;
767 info->explanation = "";
768 break;
769 }
770 }
771
772 //----------------------------------------------
f0r_construct(unsigned int width,unsigned int height)773 f0r_instance_t f0r_construct(unsigned int width, unsigned int height)
774 {
775 inst *in;
776
777 in=calloc(1,sizeof(inst));
778
779 in->w=width;
780 in->h=height;
781
782 in->col.r=0.0;
783 in->col.g=0.8;
784 in->col.b=0.0;
785 in->subsp=0;
786 in->sshape=0;
787 in->del1=0.2; in->del2=0.2; in->del3=0.2;
788 in->nud1=0.0; in->nud2=0.0; in->nud3=0.0;
789 in->slp=0.0;
790 in->soft=0;
791 in->inv=0;
792 in->op=0;
793
794 return (f0r_instance_t)in;
795 }
796
797 //---------------------------------------------------
f0r_destruct(f0r_instance_t instance)798 void f0r_destruct(f0r_instance_t instance)
799 {
800 inst *in;
801
802 in=(inst*)instance;
803
804 free(instance);
805 }
806
807 //-----------------------------------------------------
f0r_set_param_value(f0r_instance_t instance,f0r_param_t parm,int param_index)808 void f0r_set_param_value(f0r_instance_t instance, f0r_param_t parm, int param_index)
809 {
810 inst *p;
811 double tmpf;
812 int tmpi,chg;
813 f0r_param_color_t tmpc;
814
815 p=(inst*)instance;
816
817 chg=0;
818 switch(param_index)
819 {
820 case 0: //color
821 tmpc=*(f0r_param_color_t*)parm;
822 if ((tmpc.r!=p->col.r) || (tmpc.g!=p->col.g) || (tmpc.b!=p->col.b))
823 chg=1;
824 p->col=tmpc;
825 break;
826 case 1: //invert
827 tmpi=map_value_forward(*((double*)parm), 0.0, 1.0); //BOOL!!
828 if (p->inv != tmpi) chg=1;
829 p->inv=tmpi;
830 break;
831 case 2: //delta 1
832 tmpf=*(double*)parm;
833 if (tmpf!=p->del1) chg=1;
834 p->del1=tmpf;
835 break;
836 case 3: //delta 2
837 tmpf=*(double*)parm;
838 if (tmpf!=p->del2) chg=1;
839 p->del2=tmpf;
840 break;
841 case 4: //delta 3
842 tmpf=*(double*)parm;
843 if (tmpf!=p->del3) chg=1;
844 p->del3=tmpf;
845 break;
846 case 5: //slope 1
847 tmpf=*(double*)parm;
848 if (tmpf!=p->slp) chg=1;
849 p->slp=tmpf;
850 break;
851 case 6: //subspace
852 tmpi = map_value_forward(*(double*)parm, 0.0, 2.9999); //N-0.0001 if ((tmpi<0)||(tmpi>2.0)) break;
853 if (p->subsp != tmpi) chg=1;
854 p->subsp = tmpi;
855 break;
856 case 7: //shape
857 tmpi = map_value_forward(*(double*)parm, 0.0, 2.9999); //N-0.0001 if ((tmpi<0)||(tmpi>2.0)) break;
858 if (p->sshape != tmpi) chg=1;
859 p->sshape = tmpi;
860 break;
861 case 8: //edge mode
862 tmpi = map_value_forward(*(double*)parm, 0.0, 4.9999); //N-0.0001 if ((tmpi<0)||(tmpi>2.0)) break;
863 if (p->soft != tmpi) chg=1;
864 p->soft = tmpi;
865 break;
866 case 9: //operation
867 tmpi = map_value_forward(*(double*)parm, 0.0, 4.9999); //N-0.0001 if ((tmpi<0)||(tmpi>2.0)) break;
868 if (p->op != tmpi) chg=1;
869 p->op = tmpi;
870 break;
871 }
872
873 if (chg==0) return;
874
875 }
876
877 //--------------------------------------------------
f0r_get_param_value(f0r_instance_t instance,f0r_param_t param,int param_index)878 void f0r_get_param_value(f0r_instance_t instance, f0r_param_t param, int param_index)
879 {
880 inst *p;
881
882 p=(inst*)instance;
883
884 switch(param_index)
885 {
886 case 0:
887 *((f0r_param_color_t*)param)=p->col;
888 break;
889 case 1:
890 *((double*)param)=map_value_backward(p->inv, 0.0, 1.0);//BOOL!!
891 break;
892 case 2:
893 *((double*)param)=p->del1;
894 break;
895 case 3:
896 *((double*)param)=p->del2;
897 break;
898 case 4:
899 *((double*)param)=p->del3;
900 break;
901 case 5:
902 *((double*)param)=p->slp;
903 break;
904 case 6:
905 *((double*)param)=map_value_backward(p->subsp, 0.0, 2.9999);
906 break;
907 case 7:
908 *((double*)param)=map_value_backward(p->sshape, 0.0, 2.9999);
909 break;
910 case 8:
911 *((double*)param)=map_value_backward(p->soft, 0.0, 3.9999);
912 break;
913 case 9:
914 *((double*)param)=map_value_backward(p->op, 0.0, 4.9999);
915 break;
916 }
917 }
918
919 //-------------------------------------------------
920 //RGBA8888 little endian
f0r_update(f0r_instance_t instance,double time,const uint32_t * inframe,uint32_t * outframe)921 void f0r_update(f0r_instance_t instance, double time, const uint32_t* inframe, uint32_t* outframe)
922 {
923 inst *in;
924 float_rgba key;
925 triplet d,n;
926 int i;
927 uint32_t t;
928 uint8_t *cin, *cout;
929 float f1=1.0/256.0;
930 uint8_t a1,a2;
931 float_rgba *sl;
932
933 assert(instance);
934 in=(inst*)instance;
935
936 key.r=in->col.r;
937 key.g=in->col.g;
938 key.b=in->col.b;
939 key.a=1.0;
940 d.x=in->del1;
941 d.y=in->del2;
942 d.z=in->del3;
943 n.x=in->nud1;
944 n.y=in->nud2;
945 n.z=in->nud3;
946
947 //convert to float
948 sl = calloc(in->w * in->h, sizeof(float_rgba));
949 cin=(uint8_t *)inframe;
950 for (i=0;i<in->h*in->w;i++)
951 {
952 sl[i].r=f1*(float)*cin++;
953 sl[i].g=f1*(float)*cin++;
954 sl[i].b=f1*(float)*cin++;
955 cin++;
956 }
957
958 //make the selection
959 switch (in->subsp)
960 {
961 case 0:
962 sel_rgb(sl, in->w, in->h, key, d, n, in->slp, in->sshape, in->soft);
963 break;
964 case 1:
965 sel_abi(sl, in->w, in->h, key, d, n, in->slp, in->sshape, in->soft);
966 break;
967 case 2:
968 sel_hci(sl, in->w, in->h, key, d, n, in->slp, in->sshape, in->soft);
969 break;
970 default:
971 break;
972 }
973
974 //invert selection if required
975 if (in->inv==1)
976 for (i=0;i<in->h*in->w;i++)
977 sl[i].a = 1.0 - sl[i].a;
978
979 //apply alpha
980 cin=(uint8_t *)inframe;
981 cout=(uint8_t *)outframe;
982 switch (in->op)
983 {
984 case 0: //write on clear
985 for (i=0;i<in->h*in->w;i++)
986 {
987 *cout++ = *cin++; //copy R
988 *cout++ = *cin++; //copy G
989 *cout++ = *cin++; //copy B
990 *cout++ = (uint8_t)(sl[i].a*255.0);
991 cin++;
992 }
993 break;
994 case 1: //max
995 for (i=0;i<in->h*in->w;i++)
996 {
997 *cout++ = *cin++; //copy R
998 *cout++ = *cin++; //copy G
999 *cout++ = *cin++; //copy B
1000 a1 = *cin++;
1001 a2 = (uint8_t)(sl[i].a*255.0);
1002 *cout++ = (a1>a2) ? a1 : a2;
1003 }
1004 break;
1005 case 2: //min
1006 for (i=0;i<in->h*in->w;i++)
1007 {
1008 *cout++ = *cin++; //copy R
1009 *cout++ = *cin++; //copy G
1010 *cout++ = *cin++; //copy B
1011 a1 = *cin++;
1012 a2 = (uint8_t)(sl[i].a*255.0);
1013 *cout++ = (a1<a2) ? a1 : a2;
1014 }
1015 break;
1016 case 3: //add
1017 for (i=0;i<in->h*in->w;i++)
1018 {
1019 *cout++ = *cin++; //copy R
1020 *cout++ = *cin++; //copy G
1021 *cout++ = *cin++; //copy B
1022 a1 = *cin++;
1023 a2 = (uint8_t)(sl[i].a*255.0);
1024 t=(uint32_t)a1+(uint32_t)a2;
1025 *cout++ = (t<=255) ? (uint8_t)t : 255;
1026 }
1027 break;
1028 case 4: //subtract
1029 for (i=0;i<in->h*in->w;i++)
1030 {
1031 *cout++ = *cin++; //copy R
1032 *cout++ = *cin++; //copy G
1033 *cout++ = *cin++; //copy B
1034 a1 = *cin++;
1035 a2 = (uint8_t)(sl[i].a*255.0);
1036 *cout++ = (a1>a2) ? a1-a2 : 0;
1037 }
1038 break;
1039 default:
1040 break;
1041 }
1042 free(sl);
1043 }
1044
1045 //**********************************************************
1046