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