1 /*
2 test_pat_R
3 This frei0r plugin generates resolution test patterns
4 Version 0.1	may 2010
5 
6 Copyright (C) 2010  Marko Cebokli    http://lea.hamradio.si/~s57uuu
7 
8 
9  This program is free software; you can redistribute it and/or modify
10  it under the terms of the GNU General Public License as published by
11  the Free Software Foundation; either version 2 of the License, or
12  (at your option) any later version.
13 
14  This program is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  GNU General Public License for more details.
18 
19  You should have received a copy of the GNU General Public License
20  along with this program; if not, write to the Free Software
21  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 
23 */
24 
25 /***********************************************************
26 Test patterns: Resolution and spatial frequency response
27 
28 The patterns are drawn into a temporary float array, for two reasons:
29 1. drawing routines are color model independent,
30 2. drawing is done only when a parameter changes.
31 
32 only the function float2color()
33 needs to care about color models, endianness, DV legality etc.
34 
35 *************************************************************/
36 
37 //compile:	gcc -Wall -std=c99 -c -fPIC test_pat_R.c -o test_pat_R.o
38 
39 //link: gcc -lm -shared -o test_pat_R.so test_pat_R.o
40 
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <assert.h>
44 #include <math.h>
45 
46 #include "frei0r.h"
47 
48 
49 
50 double PI=3.14159265358979;
51 
52 typedef struct
53 	{
54 	float r;
55 	float g;
56 	float b;
57 	float a;
58 	} float_rgba;
59 
60 
61 //----------------------------------------------------------
draw_rectangle(float * sl,int w,int h,int x,int y,int wr,int hr,float gray)62 void draw_rectangle(float *sl, int w, int h, int x, int y, int wr, int hr, float gray)
63 {
64 int i,j;
65 int zx,kx,zy,ky;
66 
67 zx=x;  if (zx<0) zx=0;
68 zy=y;  if (zy<0) zy=0;
69 kx=x+wr;  if (kx>w) kx=w;
70 ky=y+hr;  if (ky>h) ky=h;
71 for (i=zy;i<ky;i++)
72 	for (j=zx;j<kx;j++)
73 		sl[w*i+j]=gray;
74 
75 }
76 
77 //-------------------------------------------------------
78 //draw one numerical digit, 7-segment style
79 //v=size in x direction (in y it is 2*v)
80 //d= number [0...9]
disp7s(float * sl,int w,int h,int x,int y,int v,int d,float gray)81 void disp7s(float *sl, int w, int h, int x, int y, int v, int d, float gray)
82 {
83 char seg[10]={0xEE,0x24,0xBA,0xB6,0x74,0xD6,0xDE,0xA4,0xFE,0xF6};
84 
85 if ((d<0)||(d>9)) return;
86 
87 if ((seg[d]&0x80)!=0) draw_rectangle(sl,w,h,x,  y-2*v,v,1,gray);
88 if ((seg[d]&0x40)!=0) draw_rectangle(sl,w,h,x,  y-2*v,1,v,gray);
89 if ((seg[d]&0x20)!=0) draw_rectangle(sl,w,h,x+v,y-2*v,1,v,gray);
90 if ((seg[d]&0x10)!=0) draw_rectangle(sl,w,h,x,  y-v,  v,1,gray);
91 if ((seg[d]&0x08)!=0) draw_rectangle(sl,w,h,x,  y-v,  1,v,gray);
92 if ((seg[d]&0x04)!=0) draw_rectangle(sl,w,h,x+v,y-v,  1,v,gray);
93 if ((seg[d]&0x02)!=0) draw_rectangle(sl,w,h,x  ,y,    v,1,gray);
94 }
95 
96 //-----------------------------------------------------------------
97 //draw a floating point number, using disp7s()
98 //v=size
99 //n=number
100 //f=format (as in printf, for example %5.1f)
dispF(float * sl,int w,int h,int x,int y,int v,float n,char * f,float gray)101 void dispF(float *sl, int w, int h, int x, int y, int v, float n, char *f, float gray)
102 {
103 char str[64];
104 int i;
105 
106 sprintf(str,f,n);
107 i=0;
108 while (str[i]!=0)
109 	{
110 	if (str[i]=='-')
111 		draw_rectangle(sl,w,h,x+i*(v+v/3+1),y-v,v,1,gray);
112 	else
113 		disp7s(sl,w,h,x+i*(v+v/3+1),y,v,str[i]-48,gray);
114 	i++;
115 	}
116 
117 }
118 
119 //-----------------------------------------------------------
120 //sweep parallel with bars
121 //x,y,wr,hr same as in draw_rectangle()
122 //f1, f2 as fraction of Nyquist
123 //a = amplitude,     1.0=100% mod [0.0...1.0]
124 //dir:		0=vertical  1=horizontal    sweep
125 //linp:   0=linear frequency sweep   1=linear period sweep
draw_sweep_1(float * sl,int w,int h,int x,int y,int wr,int hr,float f1,float f2,float a,int dir,int linp)126 void draw_sweep_1(float *sl, int w, int h, int x, int y, int wr, int hr, float f1, float f2, float a, int dir, int linp)
127 {
128 int i,j;
129 int zx,kx,zy,ky;
130 double p,dp,dp1,dp2,dt,dt1,dt2;
131 
132 zx=x;  if (zx<0) zx=0;
133 zy=y;  if (zy<0) zy=0;
134 kx=x+wr;  if (kx>w) kx=w;
135 ky=y+hr;  if (ky>h) ky=h;
136 
137 if (f1==0.0) f1=1.0E-12;
138 if (f2==0.0) f2=1.0E-12;
139 dp1=PI*f1; dp2=PI*f2;  //phase steps
140 dt1=1.0/dp1; dt2=1.0/dp2;
141 a=a/2.0;
142 
143 p=0;
144 if (dir==0)
145 	{
146 	for (i=zy;i<ky;i++)
147 		{
148 		if (linp==0)
149 			dp=dp1+(dp2-dp1)*(double)(i-zy)/(double)(ky-zy);
150 		else
151 			{
152 			dt=dt1+(dt2-dt1)*(double)(i-zy)/(double)(ky-zy);
153 			dp=1.0/dt;
154 			}
155 		//zacetna faza tako, da bo v sredini 0
156 		p=-(double)wr/2.0*dp;
157 		for (j=zx;j<kx;j++)
158 			{
159 			sl[w*i+j]=0.5+a*cos(p);
160 			p=p+dp;
161 			}
162 		}
163 	}
164 else
165 	{
166 	for (j=zx;j<kx;j++)
167 		{
168 		if (linp==0)
169 			dp=dp1+(dp2-dp1)*(double)(j-zx)/(double)(kx-zx);
170 		else
171 			{
172 			dt=dt1+(dt2-dt1)*(double)(j-zy)/(double)(kx-zx);
173 			dp=1.0/dt;
174 			}
175 		//zacetna faza tako, da bo v sredini 0
176 		p=-(double)hr/2.0*dp;
177 		for (i=zy;i<ky;i++)
178 			{
179 			sl[w*i+j]=0.5+a*cos(p);
180 			p=p+dp;
181 			}
182 		}
183 	}
184 }
185 
186 //-----------------------------------------------------------
187 //sweep perpendicular to bars
188 //x,y,wr,hr same as in draw_rectangle()
189 //f1, f2 as fraction of Nyquist
190 //a = amplitude,     1.0=100% mod [0.0...1.0]
191 //dir:		0=vertical  1=horizontal    sweep
192 //linp:   0=linear frequency sweep   1=linear period sweep
draw_sweep_2(float * sl,int w,int h,int x,int y,int wr,int hr,float f1,float f2,float a,int dir,int linp)193 void draw_sweep_2(float *sl, int w, int h, int x, int y, int wr, int hr, float f1, float f2, float a, int dir, int linp)
194 {
195 int i,j;
196 int zx,kx,zy,ky;
197 double p,dp,dp1,dp2,dt,dt1,dt2;
198 float s;
199 
200 zx=x;  if (zx<0) zx=0;
201 zy=y;  if (zy<0) zy=0;
202 kx=x+wr;  if (kx>w) kx=w;
203 ky=y+hr;  if (ky>h) ky=h;
204 
205 if (f1==0.0) f1=1.0E-12;
206 if (f2==0.0) f2=1.0E-12;
207 dp1=PI*f1; dp2=PI*f2;  //phase steps
208 dt1=1.0/dp1; dt2=1.0/dp2;
209 a=a/2.0;
210 
211 p=0;
212 if (dir==0)
213 	{
214 	for (i=zy;i<ky;i++)
215 		{
216 		if (linp==0)
217 			dp=dp1+(dp2-dp1)*(double)(i-zy)/(double)(ky-zy);
218 		else
219 			{
220 			dt=dt1+(dt2-dt1)*(double)(i-zy)/(double)(ky-zy);
221 			dp=1.0/dt;
222 			}
223 		p=p+dp;
224 		s=0.5+a*cos(p);
225 		for (j=zx;j<kx;j++)
226 			sl[w*i+j]=s;
227 		}
228 	}
229 else
230 	{
231 	for (j=zx;j<kx;j++)
232 		{
233 		if (linp==0)
234 			dp=dp1+(dp2-dp1)*(double)(j-zx)/(double)(kx-zx);
235 		else
236 			{
237 			dt=dt1+(dt2-dt1)*(double)(j-zy)/(double)(kx-zx);
238 			dp=1.0/dt;
239 			}
240 		p=p+dp;
241 		s=0.5+a*cos(p);
242 		for (i=zy;i<ky;i++)
243 			sl[w*i+j]=s;
244 		}
245 	}
246 }
247 
248 //--------------------------------------------------------------
249 //vertical sweep with labels (frequency changes with y)
250 //a=axis	0=horizontal frequencies   1=vert freqs
251 //amp = amplitude
252 //lps:  0=lin f sweep    1=lin p sweep
253 //ar = pixel aspect ratio (used only for LPPH labels on hor f)
254 //sf,ef		start,end freqs in Nyquists
255 //LPPH (lines per picture height) labels are in "TV lines",
256 //not line pairs. Line pairs = TV lines / 2.0
257 //lf* arrays determine where the labels will be drawn
sweep_v(float * sl,int w,int h,int a,float amp,int lps,float ar,float sf,float ef)258 void sweep_v(float *sl, int w, int h, int a, float amp, int lps, float ar, float sf, float ef)
259 {
260 float xl,nf;
261 float lf1[]={0.05,0.1,0.2,0.3,0.4,0.5,0.6,0.7}; //label lin f  nyq
262 float lf2[]={0.05,0.07,0.1,0.15,0.3,0.7};    //label lin p nyq
263 float lf3[]={100.0,200.0,300.0,400.0,500.0,600.0,700.0,800.0,900.0};
264 float lf4[]={10.0,25.0,50.0,100.0,200.0,400.0,800.0};
265 int i,x,y;
266 
267 for (x=0;x<w*h;x++) sl[x]=0.0;	//black background
268 
269 if ((w==0)||(h==0)) return;
270 if (ef==0.0) ef=1.0E-12;
271 if (sf==0.0) sf=1.0E-12;
272 if (ef==sf) ef=ef+1E-12;
273 
274 if (a==0)
275 	draw_sweep_1(sl,w,h,w/8,h/16,6*w/8,14*h/16, sf, ef, amp, 0, lps);
276 else
277 	draw_sweep_2(sl,w,h,w/8,h/16,6*w/8,14*h/16, sf, ef, amp, 0, lps);
278 
279 //labels
280 if (lps==0)	//lin freq sweep
281 	{
282 	for (i=0;i<sizeof(lf1)/sizeof(float);i++)	//Nyquist
283 		{
284 		xl=(lf1[i]-sf)/(ef-sf);
285 		if ((xl>=0.0)&&(xl<=1.0))
286 			{
287 			x=w/8-60;
288 			y=h/16+xl*(14*h/16);
289 			draw_rectangle(sl,w,h,w/8-15,y,10,3,0.9);
290 			dispF(sl,w,h,x,y+6,6,lf1[i],"%5.2f",0.9);
291 			}
292 		}
293 	for (i=0;i<sizeof(lf3)/sizeof(float);i++)	//LPPH
294 		{
295 		nf=lf3[i]/(float)h;	//lpph to nyquist
296 		if (a==0) nf=nf*ar;
297 		xl=(nf-sf)/(ef-sf);
298 		if ((xl>=0.0)&&(xl<=1.0))
299 			{
300 			x=7*w/8+10;
301 			y=h/16+xl*(14*h/16);
302 			draw_rectangle(sl,w,h,7*w/8+5,y,10,3,0.9);
303 			dispF(sl,w,h,x,y+6,6,lf3[i],"%4.0f",0.9);
304 			}
305 		}
306 	}
307 else	//lin period sweep
308 	{
309 	for (i=0;i<sizeof(lf2)/sizeof(float);i++)	//Nyquist
310 		{
311 		xl=(1.0/lf2[i]-1.0/sf)/(1.0/ef-1.0/sf);
312 		if ((xl>=0.0)&&(xl<=1.0))
313 			{
314 			x=w/8-60;
315 			y=h/16+xl*(14*h/16);
316 			draw_rectangle(sl,w,h,w/8-15,y,10,3,0.9);
317 			dispF(sl,w,h,x,y+6,6,lf2[i],"%5.2f",0.9);
318 			}
319 		}
320 	for (i=0;i<sizeof(lf4)/sizeof(float);i++)	//LPPH
321 		{
322 		nf=lf4[i]/(float)h;	//lpph to nyquist
323 		if (a==0) nf=nf*ar;
324 		xl=(1.0/nf-1.0/sf)/(1.0/ef-1.0/sf);
325 		if ((xl>=0.0)&&(xl<=1.0))
326 			{
327 			x=7*w/8+10;
328 			y=h/16+xl*(14*h/16);
329 			draw_rectangle(sl,w,h,7*w/8+5,y,10,3,0.9);
330 			dispF(sl,w,h,x,y+6,6,lf4[i],"%4.0f",0.9);
331 			}
332 		}
333 	}
334 }
335 
336 //--------------------------------------------------------------
337 //horizontal sweep with labels (frequency changes with x)
338 //a=axis	0=horizontal frequencies   1=vert freqs
339 //amp = amplitude
340 //lps:  0=lin f sweep    1=lin p sweep
341 //ar = pixel aspect ratio (used only for LPPH labels on hor f)
342 //sf,ef		start,end freqs in Nyquists
343 //LPPH (lines per picture height) labels are in "TV lines",
344 //not line pairs. Line pairs = TV lines / 2.0
345 //lf* arrays determine where the labels will be drawn
sweep_h(float * sl,int w,int h,int a,float amp,int lps,float ar,float sf,float ef)346 void sweep_h(float *sl, int w, int h, int a, float amp, int lps, float ar, float sf, float ef)
347 {
348 float xl,nf;
349 float lf1[]={0.05,0.2,0.3,0.4,0.5,0.6,0.7};	 //label lin f nyq
350 float lf2[]={0.05,0.07,0.1,0.15,0.3,0.7};   //label lin p nyq
351 float lf3[]={100.0,200.0,300.0,400.0,500.0,600.0,700.0,800.0,900.0};
352 float lf4[]={10.0,25.0,50.0,100.0,200.0,400.0,800.0};
353 int i,x,y;
354 
355 for (x=0;x<w*h;x++) sl[x]=0.0;	//black background
356 
357 if ((w==0)||(h==0)) return;
358 if (ef==0.0) ef=1.0E-12;
359 if (sf==0.0) sf=1.0E-12;
360 if (ef==sf) ef=ef+1E-12;
361 
362 if (a==0)
363 	draw_sweep_2(sl,w,h,w/16,h/8,14*w/16,6*h/8, sf, ef, amp, 1, lps);
364 else
365 	draw_sweep_1(sl,w,h,w/16,h/8,14*w/16,6*h/8, sf, ef, amp, 1, lps);
366 
367 //labels
368 if (lps==0)	//lin freq sweep
369 	{
370 	for (i=0;i<sizeof(lf1)/sizeof(float);i++)	//Nyquist
371 		{
372 		xl=(lf1[i]-sf)/(ef-sf);
373 		if ((xl>=0.0)&&(xl<=1.0))
374 			{
375 			y=7*h/8+25;
376 			x=w/16+xl*(14*w/16);
377 			draw_rectangle(sl,w,h,x,y-20,3,10,0.9);
378 			dispF(sl,w,h,x-20,y+6,6,lf1[i],"%5.2f",0.9);
379 			}
380 		}
381 	for (i=0;i<sizeof(lf3)/sizeof(float);i++)	//LPPH
382 		{
383 		nf=lf3[i]/(float)h;	//lpph to nyquist
384 		if (a==0) nf=nf*ar;
385 		xl=(nf-sf)/(ef-sf);
386 		if ((xl>=0.0)&&(xl<=1.0))
387 			{
388 			y=h/8-25;
389 			x=w/16+xl*(14*w/16);
390 			draw_rectangle(sl,w,h,x,y+8,3,10,0.9);
391 			dispF(sl,w,h,x-20,y+2,6,lf3[i],"%4.0f",0.9);
392 			}
393 		}
394 	}
395 else	//lin period sweep
396 	{
397 	for (i=0;i<sizeof(lf2)/sizeof(float);i++)	//Nyquist
398 		{
399 		xl=(1.0/lf2[i]-1.0/sf)/(1.0/ef-1.0/sf);
400 		if ((xl>=0.0)&&(xl<=1.0))
401 			{
402 			y=7*h/8+25;
403 			x=w/16+xl*(14*w/16);
404 			draw_rectangle(sl,w,h,x,y-20,3,10,0.9);
405 			dispF(sl,w,h,x-20,y+6,6,lf2[i],"%5.2f",0.9);
406 			}
407 		}
408 	for (i=0;i<sizeof(lf4)/sizeof(float);i++)	//LPPH
409 		{
410 		nf=lf4[i]/(float)h;	//lpph to nyquist
411 		if (a==0) nf=nf*ar;
412 		xl=(1.0/nf-1.0/sf)/(1.0/ef-1.0/sf);
413 		if ((xl>=0.0)&&(xl<=1.0))
414 			{
415 			y=h/8-25;
416 			x=w/16+xl*(14*w/16);
417 			draw_rectangle(sl,w,h,x,y+8,3,10,0.9);
418 			dispF(sl,w,h,x-20,y+2,6,lf4[i],"%4.0f",0.9);
419 			}
420 		}
421 	}
422 }
423 
424 //----------------------------------------------------------
425 //draws a "Siemens star" pattern
426 //ar = pixel aspect ratio (not used currently)
427 //np = numbers of periods around the circle
radials(float * sl,int w,int h,float a,float ar,float np)428 void radials(float *sl, int w, int h, float a, float ar, float np)
429 {
430 float an,s,c,g,da,r,rmin,rmax;
431 int x,y;
432 
433 da=PI/2000.0;
434 
435 for (x=0;x<w*h;x++) sl[x]=0.5;	//gray background
436 
437 a=a/2.0;
438 rmin=np/0.7/2.0/PI;	//inner edge at 0.7 Nyquist
439 rmax=(float)h/2.4;
440 for (an=0.0; an<2.0*PI; an=an+da)
441 	{
442 	g=0.5+a*cosf(np*an);
443 	c=cosf(an); s=sinf(an);
444 	for (r=rmin; r<rmax; r=r+1.0)
445 		{
446 		x=w/2+r*c;
447 		y=h/2+r*s;
448 		sl[y*w+x]=g;
449 		}
450 	}
451 
452 }
453 
454 //----------------------------------------------------------
455 //dir: 0=LF inside
456 //linp==1  lin period sweep
457 //sf,ef		start,end freqs in Nyquists
458 //ar = pixel aspect ratio (not used currently)
rings(float * sl,int w,int h,float a,float ar,int linp,float sf,float ef)459 void rings(float *sl, int w, int h, float a, float ar, int linp, float sf, float ef)
460 {
461 float k,m,g,p,da,r,rmax;
462 int x,y;
463 
464 da=PI/2000.0;
465 
466 if (h==0) return;
467 
468 a=a/2.0;
469 rmax=(float)h/2.1;
470 if (linp==0)
471 	{
472 	m=sf*PI;
473 	k=0.5*(ef-sf)*PI/rmax;
474 
475 	p=(k*rmax+m)*rmax;
476 	g=0.5+a*cosf(p);
477 	for (x=0;x<w*h;x++) sl[x]=g; //match background to outer rim
478 
479 	for (x=-rmax;x<rmax;x++)
480 		for (y=-rmax;y<rmax;y++)
481 			{
482 			r=sqrtf(x*x+y*y);
483 			if (r<rmax)
484 				{
485 				p=(k*r+m)*r;
486 				g=0.5+a*cosf(p);
487 				sl[(y+h/2)*w+x+w/2]=g;
488 				}
489 			}
490 	}
491 else
492 	{
493 	m=1.0/sf;
494 	k=(1.0/ef-1.0/sf)/rmax;
495 
496 	p=PI/k*logf(fabsf(m+k*rmax));
497 	g=0.5+a*cosf(p);
498 	for (x=0;x<w*h;x++) sl[x]=g; //match background to outer rim
499 
500 	for (x=-rmax;x<rmax;x++)
501 		for (y=-rmax;y<rmax;y++)
502 			{
503 			r=sqrtf(x*x+y*y);
504 			if (r<rmax)
505 				{
506 				p=PI/k*logf(fabsf(m+k*r));
507 				g=0.5+a*cosf(p);
508 				sl[(y+h/2)*w+x+w/2]=g;
509 				}
510 			}
511 	}
512 
513 }
514 
515 //----------------------------------------------------------
516 //fills frame with constand 2D spatial frequency
517 //ar = pixel aspect ratio (not used currently)
diags(float * sl,int w,int h,float a,float ar,float fh,float fv)518 void diags(float *sl, int w, int h, float a, float ar, float fh, float fv)
519 {
520 int x,y;
521 float p1,p;
522 
523 a=a/2.0;
524 p1=0;
525 for (y=0;y<h;y++)
526 	{
527 	p=p1;
528 	for (x=0;x<w;x++)
529 		{
530 		p=p+PI*fh;
531 		sl[y*w+x]=0.5+a*cosf(p);
532 		}
533 	p1=p1+PI*fv;
534 	}
535 }
536 
537 //-----------------------------------------------------------
538 //Nyquist blocks (horizontal, checkerboard and vertical)
539 //  N and N/2 square wave
540 //a = amplitude
nblocks(float * sl,int w,int h,float a)541 void nblocks(float *sl, int w, int h, float a)
542 {
543 int x,y;
544 float g1,g2;
545 
546 for (x=0;x<w*h;x++) sl[x]=0.5;	//gray background
547 
548 g1=(1.0+a)/2.0; g2=(1.0-a)/2.0;
549 for (y=h/7;y<3*h/7;y++)
550 	{
551 	for (x=w/13;x<4*w/13;x++)
552 		sl[y*w+x]=(y%2==0)?g1:g2;
553 	for (x=5*w/13;x<8*w/13;x++)
554 		sl[y*w+x]=((x+y)%2==0)?g1:g2;
555 	for (x=9*w/13;x<12*w/13;x++)
556 		sl[y*w+x]=(x%2==0)?g1:g2;
557 	}
558 for (y=4*h/7;y<6*h/7;y++)
559 	{
560 	for (x=w/13;x<4*w/13;x++)
561 		sl[y*w+x]=((y/2)%2==0)?g1:g2;
562 	for (x=5*w/13;x<8*w/13;x++)
563 		sl[y*w+x]=((x/2+y/2)%2==0)?g1:g2;
564 	for (x=9*w/13;x<12*w/13;x++)
565 		sl[y*w+x]=((x/2)%2==0)?g1:g2;
566 	}
567 }
568 
569 //---------------------------------------------------------
570 //square wave bars at integer fractions of Nyquist
sqbars(float * sl,int w,int h,float a)571 void sqbars(float *sl, int w, int h, float a)
572 {
573 int x,y;
574 float g1,g2;
575 
576 for (x=0;x<w*h;x++) sl[x]=0.5;	//gray background
577 
578 g1=(1.0+a)/2.0; g2=(1.0-a)/2.0;
579 
580 //horizontals
581 for (y=h/5;y<2*h/5;y++)
582 	{
583 	for (x=w/10;x<2*w/10-w/100;x++)		//Nyquist
584 		if (x%2==0) sl[y*w+x]=g1; else sl[y*w+x]=g2;
585 	for (x=2*w/10;x<3*w/10-w/100;x++)	//Nyquist/2
586 		if ((x/2)%2==0) sl[y*w+x]=g1; else sl[y*w+x]=g2;
587 	for (x=3*w/10;x<4*w/10-w/100;x++)	//Nyquist/3
588 		if ((x/3)%2==0) sl[y*w+x]=g1; else sl[y*w+x]=g2;
589 	for (x=4*w/10;x<5*w/10-w/100;x++)	//Nyquist/4
590 		if ((x/4)%2==0) sl[y*w+x]=g1; else sl[y*w+x]=g2;
591 	for (x=5*w/10;x<6*w/10-w/100;x++)	//Nyquist/5
592 		if ((x/5)%2==0) sl[y*w+x]=g1; else sl[y*w+x]=g2;
593 	for (x=6*w/10;x<7*w/10-w/100;x++)	//Nyquist/6
594 		if ((x/6)%2==0) sl[y*w+x]=g1; else sl[y*w+x]=g2;
595 	for (x=7*w/10;x<8*w/10-w/100;x++)	//Nyquist/7
596 		if ((x/7)%2==0) sl[y*w+x]=g1; else sl[y*w+x]=g2;
597 	for (x=8*w/10;x<9*w/10-w/100;x++)	//Nyquist/8
598 		if ((x/8)%2==0) sl[y*w+x]=g1; else sl[y*w+x]=g2;
599 	}
600 
601 //verticals
602 for (y=3*h/5;y<4*h/5;y++)
603 	{
604 	for (x=w/10;x<2*w/10-w/100;x++)		//Nyquist
605 		if (y%2==0) sl[y*w+x]=g1; else sl[y*w+x]=g2;
606 	for (x=2*w/10;x<3*w/10-w/100;x++)	//Nyquist/2
607 		if ((y/2)%2==0) sl[y*w+x]=g1; else sl[y*w+x]=g2;
608 	for (x=3*w/10;x<4*w/10-w/100;x++)	//Nyquist/3
609 		if ((y/3)%2==0) sl[y*w+x]=g1; else sl[y*w+x]=g2;
610 	for (x=4*w/10;x<5*w/10-w/100;x++)	//Nyquist/4
611 		if ((y/4)%2==0) sl[y*w+x]=g1; else sl[y*w+x]=g2;
612 	for (x=5*w/10;x<6*w/10-w/100;x++)	//Nyquist/5
613 		if ((y/5)%2==0) sl[y*w+x]=g1; else sl[y*w+x]=g2;
614 	for (x=6*w/10;x<7*w/10-w/100;x++)	//Nyquist/6
615 		if ((y/6)%2==0) sl[y*w+x]=g1; else sl[y*w+x]=g2;
616 	for (x=7*w/10;x<8*w/10-w/100;x++)	//Nyquist/7
617 		if ((y/7)%2==0) sl[y*w+x]=g1; else sl[y*w+x]=g2;
618 	for (x=8*w/10;x<9*w/10-w/100;x++)	//Nyquist/8
619 		if ((y/8)%2==0) sl[y*w+x]=g1; else sl[y*w+x]=g2;
620 	}
621 }
622 
623 
624 
625 //-----------------------------------------------------
626 //converts the internal monochrome float image into
627 //Frei0r rgba8888 color
628 //ch selects the channel   0=all  1=R  2=G  3=B
629 //sets alpha to opaque
float2color(float * sl,uint32_t * outframe,int w,int h,int ch)630 void float2color(float *sl, uint32_t* outframe, int w , int h, int ch)
631 {
632 int i,ri,gi,bi;
633 uint32_t p;
634 float r,g,b;
635 
636 switch (ch)
637 	{
638 	case 0:		//all (gray)
639 		for (i=0;i<w*h;i++)
640 			{
641 			p=(uint32_t)(255.0*sl[i]) & 0xFF;
642 			outframe[i] = (p<<16)+(p<<8)+p+0xFF000000;
643 			}
644 		break;
645 	case 1:		//R
646 		for (i=0;i<w*h;i++)
647 			{
648 			p=(uint32_t)(255.0*sl[i]) & 0xFF;
649 			outframe[i] = p+0xFF000000;
650 			}
651 		break;
652 	case 2:		//G
653 		for (i=0;i<w*h;i++)
654 			{
655 			p=(uint32_t)(255.0*sl[i]) & 0xFF;
656 			outframe[i] = (p<<8)+0xFF000000;
657 			}
658 		break;
659 	case 3:		//B
660 		for (i=0;i<w*h;i++)
661 			{
662 			p=(uint32_t)(255.0*sl[i]) & 0xFF;
663 			outframe[i] = (p<<16)+0xFF000000;
664 			}
665 		break;
666 	case 4:		//ccir rec 601  R-Y   on 50 gray
667 		for (i=0;i<w*h;i++)
668 			{
669 			r=sl[i];
670 			b=0.5;
671 			g=(0.5-0.299*r-0.114*b)/0.587;
672 			ri=(int)(255.0*r);
673 			gi=(int)(255.0*g);
674 			bi=(int)(255.0*b);
675 			outframe[i] = (bi<<16)+(gi<<8)+ri+0xFF000000;
676 			}
677 		break;
678 	case 5:		//ccir rec 601  B-Y   on 50% gray
679 		for (i=0;i<w*h;i++)
680 			{
681 			b=sl[i];
682 			r=0.5;
683 			g=(0.5-0.299*r-0.114*b)/0.587;
684 			ri=(int)(255.0*r);
685 			gi=(int)(255.0*g);
686 			bi=(int)(255.0*b);
687 			outframe[i] = (bi<<16)+(gi<<8)+ri+0xFF000000;
688 			}
689 		break;
690 	case 6:		//ccir rec 709  R-Y   on 50 gray
691 		for (i=0;i<w*h;i++)
692 			{
693 			r=sl[i];
694 			b=0.5;
695 			g=(0.5-0.2126*r-0.0722*b)/0.7152;
696 			ri=(int)(255.0*r);
697 			gi=(int)(255.0*g);
698 			bi=(int)(255.0*b);
699 			outframe[i] = (bi<<16)+(gi<<8)+ri+0xFF000000;
700 			}
701 		break;
702 	case 7:		//ccir rec 709  B-Y   on 50% gray
703 		for (i=0;i<w*h;i++)
704 			{
705 			b=sl[i];
706 			r=0.5;
707 			g=(0.5-0.2126*r-0.0722*b)/0.7152;
708 			ri=(int)(255.0*r);
709 			gi=(int)(255.0*g);
710 			bi=(int)(255.0*b);
711 			outframe[i] = (bi<<16)+(gi<<8)+ri+0xFF000000;
712 			}
713 		break;
714 	default:
715 		break;
716 	}
717 
718 }
719 
720 //-----------------------------------------------------
721 //stretch [0...1] to parameter range [min...max] linear
map_value_forward(double v,float min,float max)722 float map_value_forward(double v, float min, float max)
723 {
724 return min+(max-min)*v;
725 }
726 
727 //-----------------------------------------------------
728 //collapse from parameter range [min...max] to [0...1] linear
map_value_backward(float v,float min,float max)729 double map_value_backward(float v, float min, float max)
730 {
731 return (v-min)/(max-min);
732 }
733 
734 //-----------------------------------------------------
735 //stretch [0...1] to parameter range [min...max] logarithmic
736 //min and max must be positive!
map_value_forward_log(double v,float min,float max)737 float map_value_forward_log(double v, float min, float max)
738 {
739 float sr,k;
740 
741 sr=sqrtf(min*max);
742 k=2.0*log(max/sr);
743 return sr*expf(k*(v-0.5));
744 }
745 
746 //-----------------------------------------------------
747 //collapse from parameter range [min...max] to [0...1] logarithmic
748 //min and max must be positive!
map_value_backward_log(float v,float min,float max)749 double map_value_backward_log(float v, float min, float max)
750 {
751 float sr,k;
752 
753 sr=sqrtf(min*max);
754 k=2.0*log(max/sr);
755 return logf(v/sr)/k+0.5;
756 }
757 
758 //**************************************************
759 //obligatory frei0r stuff follows
760 
761 //------------------------------------------------
762 //this structure holds an instance of the test_pat_R plugin
763 typedef struct
764 {
765   unsigned int w;
766   unsigned int h;
767 
768   int type;
769   int chan;
770   float amp;
771   int linp;
772   float f1;
773   float f2;
774   int aspt;
775   float mpar;
776 
777   float par;
778   float *sl;
779 
780 } tp_inst_t;
781 
782 //----------------------------------------------------
f0r_init()783 int f0r_init()
784 {
785   return 1;
786 }
787 
788 //--------------------------------------------------
f0r_deinit()789 void f0r_deinit()
790 { /* no initialization required */ }
791 
792 //--------------------------------------------------
f0r_get_plugin_info(f0r_plugin_info_t * tp_info)793 void f0r_get_plugin_info(f0r_plugin_info_t* tp_info)
794 {
795   tp_info->name           = "test_pat_R";
796   tp_info->author         = "Marko Cebokli";
797   tp_info->plugin_type    = F0R_PLUGIN_TYPE_SOURCE;
798 //  tp_info->plugin_type    = F0R_PLUGIN_TYPE_FILTER;
799   tp_info->color_model    = F0R_COLOR_MODEL_RGBA8888;
800   tp_info->frei0r_version = FREI0R_MAJOR_VERSION;
801   tp_info->major_version  = 0;
802   tp_info->minor_version  = 2;
803   tp_info->num_params     = 8;
804   tp_info->explanation    = "Generates resolution test patterns";
805 }
806 
807 //--------------------------------------------------
f0r_get_param_info(f0r_param_info_t * info,int param_index)808 void f0r_get_param_info(f0r_param_info_t* info, int param_index)
809 {
810   switch (param_index)
811     {
812     case 0:
813       info->name        = "Type";
814       info->type        = F0R_PARAM_DOUBLE;
815       info->explanation = "Type of test pattern"; break;
816     case 1:
817       info->name	="Channel";
818       info->type	= F0R_PARAM_DOUBLE;
819       info->explanation = "Into which color channel to draw";
820       break;
821     case 2:
822       info->name	= "Amplitude";
823       info->type	= F0R_PARAM_DOUBLE;
824       info->explanation = "Amplitude (contrast) of the pattern";
825       break;
826     case 3:
827       info->name        = "Lin P swp";
828       info->type        = F0R_PARAM_BOOL;
829       info->explanation = "Use linear period sweep";
830       break;
831     case 4:
832       info->name	= "Freq 1";
833       info->type	= F0R_PARAM_DOUBLE;
834       info->explanation = "Pattern 7 H frequency";
835       break;
836     case 5:
837       info->name	= "Freq 2";
838       info->type	= F0R_PARAM_DOUBLE;
839       info->explanation = "Pattern 7 V frequency";
840       break;
841     case 6:
842       info->name	="Aspect type";
843       info->type	= F0R_PARAM_DOUBLE;
844       info->explanation = "Pixel aspect ratio presets";
845       break;
846     case 7:
847       info->name	= "Manual aspect";
848       info->type	= F0R_PARAM_DOUBLE;
849       info->explanation = "Manual pixel aspect ratio";
850       break;
851     }
852 }
853 
854 //--------------------------------------------------
f0r_construct(unsigned int width,unsigned int height)855 f0r_instance_t f0r_construct(unsigned int width, unsigned int height)
856 {
857   tp_inst_t* inst = calloc(1, sizeof(*inst));
858   inst->w  = width;
859   inst->h = height;
860 
861   inst->type=0;
862   inst->chan=0;
863   inst->amp=0.8;
864   inst->linp=0;
865   inst->f1=0.03;
866   inst->f2=0.03;
867   inst->aspt=0;
868   inst->mpar=1.0;
869 
870   inst->par=1.0;
871   inst->sl=(float*)calloc(width*height,sizeof(float));
872 
873   sweep_v(inst->sl, inst->w, inst->h, 0, inst->amp, inst->linp, inst->par, 0.05, 0.7);
874 
875   return (f0r_instance_t)inst;
876 }
877 
878 //--------------------------------------------------
f0r_destruct(f0r_instance_t instance)879 void f0r_destruct(f0r_instance_t instance)
880 {
881   tp_inst_t* inst = (tp_inst_t*)instance;
882 
883   free(inst->sl);
884   free(inst);
885 }
886 
887 //--------------------------------------------------
f0r_set_param_value(f0r_instance_t instance,f0r_param_t param,int param_index)888 void f0r_set_param_value(f0r_instance_t instance, f0r_param_t param, int param_index)
889 {
890   tp_inst_t* inst = (tp_inst_t*)instance;
891 
892   f0r_param_double* p = (f0r_param_double*) param;
893 
894   int chg,tmpi;
895   float tmpf;
896 
897   chg=0;
898   switch (param_index)
899     {
900     case 0:	//type
901       tmpf=*((double*)p);
902       if (tmpf>=1.0)
903         tmpi=(int)tmpf;
904       else
905         tmpi = map_value_forward(tmpf, 0.0, 9.9999);
906       if ((tmpi<0)||(tmpi>9.0)) break;
907       if (inst->type != tmpi) chg=1;
908       inst->type = tmpi;
909       break;
910     case 1:	//channel
911       tmpf=*((double*)p);
912       if (tmpf>=1.0)
913         tmpi=(int)tmpf;
914       else
915         tmpi = map_value_forward(tmpf, 0.0, 7.9999);
916       if ((tmpi<0)||(tmpi>7.0)) break;
917       if (inst->chan != tmpi) chg=1;
918       inst->chan = tmpi;
919     case 2:	//amplitude
920       tmpf = map_value_forward(*((double*)p), 0.0, 1.0);
921       if (inst->amp != tmpf) chg=1;
922       inst->amp = tmpf;
923       break;
924     case 3:	//linear period sweep
925       tmpi = map_value_forward(*((double*)p), 0.0, 1.0);
926       if (inst->linp != tmpi) chg=1;
927       inst->linp = tmpi;
928       break;
929     case 4:	//frequency 1
930       tmpf = map_value_forward(*((double*)p), 0.0, 1.0);
931       if (inst->f1 != tmpf) chg=1;
932       inst->f1 = tmpf;
933       break;
934     case 5:	//frequency 2
935       tmpf = map_value_forward(*((double*)p), 0.0, 1.0);
936       if (inst->f2 != tmpf) chg=1;
937       inst->f2 = tmpf;
938       break;
939     case 6:	//aspect type
940       tmpf=*((double*)p);
941       if (tmpf>=1.0)
942         tmpi=(int)tmpf;
943       else
944       tmpi = map_value_forward(tmpf, 0.0, 6.9999);
945       if ((tmpi<0)||(tmpi>6.0)) break;
946       if (inst->aspt != tmpi) chg=1;
947       inst->aspt = tmpi;
948       switch (inst->aspt)	//pixel aspect ratio
949         {
950         case 0: inst->par=1.000;break;		//square pixels
951         case 1: inst->par=1.067;break;		//PAL DV
952         case 2: inst->par=1.455;break;		//PAL wide
953         case 3: inst->par=0.889;break;		//NTSC DV
954         case 4: inst->par=1.212;break;		//NTSC wide
955         case 5: inst->par=1.333;break;		//HDV
956         case 6: inst->par=inst->mpar;break;	//manual
957         }
958       break;
959     case 7:	//manual aspect
960       tmpf = map_value_forward_log(*((double*)p), 0.5, 2.0);
961       if (inst->mpar != tmpf) chg=1;
962       inst->mpar = tmpf;
963       if (inst->aspt==6) inst->par=inst->mpar;
964       break;
965     }
966 
967   if (chg==0) return;
968 
969   switch (inst->type)
970     {
971     case 0:		 //hor freq  ver sweep
972       sweep_v(inst->sl, inst->w, inst->h, 0, inst->amp, inst->linp, inst->par, 0.05, 0.7);
973       break;
974     case 1:		 //hor freq  hor sweep
975       sweep_h(inst->sl, inst->w, inst->h, 0, inst->amp, inst->linp, inst->par, 0.05, 0.7);
976       break;
977     case 2:		 //ver freq  ver sweep
978       sweep_v(inst->sl, inst->w, inst->h, 1, inst->amp, inst->linp, inst->par, 0.05, 0.7); //ver f  ver sw
979       break;
980     case 3:		 //ver freq  hor sweep
981       sweep_h(inst->sl, inst->w, inst->h, 1, inst->amp, inst->linp, inst->par, 0.05, 0.7);
982       break;
983     case 4:		//   "Siemens star"
984       radials(inst->sl, inst->w, inst->h, inst->amp,  inst->par, 60.0);
985       break;
986     case 5:		//rings outwards
987       rings(inst->sl, inst->w, inst->h, inst->amp,  inst->par, inst->linp, 0.05, 0.7);
988       break;
989     case 6:		//rings inwards
990       rings(inst->sl, inst->w, inst->h, inst->amp,  inst->par, inst->linp, 0.7, 0.05);
991       break;
992     case 7:		//uniform 2D spatial frequency
993       diags(inst->sl, inst->w, inst->h, inst->amp,  inst->par, inst->f1, inst->f2);
994       break;
995     case 8:		//   "Nyquist blocks"
996       nblocks(inst->sl, inst->w, inst->h, inst->amp);
997       break;
998     case 9:		//square bars at integer Nyquist fractions
999       sqbars(inst->sl, inst->w, inst->h, inst->amp);
1000       break;
1001     default:
1002       break;
1003     }
1004 
1005 }
1006 
1007 //-------------------------------------------------
f0r_get_param_value(f0r_instance_t instance,f0r_param_t param,int param_index)1008 void f0r_get_param_value(f0r_instance_t instance, f0r_param_t param, int param_index)
1009 {
1010   tp_inst_t* inst = (tp_inst_t*)instance;
1011 
1012   f0r_param_double* p = (f0r_param_double*) param;
1013 
1014   switch (param_index)
1015     {
1016     case 0:	//type
1017       *p = map_value_backward(inst->type, 0.0, 9.9999);
1018       break;
1019     case 1:	//channel
1020       *p = map_value_backward(inst->chan, 0.0, 7.9999);
1021       break;
1022     case 2:	//amplitude
1023       *p = map_value_backward(inst->amp, 0.0, 1.0);
1024       break;
1025     case 3:	//linear period sweep
1026       *p = map_value_backward(inst->linp, 0.0, 1.0);
1027       break;
1028     case 4:	//frequency 1
1029       *p = map_value_backward(inst->f1, 0.0, 1.0);
1030       break;
1031     case 5:	//frequency 2
1032       *p = map_value_backward(inst->f2, 0.0, 1.0);
1033       break;
1034     case 6:	//aspect type
1035       *p = map_value_backward(inst->aspt, 0.0, 6.9999);
1036       break;
1037     case 7:	//manual aspect
1038       *p = map_value_backward_log(inst->mpar, 0.5, 2.0);
1039       break;
1040     }
1041 }
1042 
1043 //---------------------------------------------------
f0r_update(f0r_instance_t instance,double time,const uint32_t * inframe,uint32_t * outframe)1044 void f0r_update(f0r_instance_t instance, double time, const uint32_t* inframe, uint32_t* outframe)
1045 {
1046 
1047   assert(instance);
1048   tp_inst_t* inst = (tp_inst_t*)instance;
1049 
1050   float2color(inst->sl, outframe, inst->w , inst->h, inst->chan);
1051 
1052 }
1053