/*
test_pat_B
This frei0r plugin generates TV test card approximations
Version 0.1 may 2010
Copyright (C) 2010 Marko Cebokli http://lea.hamradio.si/~s57uuu
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/***********************************************************
Test patterns: Broadcast test cards
This plugin draws a set of test patterns, similar to popular
TV test cards
The patterns are drawn into a temporary float array, for two reasons:
1. drawing routines are color model independent,
2. drawing is done only when a parameter changes.
only the function floatrgba2color()
needs to care about color models, endianness, DV legality etc.
*************************************************************/
//compile: gcc -Wall -c -fPIC test_pat_B.c -o test_pat_B.o
//link: gcc -lm -shared -o test_pat_B.so test_pat_B.o
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include "frei0r.h"
double PI=3.14159265358979;
typedef struct
{
float r;
float g;
float b;
float a;
} float_rgba;
//------------------------------------------------------------------
void draw_rectangle(float_rgba *s, int w, int h, float x, float y, float wr, float hr, float_rgba c)
{
int i,j;
int zx,kx,zy,ky;
zx=x; if (zx<0) zx=0;
zy=y; if (zy<0) zy=0;
kx=x+wr; if (kx>w) kx=w;
ky=y+hr; if (ky>h) ky=h;
for (i=zy;i<ky;i++)
for (j=zx;j<kx;j++)
s[w*i+j]=c;
}
//-----------------------------------------------------------
//pocasna za velike kroge.....
void draw_circle(float_rgba *sl, int w, int h, float ar, int x, int y, int rn, int rz, float_rgba c)
{
int i,j;
int zx,kx,zy,ky;
float rr,rmin,rmax;
zx=x-rz/ar-1; if (zx<0) zx=0;
zy=y-rz-1; if (zy<0) zy=0;
kx=x+rz/ar+1; if (kx>w) kx=w;
ky=y+rz+1; if (ky>h) ky=h;
rmin=(float)rn;
rmax=(float)rz;
for (i=zy;i<ky;i++)
for (j=zx;j<kx;j++)
{
rr=sqrtf((i-y)*(i-y)+(j-x)*(j-x)*ar*ar);
if ((rr>=rmin)&&(rr<=rmax)) sl[w*i+j]=c;
}
}
//------------------------------------------------------------------
//ar = pixel aspect ratio
//x,y = center
//xb,yb = upper left corner of box
//vx,vy = size of box
void draw_boxed_circle(float_rgba *s, int w, int h, float x, float y, float r, float xb, float yb, float vx, float vy, float ar, float_rgba c)
{
int xz,yz,xk,yk;
int i,j;
float rr;
xz=x-r/ar-1; if (xz<0) xz=0; if (xz<xb) xz=xb;
xk=x+r/ar+1; if (xk>w) xk=w; if (xk>(xb+vx)) xk=xb+vx;
yz=y-r-1; if (yz<0) yz=0; if (yz<yb) yz=yb;
yk=y+r+1; if (yk>h) yk=h; if (yk>(yb+vy)) yk=yb+vy;
for (i=yz;i<yk;i++)
for (j=xz;j<xk;j++)
{
rr=sqrtf((i-y)*(i-y)+(j-x)*(j-x)*ar*ar);
if (rr<r) s[i*w+j]=c;
}
}
//---------------------------------------------------------
//draw an approximation of the Philips PM5544 test pattern
//ar = pixel aspect ratio
void draw_pm(float_rgba *s, int w, int h, float ar)
{
float_rgba c;
int vky,vkx,nkx,x0,y0,x0d,y0d;
int i,j;
float rk,v1,v2;
float f,df; //faza in korak faze za rastre
float a;
//doloci velikost kocke po y tako, da jih bo po visini 13.x
//z malo rezerve...
vky=(h-25)/13;
//velikost koceke po x prilagodimo glede na frame in pix aspect
vkx=(int)rintf((float)vky/ar);
nkx=w/vkx-1; //stevilo kock po x (naredi da bo vedno liho???)
x0=(w-vkx*nkx)/2; //zacetni offset za centriranje
y0=(h-vky*13)/2;
x0d=x0; y0d=y0; //ostanek na desni in dol
if ((w-vkx*nkx)%2==1) x0d++;
if ((h-vky*13)%2==1) y0d++;
rk=6.0*vky;
c.a=1.0;
//ozadje
c.r=0.45; c.g=0.45; c.b=0.45;
for (i=0;i<w*h;i++) s[i]=c;
//narisi mrezo
c.r=0.92; c.g=0.92; c.b=0.92;
for (i=x0;i<w;i=i+vkx) draw_rectangle(s,w,h,i-1,0,3,h,c);
for (i=y0;i<h;i=i+vky) draw_rectangle(s,w,h,0,i-1,w,3,c);
//robovi
c.r=0.0; c.g=0.0; c.b=0.0;
for (i=x0;i<w;i=i+2*vkx)
{
draw_rectangle(s,w,h,i+2,0,vkx-3,y0-1,c); //zgoraj
draw_rectangle(s,w,h,i+2,h-y0d+2,vkx-3,y0d-2,c);//spodaj
}
for (i=y0;i<h;i=i+2*vky)
draw_rectangle(s,w,h,0,i+2,x0-1,vky-3,c); //levo
for (i=y0;i<h;i=i+2*vky)
{
if ((nkx%2)==0) {c.r=0.98; c.g=0.98; c.b=0.98;}
draw_rectangle(s,w,h,w-x0d+2,i+2,x0d-2,vky-3,c);//desno
}
c.r=0.98; c.g=0.98; c.b=0.98;
for (i=x0+vkx;i<w-vkx;i=i+2*vkx)
{
draw_rectangle(s,w,h,i+2,0,vkx-3,y0-1,c); //zgoraj
draw_rectangle(s,w,h,i+2,h-y0d+2,vkx-3,y0d-2,c);//spodaj
}
for (i=y0+vky;i<h-vky;i=i+2*vky)
draw_rectangle(s,w,h-1,0,i+2,x0-1,vky-3,c); //levo
for (i=y0+vky;i<h-vky;i=i+2*vky)
{
if ((nkx%2)==0) {c.r=0.0; c.g=0.0; c.b=0.0;}
draw_rectangle(s,w,h,w-x0d+2,i+2,x0d-2,vky-3,c);//desno
}
c.r=0.98; c.g=0.98; c.b=0.98;
draw_rectangle(s,w,h,0,0,x0-1,y0-1,c); //zg lev
draw_rectangle(s,w,h,0,h-y0d+2,x0-1,y0d-1,c); //sp lev
if ((nkx%2)==0) {c.r=0.0; c.g=0.0; c.b=0.0;}
draw_rectangle(s,w,h,w-x0d+2,0,x0d-1,y0-1,c); //zg des
draw_rectangle(s,w,h,w-x0d+2,h-y0d+2,x0d-1,y0d-1,c); //sp des
// "slusalke"
c.r=0.158; c.g=0.602; c.b=0.441;
draw_rectangle(s,w,h,x0+vkx+2,y0+vky+2,vkx-3,11*vky/2-2,c);
draw_rectangle(s,w,h,x0+2*vkx-1,y0+vky+2,2,2*vky-3,c);
c.r=0.286; c.g=0.455; c.b=0.861;
draw_rectangle(s,w,h,x0+2*vkx+2,y0+vky+2,vkx-3,2*vky-4,c);
draw_rectangle(s,w,h,x0+2*vkx+1,y0+vky+2,2,2*vky-3,c);
c.r=0.736; c.g=0.307; c.b=0.441;
draw_rectangle(s,w,h,x0+vkx+2,y0+13*vky/2+2,vkx-3,11*vky/2-3,c);
draw_rectangle(s,w,h,x0+2*vkx-1,y0+10*vky+2,2,2*vky-3,c);
c.r=0.609; c.g=0.455; c.b=0.020;
draw_rectangle(s,w,h,x0+2*vkx+2,y0+10*vky+2,vkx-3,2*vky-4,c);
draw_rectangle(s,w,h,x0+2*vkx+1,y0+10*vky+2,2,2*vky-3,c);
c.r=0.286; c.g=0.455; c.b=0.861;
draw_rectangle(s,w,h,x0+(nkx-3)*vkx+2,y0+vky+2,vkx-3,2*vky-4,c);
draw_rectangle(s,w,h,x0+(nkx-2)*vkx-1,y0+vky+2,2,2*vky-3,c);
c.r=0.451; c.g=0.555; c.b=0.000;
draw_rectangle(s,w,h,x0+(nkx-2)*vkx+2,y0+vky+2,vkx-3,11*vky/2-2,c);
draw_rectangle(s,w,h,x0+(nkx-2)*vkx+1,y0+vky+2,2,2*vky-3,c);
c.r=0.609; c.g=0.455; c.b=0.020;
draw_rectangle(s,w,h,x0+(nkx-3)*vkx+2,y0+10*vky+2,vkx-3,2*vky-4,c);
draw_rectangle(s,w,h,x0+(nkx-2)*vkx-1,y0+10*vky+2,2,2*vky-3,c);
c.r=0.455; c.g=0.355; c.b=0.957;
draw_rectangle(s,w,h,x0+(nkx-2)*vkx+2,y0+13*vky/2+2,vkx-3,11*vky/2-3,c);
draw_rectangle(s,w,h,x0+(nkx-2)*vkx+1,y0+10*vky+2,2,2*vky-3,c);
c.r=0.98; c.g=0.98; c.b=0.98;
draw_boxed_circle(s,w,h, w/2.0,h/2.0,rk, 0.0,0.0,w,y0+2*vky, ar,c);
c.r=0.0; c.g=0.0; c.b=0.0; //beli na vrhu
draw_boxed_circle(s,w,h, w/2.0,h/2.0,rk, w/2-6*vkx,y0+2*vky, 12*vkx, 2*vky, ar,c); //crni visine 2
c.r=0.98; c.g=0.98; c.b=0.98;
draw_rectangle(s,w,h,w/2-3*vkx,y0+2*vky,6*vkx,vky,c); //beli za crtico
c.r=0.0; c.g=0.0; c.b=0.0;
draw_rectangle(s,w,h,w/2-2.5*vkx,y0+2*vky,3,vky,c); //crtica
draw_rectangle(s,w,h,w/2-2*vkx,y0+vky,4*vkx,vky,c); //title zg
//izmenicni crno sivi
c.r=0.723; c.g=0.723; c.b=0.723;
v1=vkx*11.09/16.0;
for (i=w/2-5.5*vkx+v1;i<w/2+4*vkx;i=i+2.0*v1)
draw_rectangle(s,w,h,i,y0+3*vky,v1,vky,c);
draw_boxed_circle(s,w,h, w/2.0,h/2.0,rk, w/2-5.5*vkx+15*v1,y0+3*vky,vkx,vky, ar,c);
//barve
v2=rk/3.0/ar;
c.r=0.730; c.g=0.73; c.b=0.0;
draw_boxed_circle(s,w,h, w/2.0,h/2.0,rk, w/2-3*v2,y0+4*vky,v2,2*vky, ar,c);
c.r=0.0; c.g=0.74; c.b=0.74;
draw_rectangle(s,w,h,w/2-2*v2,y0+4*vky,v2,2*vky,c);
c.r=0.0; c.g=0.75; c.b=0.0;
draw_rectangle(s,w,h,w/2-v2,y0+4*vky,v2+1,2*vky,c);
c.r=0.75; c.g=0.0; c.b=0.75;
draw_rectangle(s,w,h,w/2,y0+4*vky,v2,2*vky,c);
c.r=0.765; c.g=0.0; c.b=0.0;
draw_rectangle(s,w,h,w/2+v2,y0+4*vky,v2,2*vky,c);
c.r=0.0; c.g=0.0; c.b=0.765;
draw_boxed_circle(s,w,h, w/2.0,h/2.0,rk, w/2+2*v2,y0+4*vky,v2,2*vky, ar,c);
c.r=0.0; c.g=0.0; c.b=0.0;
draw_boxed_circle(s,w,h, w/2.0,h/2.0,rk, w/2-6.1*vkx,y0+6*vky, 13.2*vkx, 4*vky, ar,c); //crno spodaj, podloga za center, raster, sivine
//rastri
f=3.14;
df=(float)w/42.66/ar; //perioda v pix
df=6.28/df; //fazni korak
for (i=(w/2-2.5*v2);i<(w/2-1.5*v2);i++)
{
a=0.47+0.47*cosf(f);
f=f+df;
c.r=a; c.g=a; c.b=a;
for (j=(y0+7*vky);j<(y0+9*vky);j++)
s[j*w+i]=c;
}
df=(float)w/96.0/ar; df=6.28/df; //fazni korak
for (i=(w/2-1.5*v2);i<(w/2-0.5*v2);i++)
{
a=0.47+0.47*cosf(f);
f=f+df;
c.r=a; c.g=a; c.b=a;
for (j=(y0+7*vky);j<(y0+9*vky);j++)
s[j*w+i]=c;
}
df=(float)w/149.0/ar; df=6.28/df; //fazni korak
for (i=(w/2-0.5*v2);i<(w/2+0.5*v2);i++)
{
a=0.47+0.47*cosf(f);
f=f+df;
c.r=a; c.g=a; c.b=a;
for (j=(y0+7*vky);j<(y0+9*vky);j++)
s[j*w+i]=c;
}
df=(float)w/202.0/ar; df=6.28/df; //fazni korak
for (i=(w/2+0.5*v2);i<(w/2+1.5*v2);i++)
{
a=0.47+0.47*cosf(f);
f=f+df;
c.r=a; c.g=a; c.b=a;
for (j=(y0+7*vky);j<(y0+9*vky);j++)
s[j*w+i]=c;
}
df=(float)w/256.0/ar; df=6.28/df; //fazni korak
for (i=(w/2+1.5*v2);i<(w/2+2.5*v2);i++)
{
a=0.47+0.47*cosf(f);
f=f+df;
c.r=a; c.g=a; c.b=a;
for (j=(y0+7*vky);j<(y0+9*vky);j++)
s[j*w+i]=c;
}
//centralni del
c.r=0.0; c.g=0.0; c.b=0.0;
draw_rectangle(s,w,h,w/2-vkx/2,y0+5*vky,vkx,3*vky,c); //pokonc crni
c.r=0.98; c.g=0.98; c.b=0.98;
draw_rectangle(s,w,h,w/2-rk/ar+1,y0+6.5*vky,2*rk/ar,2,c); //bela crta
for (i=(w/2-5.5*vkx-1);i<(w/2+5.5*vkx);i=i+vkx)
draw_rectangle(s,w,h,i,y0+6*vky,2,vky,c); //bele crtice
draw_rectangle(s,w,h,w/2-1,y0+5*vky,2,3*vky,c); //pokonci bela
//sivine
c.r=0.172; c.g=0.172; c.b=0.172;
draw_rectangle(s,w,h,w/2-2*v2,y0+9*vky,v2,vky,c);
c.r=0.37; c.g=0.37; c.b=0.37;
draw_rectangle(s,w,h,w/2-v2,y0+9*vky,v2+1,vky,c);
c.r=0.566; c.g=0.566; c.b=0.566;
draw_rectangle(s,w,h,w/2,y0+9*vky,v2,vky,c);
c.r=0.77; c.g=0.77; c.b=0.77;
draw_rectangle(s,w,h,w/2+v2,y0+9*vky,v2,vky,c);
c.r=0.97; c.g=0.97; c.b=0.97;
draw_boxed_circle(s,w,h, w/2.0,h/2.0,rk, w/2+2*v2,y0+9*vky, v2, vky, ar,c);
draw_boxed_circle(s,w,h, w/2.0,h/2.0,rk, w/2-rk,y0+10*vky, 2*rk, vky, ar,c); //bela podloga
c.r=0.0; c.g=0.0; c.b=0.0;
draw_rectangle(s,w,h,w/2-3*vkx,y0+10*vky,6*vkx,vky,c); //title sp
c.r=0.97; c.g=0.97; c.b=0.97;
draw_rectangle(s,w,h,w/2-2.5*vkx,y0+10*vky,3,vky,c); //crtica
//spodnji del
c.r=0.73; c.g=0.73; c.b=0.0;
draw_boxed_circle(s,w,h, w/2.0,h/2.0,rk, w/2-4*vkx,y0+11*vky, 4*vkx, 2*vky, ar,c);
draw_boxed_circle(s,w,h, w/2.0,h/2.0,rk, w/2+0.5*vkx,y0+11*vky, 4*vkx, 2*vky, ar,c);
c.r=0.758; c.g=0.0; c.b=0.0;
draw_boxed_circle(s,w,h, w/2.0,h/2.0,rk, w/2-0.5*vkx,y0+11*vky, vkx, 2*vky, ar,c);
}
//---------------------------------------------------------
//draw an approximation of the Telefunken FuBK test pattern
//ar = pixel aspect ratio
//simpl=1: does not draw the circle and central vertical
void draw_fu(float_rgba *s, int w, int h, float ar, int simpl)
{
float_rgba c;
int vky,vkx,nkx,x0,y0;
int i,j,z,k;
float rk,v1;
float f,df; //faza in korak faze za rastre
float a;
//doloci velikost kocke po y tako, da jih bo po visini 14.x
//z malo rezerve...
vky=(h-10)/14;
//velikost koceke po x prilagodimo glede na frame in pix aspect
vkx=(int)rintf((float)vky/ar);
nkx=w/vkx-1; //stevilo kock po x
if (nkx%2==1) nkx--;
x0=(w-vkx*nkx)/2; //zacetni offset za centriranje
if (x0>vkx) x0=x0-vkx;
y0=(h-vky*14)/2;
rk=6.7*vky;
c.a=1.0;
//ozadje
c.r=0.25; c.g=0.25; c.b=0.25;
for (i=0;i<w*h;i++) s[i]=c;
//narisi mrezo
c.r=1.00; c.g=1.00; c.b=1.00;
for (i=x0;i<w;i=i+vkx) draw_rectangle(s,w,h,i-1,0,3,h,c);
for (i=y0;i<h;i=i+vky) draw_rectangle(s,w,h,0,i-1,w,3,c);
//barve zgoraj
c.r=0.75; c.g=0.75; c.b=0.75;
draw_rectangle(s,w,h,w/2-6*vkx+1,y0+2*vky+1,1.5*vkx,3*vky,c);
c.r=0.75; c.g=0.75; c.b=0.0;
draw_rectangle(s,w,h,w/2-4.5*vkx,y0+2*vky+1,1.5*vkx,3*vky,c);
c.r=0.0; c.g=0.75; c.b=0.75;
draw_rectangle(s,w,h,w/2-3*vkx,y0+2*vky+1,1.5*vkx,3*vky,c);
c.r=0.0; c.g=0.75; c.b=0.0;
draw_rectangle(s,w,h,w/2-1.5*vkx,y0+2*vky+1,1.5*vkx,3*vky,c);
c.r=0.75; c.g=0.0; c.b=0.75;
draw_rectangle(s,w,h,w/2,y0+2*vky+1,1.5*vkx,3*vky,c);
c.r=0.75; c.g=0.0; c.b=0.0;
draw_rectangle(s,w,h,w/2+1.5*vkx,y0+2*vky+1,1.5*vkx,3*vky,c);
c.r=0.0; c.g=0.0; c.b=0.75;
draw_rectangle(s,w,h,w/2+3*vkx,y0+2*vky+1,1.5*vkx,3*vky,c);
c.r=0.0; c.g=0.0; c.b=0.0;
draw_rectangle(s,w,h,w/2+4.5*vkx,y0+2*vky+1,1.5*vkx-1,3*vky,c);
//sivine
v1=12*vkx/5;
c.r=0.0; c.g=0.0; c.b=0.0;
draw_rectangle(s,w,h,w/2-6*vkx+1,y0+5*vky,v1-1,2*vky-1,c);
c.r=0.3; c.g=0.3; c.b=0.3;
draw_rectangle(s,w,h,w/2-6*vkx+v1,y0+5*vky,v1,2*vky-1,c);
c.r=0.5; c.g=0.5; c.b=0.5;
draw_rectangle(s,w,h,w/2-6*vkx+2*v1,y0+5*vky,v1,2*vky-1,c);
c.r=0.75; c.g=0.75; c.b=0.75;
draw_rectangle(s,w,h,w/2-6*vkx+3*v1,y0+5*vky,v1,2*vky-1,c);
c.r=1.00; c.g=1.00; c.b=1.00;
draw_rectangle(s,w,h,w/2-6*vkx+4*v1,y0+5*vky,v1,2*vky-1,c);
//bela podloga za title, rasteje in spico
draw_rectangle(s,w,h,w/2-6*vkx,y0+7*vky,12*vkx,3*vky,c);
//title bar
c.r=0.0; c.g=0.0; c.b=0.0;
draw_rectangle(s,w,h,w/2-1.5*v1,y0+7*vky+1,3*v1,vky,c);
//sivina pod rastri
c.r=0.54; c.g=0.54; c.b=0.54;
draw_rectangle(s,w,h,w/2-4.5*vkx,y0+8*vky,10.5*vkx-1,vky,c);
//rastri
f=-3.14/2.0;
df=(float)w/52.0/ar; df=6.28/df; //fazni korak
for (i=(w/2-0.646*rk/ar);i<(w/2-0.373*rk/ar);i++)
{
a=0.5+0.49*cosf(f);
f=f+df;
c.r=a; c.g=a; c.b=a;
for (j=(y0+8*vky);j<(y0+9*vky);j++)
s[j*w+i]=c;
}
f=-3.14/2.0;
df=(float)w/103.0/ar; df=6.28/df; //fazni korak
for (i=(w/2-0.332*rk/ar);i<(w/2-0.060*rk/ar);i++)
{
a=0.5+0.49*cosf(f);
f=f+df;
c.r=a; c.g=a; c.b=a;
for (j=(y0+8*vky);j<(y0+9*vky);j++)
s[j*w+i]=c;
}
f=-3.14/2.0;
df=(float)w/156.0/ar; df=6.28/df; //fazni korak
for (i=(w/2+0.056*rk/ar);i<(w/2+0.299*rk/ar);i++)
{
a=0.5+0.49*cosf(f);
f=f+df;
c.r=a; c.g=a; c.b=a;
for (j=(y0+8*vky);j<(y0+9*vky);j++)
s[j*w+i]=c;
}
//rjava
c.r=0.69; c.g=0.5; c.b=0.0;
draw_rectangle(s,w,h,w/2+0.369*rk/ar,y0+8*vky,0.437*rk/ar,vky,c);
//spica
c.r=0.0; c.g=0.0; c.b=0.0;
v1=vkx/2.857;
z=w/2-v1/2+2;
for (i=(y0+9*vky);i<(y0+10*vky);i++)
{
k=z+v1*((y0+10*vky)-i)/vky;
for (j=z;j<k;j++) s[i*w+j]=c;
}
//rdeci gradient
c.r=1.00; c.g=0.055; c.b=0.375;
draw_rectangle(s,w,h,w/2-6*vkx+1,y0+10*vky+1,2*vkx,vky-1,c);
for (i=(w/2-4*vkx);i<(w/2+2*vkx);i++)
{
a=(((float)w/2.0+2.0*vkx)-(float)i)/(6.0*(float)vkx);
c.r=.999*a; c.g=0.055*a; c.b=0.375*a;
for (j=(y0+10*vky+1);j<(y0+11*vky);j++)
s[j*w+i]=c;
}
//plavi gradient
c.r=0.375; c.g=0.254; c.b=1.00;
draw_rectangle(s,w,h,w/2-6*vkx+1,y0+11*vky,2*vkx,vky-1,c);
for (i=(w/2-4*vkx);i<(w/2+2*vkx);i++)
{
a=(((float)w/2.0+2.0*vkx)-(float)i)/(6.0*(float)vkx);
c.r=.375*a; c.g=0.254*a; c.b=1.00*a;
for (j=(y0+11*vky);j<(y0+12*vky-1);j++)
s[j*w+i]=c;
}
//sivo spodaj desno
c.r=0.375; c.g=0.375; c.b=0.375;
draw_rectangle(s,w,h,w/2+2*vkx,y0+10*vky+1,4*vkx-1,2*vky-2,c);
if (simpl==0)
{
//crta na sredi
c.r=1.00; c.g=1.00; c.b=1.00;
draw_rectangle(s,w,h,w/2-1,y0+5*vky,3,4*vky,c);
//krog
draw_circle(s,w,h,ar,w/2,h/2,rk,rk+3,c);
}
}
//----------------------------------------------------------
//simple color bars
//m=modulation 0: 100% 1: 95% 2: 75%
//r=0 bars only r=1 read area below ("PAL" color bars)
void bars_simple(float_rgba *s, int w, int h, int m, int r)
{
float_rgba white,yellow,cyan,green,magenta,red,blue,black;
int h1;
switch (m)
{
case 0: //100% (PAL) color bars 100.0.100.0
white.r=1.00; white.g=1.00; white.b=1.00;
yellow.r=1.00; yellow.g=1.00; yellow.b=0.0;
cyan.r=0.0; cyan.g=1.00; cyan.b=1.00;
green.r=0.0; green.g=1.00; green.b=0.0;
magenta.r=1.00; magenta.g=0.0; magenta.b=1.00;
red.r=1.00; red.g=0.0; red.b=0.0;
blue.r=0.0; blue.g=0.0; blue.b=1.00;
black.r=0.0; black.g=0.0; black.b=0.0;
break;
case 1: //95% (BBC) color bars 100.0.100.25
white.r=1.00; white.g=1.00; white.b=1.00;
yellow.r=1.00; yellow.g=1.00; yellow.b=0.25;
cyan.r=0.25; cyan.g=1.00; cyan.b=1.00;
green.r=0.25; green.g=1.00; green.b=0.25;
magenta.r=1.00; magenta.g=0.25; magenta.b=1.00;
red.r=1.00; red.g=0.25; red.b=0.25;
blue.r=0.25; blue.g=0.25; blue.b=1.00;
black.r=0.0; black.g=0.0; black.b=0.0;
break;
case 2: //75% (IBA/EBU) color bars 100.0.75.0
white.r=1.00; white.g=1.00; white.b=1.00;
yellow.r=0.75; yellow.g=0.75; yellow.b=0.0;
cyan.r=0.0; cyan.g=0.75; cyan.b=0.75;
green.r=0.0; green.g=0.75; green.b=0.0;
magenta.r=0.75; magenta.g=0.0; magenta.b=0.75;
red.r=0.75; red.g=0.0; red.b=0.0;
blue.r=0.0; blue.g=0.0; blue.b=0.75;
black.r=0.0; black.g=0.0; black.b=0.0;
break;
default:
break;
}
white.a=1.0; yellow.a=1.0; cyan.a=1.0; green.a=1.0;
magenta.a=1.0; red.a=1.0; blue.a=1.0; black.a=1.0;
if (r==0) h1=h; else h1=0.55*h;
draw_rectangle(s,w,h,0*w/8,0,w/8+1,h,white);
draw_rectangle(s,w,h,1*w/8,0,w/8+1,h,yellow);
draw_rectangle(s,w,h,2*w/8,0,w/8+1,h,cyan);
draw_rectangle(s,w,h,3*w/8,0,w/8+1,h,green);
draw_rectangle(s,w,h,4*w/8,0,w/8+1,h,magenta);
draw_rectangle(s,w,h,5*w/8,0,w/8+1,h,red);
draw_rectangle(s,w,h,6*w/8,0,w/8+1,h,blue);
draw_rectangle(s,w,h,7*w/8,0,w/8+1,h,black);
if (r==1)
draw_rectangle(s,w,h,0,h1,w,h-h1,red);
}
//----------------------------------------------------------
//draws an approximation to the SMPTE color bars
void bars_smpte(float_rgba *s, int w, int h)
{
float_rgba c;
c.a=1.0;
//top bars
c.r=0.75; c.g=0.75; c.b=0.75;
draw_rectangle(s,w,h,0*w/7,0,w/7+1,2*h/3+1,c);
c.r=0.75; c.g=0.75; c.b=0.0;
draw_rectangle(s,w,h,1*w/7,0,w/7+1,2*h/3+1,c);
c.r=0.0; c.g=0.75; c.b=0.75;
draw_rectangle(s,w,h,2*w/7,0,w/7+1,2*h/3+1,c);
c.r=0.0; c.g=0.75; c.b=0.0;
draw_rectangle(s,w,h,3*w/7,0,w/7+1,2*h/3+1,c);
c.r=0.75; c.g=0.0; c.b=0.75;
draw_rectangle(s,w,h,4*w/7,0,w/7+1,2*h/3+1,c);
c.r=0.75; c.g=0.0; c.b=0.0;
draw_rectangle(s,w,h,5*w/7,0,w/7+1,2*h/3+1,c);
c.r=0.0; c.g=0.0; c.b=0.75;
draw_rectangle(s,w,h,6*w/7,0,w/7+1,2*h/3+1,c);
//middle bars
c.r=0.0; c.g=0.0; c.b=0.75;
draw_rectangle(s,w,h,0*w/7,2*h/3,w/7+1,h/12+1,c);
c.r=0.074; c.g=0.074; c.b=0.074;
draw_rectangle(s,w,h,1*w/7,2*h/3,w/7+1,h/12+1,c);
c.r=0.75; c.g=0.0; c.b=0.75;
draw_rectangle(s,w,h,2*w/7,2*h/3,w/7+1,h/12+1,c);
c.r=0.074; c.g=0.074; c.b=0.074;
draw_rectangle(s,w,h,3*w/7,2*h/3,w/7+1,h/12+1,c);
c.r=0.0; c.g=0.75; c.b=0.75;
draw_rectangle(s,w,h,4*w/7,2*h/3,w/7+1,h/12+1,c);
c.r=0.074; c.g=0.074; c.b=0.074;
draw_rectangle(s,w,h,5*w/7,2*h/3,w/7+1,h/12+1,c);
c.r=0.75; c.g=0.75; c.b=0.75;
draw_rectangle(s,w,h,6*w/7,2*h/3,w/7+1,h/12+1,c);
//bottom bars
c.r=0.0; c.g=0.129; c.b=0.297;
draw_rectangle(s,w,h,0*w/28,3*h/4,5*w/28+1,h/4+1,c);
c.r=1.00; c.g=1.00; c.b=1.00;
draw_rectangle(s,w,h,5*w/28,3*h/4,5*w/28+1,h/4+1,c);
c.r=0.195; c.g=0.0; c.b=0.414;
draw_rectangle(s,w,h,10*w/28,3*h/4,5*w/28+1,h/4+1,c);
c.r=0.074; c.g=0.074; c.b=0.074;
draw_rectangle(s,w,h,15*w/28,3*h/4,7*w/28+1,h/4+1,c);
//pluge bars
c.r=0.035; c.g=0.035; c.b=0.035;
draw_rectangle(s,w,h,15*w/21,3*h/4,w/21+1,h/4+1,c);
c.r=0.074; c.g=0.074; c.b=0.074;
draw_rectangle(s,w,h,16*w/21,3*h/4,w/21+1,h/4+1,c);
c.r=0.113; c.g=0.113; c.b=0.113;
draw_rectangle(s,w,h,17*w/21,3*h/4,w/21+1,h/4+1,c);
c.r=0.074; c.g=0.074; c.b=0.074;
draw_rectangle(s,w,h,6*w/7,3*h/4,w/7+1,h/4+1,c);
}
//-----------------------------------------------------
//converts the internal RGB float image into
//Frei0r rgba8888 color
//sets alpha to opaque
void floatrgba2color(float_rgba *sl, uint32_t* outframe, int w , int h)
{
int i;
uint32_t p;
for (i=0;i<w*h;i++)
{
p=(uint32_t)(255.0*sl[i].b) & 0xFF;
p=(p<<8) + ((uint32_t)(255.0*sl[i].g) & 0xFF);
p=(p<<8) + ((uint32_t)(255.0*sl[i].r) & 0xFF);
outframe[i] = p + 0xFF000000; //no transparency
}
}
//-----------------------------------------------------
//stretch [0...1] to parameter range [min...max] linear
float map_value_forward(double v, float min, float max)
{
return min+(max-min)*v;
}
//-----------------------------------------------------
//collapse from parameter range [min...max] to [0...1] linear
double map_value_backward(float v, float min, float max)
{
return (v-min)/(max-min);
}
//-----------------------------------------------------
//stretch [0...1] to parameter range [min...max] logarithmic
//min and max must be positive!
float map_value_forward_log(double v, float min, float max)
{
float sr,k;
sr=sqrtf(min*max);
k=2.0*log(max/sr);
return sr*expf(k*(v-0.5));
}
//-----------------------------------------------------
//collapse from parameter range [min...max] to [0...1] logarithmic
//min and max must be positive!
double map_value_backward_log(float v, float min, float max)
{
float sr,k;
sr=sqrtf(min*max);
k=2.0*log(max/sr);
return logf(v/sr)/k+0.5;
}
//**************************************************
//obligatory frei0r stuff follows
//------------------------------------------------
//this structure holds an instance of the test_pat_B plugin
typedef struct
{
unsigned int w;
unsigned int h;
int type;
int aspt;
float mpar;
float par;
float_rgba *sl;
} tp_inst_t;
//----------------------------------------------------
int f0r_init()
{
return 1;
}
//--------------------------------------------------
void f0r_deinit()
{ /* no initialization required */ }
//--------------------------------------------------
void f0r_get_plugin_info(f0r_plugin_info_t* tp_info)
{
tp_info->name = "test_pat_B";
tp_info->author = "Marko Cebokli";
tp_info->plugin_type = F0R_PLUGIN_TYPE_SOURCE;
// tp_info->plugin_type = F0R_PLUGIN_TYPE_FILTER;
tp_info->color_model = F0R_COLOR_MODEL_RGBA8888;
tp_info->frei0r_version = FREI0R_MAJOR_VERSION;
tp_info->major_version = 0;
tp_info->minor_version = 1;
tp_info->num_params = 3;
tp_info->explanation = "Generates test card lookalikes";
}
//--------------------------------------------------
void f0r_get_param_info(f0r_param_info_t* info, int param_index)
{
switch (param_index)
{
case 0:
info->name = "Type";
info->type = F0R_PARAM_DOUBLE;
info->explanation = "8 choices, select test pattern"; break;
case 1:
info->name ="Aspect type";
info->type = F0R_PARAM_DOUBLE;
info->explanation = "7 choices, pixel aspect ratio";
break;
case 2:
info->name = "Manual Aspect";
info->type = F0R_PARAM_DOUBLE;
info->explanation = "Manual pixel aspect ratio (Aspect type 6)";
break;
}
}
//--------------------------------------------------
f0r_instance_t f0r_construct(unsigned int width, unsigned int height)
{
tp_inst_t* inst = calloc(1, sizeof(*inst));
inst->w = width;
inst->h = height;
inst->type=0;
inst->aspt=0;
inst->mpar=1.0;
inst->par=1.0;
inst->sl=(float_rgba*)calloc(width*height,sizeof(float_rgba));
bars_simple(inst->sl, inst->w, inst->h, 0, 0);
return (f0r_instance_t)inst;
}
//--------------------------------------------------
void f0r_destruct(f0r_instance_t instance)
{
tp_inst_t* inst = (tp_inst_t*)instance;
free(inst->sl);
free(inst);
}
//--------------------------------------------------
void f0r_set_param_value(f0r_instance_t instance, f0r_param_t param, int param_index)
{
tp_inst_t* inst = (tp_inst_t*)instance;
f0r_param_double* p = (f0r_param_double*) param;
int chg,tmpi;
float tmpf;
chg=0;
switch (param_index)
{
case 0: //type
tmpf=*((double*)p);
if (tmpf>=1.0)
tmpi=(int)tmpf;
else
tmpi = map_value_forward(tmpf, 0.0, 7.9999);
if ((tmpi<0)||(tmpi>7.0)) break;
if (inst->type != tmpi) chg=1;
inst->type = tmpi;
break;
case 1: //aspect type
tmpf=*((double*)p);
if (tmpf>=1.0)
tmpi=(int)tmpf;
else
tmpi = map_value_forward(tmpf, 0.0, 6.9999);
if ((tmpi<0)||(tmpi>6.0)) break;
if (inst->aspt != tmpi) chg=1;
inst->aspt = tmpi;
switch (inst->aspt) //pixel aspect ratio
{
case 0: inst->par=1.000;break; //square pixels
case 1: inst->par=1.067;break; //PAL DV
case 2: inst->par=1.455;break; //PAL wide
case 3: inst->par=0.889;break; //NTSC DV
case 4: inst->par=1.212;break; //NTSC wide
case 5: inst->par=1.333;break; //HDV
case 6: inst->par=inst->mpar;break; //manual
}
break;
case 2: //manual aspect
tmpf = map_value_forward_log(*((double*)p), 0.5, 2.0);
if (inst->mpar != tmpf) chg=1;
inst->mpar = tmpf;
if (inst->aspt==4) inst->par=inst->mpar;
break;
}
if (chg==0) return;
switch (inst->type)
{
case 0: //100% PAL color bars
bars_simple(inst->sl, inst->w, inst->h, 0, 0);
break;
case 1: //PAL color bars with red
bars_simple(inst->sl, inst->w, inst->h, 0, 1);
break;
case 2: //95% BBC color bars
bars_simple(inst->sl, inst->w, inst->h, 1, 0);
break;
case 3: //75% EBU color bars
bars_simple(inst->sl, inst->w, inst->h, 2, 0);
break;
case 4: //SMPTE color bars
bars_smpte(inst->sl, inst->w, inst->h);
break;
case 5: //philips PM5544
draw_pm(inst->sl, inst->w, inst->h, inst->par);
break;
case 6: //FuBK
draw_fu(inst->sl, inst->w, inst->h, inst->par, 0);
break;
case 7: //simplified FuBK
draw_fu(inst->sl, inst->w, inst->h, inst->par, 1);
break;
default:
break;
}
}
//-------------------------------------------------
void f0r_get_param_value(f0r_instance_t instance, f0r_param_t param, int param_index)
{
tp_inst_t* inst = (tp_inst_t*)instance;
f0r_param_double* p = (f0r_param_double*) param;
switch (param_index)
{
case 0: //type
*p = map_value_backward(inst->type, 0.0, 7.9999);
break;
case 1: //aspect type
*p = map_value_backward(inst->aspt, 0.0, 6.9999);
break;
case 2: //manual aspect
*p = map_value_backward_log(inst->mpar, 0.5, 2.0);
break;
}
}
//---------------------------------------------------
void f0r_update(f0r_instance_t instance, double time, const uint32_t* inframe, uint32_t* outframe)
{
assert(instance);
tp_inst_t* inst = (tp_inst_t*)instance;
floatrgba2color(inst->sl, outframe, inst->w , inst->h);
}