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