/*
alphaspot.c
This frei0r plugin draws simple shapes into the alpha channel
Version 0.1 aug 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.
*/
//compile: gcc -c -fPIC -Wall alphaspot.c -o alphaspot.o
//link: gcc -shared -o alphaspot.so alphaspot.o
//#include <stdio.h>
#include <frei0r.h>
#include <stdlib.h>
#include <math.h>
#include <assert.h>
//----------------------------------------
//struktura za instanco efekta
typedef struct
{
int h;
int w;
float pozx,pozy,sizx,sizy,wdt,tilt,min,max;
int shp,op;
uint32_t *gr8;
} inst;
//----------------------------------------------------------
//general (rotated) rectangle with soft border
void gen_rec_s(uint32_t* sl, int w, int h, float siz1, float siz2, float tilt, float pozx, float pozy, float min, float max, float wb)
{
int i,j;
float d1,d2,d,db,st,ct,g,is1,is2;
if ((siz1==0.0)||(siz2==0.0)) return;
st=sinf(tilt);
ct=cosf(tilt);
is1=1.0/siz1;
is2=1.0/siz2;
for (i=0;i<h;i++)
for (j=0;j<w;j++)
{
d1=(i-pozy)*st+(j-pozx)*ct;
d2=(i-pozy)*ct-(j-pozx)*st;
d1=fabsf(d1)*is1;
d2=fabsf(d2)*is2;
d=(d1<d2)?d2:d1;
d1=1.0-(1.0-d1)*is2/is1;
db=(d1<d2)?d2:d1;
if (fabsf(d)>1.0)
g=min;
else
{
if (db<=1.004-wb)
g=max;
else
{
g=min+(1.0-wb-db)/wb*(max-min);
}
}
g=g*255.0;
sl[i*w+j] = (((uint32_t)g)<<24)&0xFF000000;
}
}
//----------------------------------------------------------
//general (rotated) ellipse with soft border
void gen_eli_s(uint32_t* sl, int w, int h, float siz1, float siz2, float tilt, float pozx, float pozy, float min, float max, float wb)
{
int i,j;
float d1,d2,d,db,st,ct,is1,is2,g,wbb;
if ((siz1==0.0)||(siz2==0.0)) return;
st=sinf(tilt);
ct=cosf(tilt);
is1=1.0/siz1;
is2=1.0/siz2;
wbb=wb;
for (i=0;i<h;i++)
for (j=0;j<w;j++)
{
d1=(i-pozy)*st+(j-pozx)*ct;
d2=(i-pozy)*ct-(j-pozx)*st;
d=hypotf(d1*is1,d2*is2);
db=d; //neenakomeren rob!!!
if (d>1.0)
g=min;
else
{
if (db<=1.004-wb)
g=max;
else
{
g=min+(1.0-wb-db)/wb*(max-min);
}
}
g=g*255.0;
sl[i*w+j] = (((uint32_t)g)<<24)&0xFF000000;
}
}
//----------------------------------------------------------
//general (rotated) triangle with soft border
void gen_tri_s(uint32_t* sl, int w, int h, float siz1, float siz2, float tilt, float pozx, float pozy, float min, float max, float wb)
{
int i,j;
float d1,d2,d3,d4,d,st,ct,is1,is2,k5,lim,db,g;
if ((siz1==0.0)||(siz2==0.0)) return;
st=sinf(tilt);
ct=cosf(tilt);
is1=1.0/siz1;
is2=1.0/siz2;
k5=1.0/sqrtf(5.0);
lim=0.82;
for (i=0;i<h;i++)
for (j=0;j<w;j++)
{
d1=(i-pozy)*st+(j-pozx)*ct;
d2=(i-pozy)*ct-(j-pozx)*st;
d1=d1*is1;
d2=d2*is2;
d3=(2.0*d1+d2+1.0)*k5;
d4=(2.0*d1-d2-1.0)*k5;
d2=fabsf(d2);
d3=fabsf(d3);
d4=fabsf(d4);
d=d2;
if (d3>d) d=d3;
if (d4>d) d=d4;
db=d;
if (fabsf(d)>lim)
g=min;
else
{
if (db<=1.004*lim-wb)
g=max;
else
{
g=min+(lim-wb-db)/wb*(max-min);
}
}
g=g*255.0;
sl[i*w+j] = (((uint32_t)g)<<24)&0xFF000000;
}
}
//----------------------------------------------------------
//general (rotated) diamond shape with soft border
void gen_dia_s(uint32_t* sl, int w, int h, float siz1, float siz2, float tilt, float pozx, float pozy, float min, float max, float wb)
{
int i,j;
float d1,d2,d,db,st,ct,is1,is2,g;
if ((siz1==0.0)||(siz2==0.0)) return;
st=sinf(tilt);
ct=cosf(tilt);
is1=1.0/siz1;
is2=1.0/siz2;
for (i=0;i<h;i++)
for (j=0;j<w;j++)
{
d1=(i-pozy)*st+(j-pozx)*ct;
d2=(i-pozy)*ct-(j-pozx)*st;
d=fabsf(d1*is1)+fabsf(d2*is2);
db=d;
if (fabsf(d)>1.0)
g=min;
else
{
if (db<=1.004-wb)
g=max;
else
{
g=min+(1.0-wb-db)/wb*(max-min);
}
}
g=g*255.0;
sl[i*w+j] = (((uint32_t)g)<<24)&0xFF000000;
}
}
//-----------------------------------------------------
void draw(inst *in)
{
switch (in->shp)
{
case 0:
gen_rec_s(in->gr8, in->w, in->h, in->sizx*in->w, in->sizy*in->h, in->tilt, in->pozx*in->w, in->pozy*in->h, in->min, in->max, in->wdt);
break;
case 1:
gen_eli_s(in->gr8, in->w, in->h, in->sizx*in->w, in->sizy*in->h, in->tilt, in->pozx*in->w, in->pozy*in->h, in->min, in->max, in->wdt);
break;
case 2:
gen_tri_s(in->gr8, in->w, in->h, in->sizx*in->w, in->sizy*in->h, in->tilt, in->pozx*in->w, in->pozy*in->h, in->min, in->max, in->wdt);
break;
case 3:
gen_dia_s(in->gr8, in->w, in->h, in->sizx*in->w, in->sizy*in->h, in->tilt, in->pozx*in->w, in->pozy*in->h, in->min, in->max, in->wdt);
break;
default:
break;
}
}
//-----------------------------------------------------
//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);
}
//***********************************************
// OBVEZNE FREI0R FUNKCIJE
//-----------------------------------------------
int f0r_init()
{
return 1;
}
//------------------------------------------------
void f0r_deinit()
{
}
//-----------------------------------------------
void f0r_get_plugin_info(f0r_plugin_info_t* info)
{
info->name="alphaspot";
info->author="Marko Cebokli";
info->plugin_type=F0R_PLUGIN_TYPE_FILTER;
info->color_model=F0R_COLOR_MODEL_RGBA8888;
info->frei0r_version=FREI0R_MAJOR_VERSION;
info->major_version=0;
info->minor_version=1;
info->num_params=10;
info->explanation="Draws simple shapes into the alpha channel";
}
//--------------------------------------------------
void f0r_get_param_info(f0r_param_info_t* info, int param_index)
{
switch(param_index)
{
case 0:
info->name = "Shape";
info->type = F0R_PARAM_DOUBLE;
info->explanation = "";
break;
case 1:
info->name = "Position X";
info->type = F0R_PARAM_DOUBLE;
info->explanation = "";
break;
case 2:
info->name = "Position Y";
info->type = F0R_PARAM_DOUBLE;
info->explanation = "";
break;
case 3:
info->name = "Size X";
info->type = F0R_PARAM_DOUBLE;
info->explanation = "";
break;
case 4:
info->name = "Size Y";
info->type = F0R_PARAM_DOUBLE;
info->explanation = "";
break;
case 5:
info->name = "Tilt";
info->type = F0R_PARAM_DOUBLE;
info->explanation = "";
break;
case 6:
info->name = "Transition width";
info->type = F0R_PARAM_DOUBLE;
info->explanation = "";
break;
case 7:
info->name = "Min";
info->type = F0R_PARAM_DOUBLE;
info->explanation = "";
break;
case 8:
info->name = "Max";
info->type = F0R_PARAM_DOUBLE;
info->explanation = "";
break;
case 9:
info->name = "Operation";
info->type = F0R_PARAM_DOUBLE;
info->explanation = "";
break;
}
}
//----------------------------------------------
f0r_instance_t f0r_construct(unsigned int width, unsigned int height)
{
inst *in;
in=calloc(1,sizeof(inst));
in->w=width;
in->h=height;
in->shp=0;
in->pozx=0.5;
in->pozy=0.5;
in->sizx=0.1;
in->sizy=0.1;
in->wdt=0.2;
in->tilt=0.0;
in->min=0.0;
in->max=1.0;
in->op=0;
in->gr8 = (uint32_t*)calloc(in->w*in->h, sizeof(uint32_t));
draw(in);
return (f0r_instance_t)in;
}
//---------------------------------------------------
void f0r_destruct(f0r_instance_t instance)
{
inst *in;
in=(inst*)instance;
free(in->gr8);
free(instance);
}
//-----------------------------------------------------
void f0r_set_param_value(f0r_instance_t instance, f0r_param_t parm, int param_index)
{
inst *p;
double tmpf;
int tmpi,chg;
p=(inst*)instance;
chg=0;
switch(param_index)
{
case 0:
tmpi=map_value_forward(*((double*)parm), 0.0, 3.9999);
if (p->shp != tmpi) chg=1;
p->shp=tmpi;
break;
case 1:
tmpf=*(double*)parm;
if (tmpf!=p->pozx) chg=1;
p->pozx=tmpf;
break;
case 2:
tmpf=*(double*)parm;
if (tmpf!=p->pozy) chg=1;
p->pozy=tmpf;
break;
case 3:
tmpf=*(double*)parm;
if (tmpf!=p->sizx) chg=1;
p->sizx=tmpf;
break;
case 4:
tmpf=*(double*)parm;
if (tmpf!=p->sizy) chg=1;
p->sizy=tmpf;
break;
case 5:
tmpf=map_value_forward(*((double*)parm), -3.15, 3.15);
if (tmpf!=p->tilt) chg=1;
p->tilt=tmpf;
break;
case 6:
tmpf=*(double*)parm;
if (tmpf!=p->wdt) chg=1;
p->wdt=tmpf;
break;
case 7:
tmpf=*(double*)parm;
if (tmpf!=p->min) chg=1;
p->min=tmpf;
break;
case 8:
tmpf=*(double*)parm;
if (tmpf!=p->max) chg=1;
p->max=tmpf;
break;
case 9:
tmpi=map_value_forward(*((double*)parm), 0.0, 4.9999);
if (p->op != tmpi) chg=1;
p->op=tmpi;
break;
}
if (chg==0) return;
draw(p);
}
//--------------------------------------------------
void f0r_get_param_value(f0r_instance_t instance, f0r_param_t param, int param_index)
{
inst *p;
double tmpf;
int tmpi;
p=(inst*)instance;
switch(param_index)
{
case 0:
*((double*)param)=map_value_backward(p->shp, 0.0, 3.9999);
break;
case 1:
*((double*)param)=p->pozx;
break;
case 2:
*((double*)param)=p->pozy;
break;
case 3:
*((double*)param)=p->sizx;
break;
case 4:
*((double*)param)=p->sizy;
break;
case 5:
*((double*)param)=map_value_backward(p->tilt, -3.15, 3.15);
break;
case 6:
*((double*)param)=p->wdt;
break;
case 7:
*((double*)param)=p->min;
break;
case 8:
*((double*)param)=p->max;
break;
case 9:
*((double*)param)=map_value_backward(p->op, 0.0, 4.9999);
break;
}
}
//-------------------------------------------------
void f0r_update(f0r_instance_t instance, double time, const uint32_t* inframe, uint32_t* outframe)
{
inst *in;
int i,j;
float a,d,st,ct;
uint32_t t;
assert(instance);
in=(inst*)instance;
switch (in->op)
{
case 0: //write on clear
for (i=0;i<in->h*in->w;i++)
outframe[i] = (inframe[i]&0x00FFFFFF) | in->gr8[i];
break;
case 1: //max
for (i=0;i<in->h*in->w;i++)
{
t=((inframe[i]&0xFF000000)>in->gr8[i]) ? inframe[i]&0xFF000000 : in->gr8[i];
outframe[i] = (inframe[i]&0x00FFFFFF) | t;
}
break;
case 2: //min
for (i=0;i<in->h*in->w;i++)
{
t=((inframe[i]&0xFF000000)<in->gr8[i]) ? inframe[i]&0xFF000000 : in->gr8[i];
outframe[i] = (inframe[i]&0x00FFFFFF) | t;
}
break;
case 3: //add
for (i=0;i<in->h*in->w;i++)
{
t=((inframe[i]&0xFF000000)>>1)+(in->gr8[i]>>1);
t = (t>0x7F800000) ? 0xFF000000 : t<<1;
outframe[i] = (inframe[i]&0x00FFFFFF) | t;
}
break;
case 4: //subtract
for (i=0;i<in->h*in->w;i++)
{
t= ((inframe[i]&0xFF000000)>in->gr8[i]) ? (inframe[i]&0xFF000000)-in->gr8[i] : 0;
outframe[i] = (inframe[i]&0x00FFFFFF) | t;
}
break;
default:
break;
}
}
//**********************************************************