/* * Jakdaw's XMMS Plugin. * Copyright (C) 1999, 2000, Christopher Wilson. * * Email: * Project Homepage: * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ #include #include "feedback.h" typedef uint32_t (*transform_function) (JakdawPrivate *priv, int x, int y); static void init_table(JakdawPrivate *priv); static void table_store(JakdawPrivate *priv, int x); static void blur_then(JakdawPrivate *priv, int x, int y, transform_function func); /* Transforms */ static uint32_t nothing(JakdawPrivate *priv, int x, int y); static uint32_t scroll(JakdawPrivate *priv, int x, int y); static uint32_t zoom_rotate(JakdawPrivate *priv, int x, int y); static uint32_t zoom_ripple(JakdawPrivate *priv, int x, int y); static uint32_t into_screen(JakdawPrivate *priv, int x, int y); static uint32_t zoom_ripplenew(JakdawPrivate *priv, int x, int y); void _jakdaw_feedback_init(JakdawPrivate *priv, int x, int y) { int a, b; init_table(priv); priv->new_image= visual_mem_malloc0 (priv->xres*priv->yres*4); for(b=0;byres;b++) for(a=0;axres;a++) { switch(priv->zoom_mode) { case FEEDBACK_ZOOMRIPPLE: blur_then(priv, a,b,zoom_ripple); break; case FEEDBACK_BLURONLY: blur_then(priv, a,b,nothing); break; case FEEDBACK_ZOOMROTATE: blur_then(priv, a,b,zoom_rotate); break; case FEEDBACK_SCROLL: blur_then(priv, a,b,scroll); break; case FEEDBACK_INTOSCREEN: blur_then(priv, a,b,into_screen); break; case FEEDBACK_NEWRIPPLE: blur_then(priv, a,b,zoom_ripplenew); break; default: blur_then(priv, a,b,nothing); } } } void _jakdaw_feedback_reset(JakdawPrivate *priv, int x, int y) { // Check whether res or feedback type have changed here _jakdaw_feedback_close(priv); _jakdaw_feedback_init(priv, x,y); } void _jakdaw_feedback_close(JakdawPrivate *priv) { if (priv->new_image != NULL) visual_mem_free (priv->new_image); if (priv->table != NULL) visual_mem_free (priv->table); } void _jakdaw_feedback_render(JakdawPrivate *priv, uint32_t *vscr) { int x,tptr,niptr,a; int r,g,b; int np, rdr, gdr, bdr; /* Most feedback effects don't take well to the middle pixel becoming * a bright colour - so we just blank it here. Most effects now rely on * this as a black pixel to be used instead of those that fall off the * edges of the screen. */ vscr[((priv->yres>>1)*priv->xres)+(priv->xres>>1)]=0; tptr=niptr=0; np=priv->xres*priv->yres; rdr=priv->decay_rate<<2; gdr=priv->decay_rate<<10; bdr=priv->decay_rate<<18; for(x=0;xtable[tptr++]]; r=a&0xff; g=a&0xff00; b=a&0xff0000; a=vscr[priv->table[tptr++]]; r+=a&0xff; g+=a&0xff00; b+=a&0xff0000; a=vscr[priv->table[tptr++]]; r+=a&0xff; g+=a&0xff00; b+=a&0xff0000; a=vscr[priv->table[tptr++]]; r+=a&0xff; g+=a&0xff00; b+=a&0xff0000; r=r>rdr ? r-rdr : 0; g=g>gdr ? g-gdr : 0; b=b>bdr ? b-bdr : 0; a=(r&0x3fc)|(g&0x3fc00)|(b&0x3fc0000); a>>=2; priv->new_image[niptr++]=a; } memcpy(vscr, priv->new_image, priv->xres*priv->yres*4); } static void init_table(JakdawPrivate *priv) { priv->table=visual_mem_malloc0(priv->xres*priv->yres*sizeof(uint32_t)*4); // 4 points / pixel priv->tableptr=0; } static void table_store(JakdawPrivate *priv, int x) { priv->table[priv->tableptr++]=x; } static void blur_then(JakdawPrivate *priv, int x, int y, transform_function func) { uint32_t a; a=x+1xres ? x+1 : x; table_store(priv, func(priv,a,y)); a=x-1<0 ? 0 : x-1; table_store(priv, func(priv,a,y)); a=y+1yres ? y+1 : y; table_store(priv, func(priv,x,a)); a=y-1<0 ? 0 : y-1; table_store(priv, func(priv,x,a)); return; } // Transform functions --------------------------------------------------------- static uint32_t nothing(JakdawPrivate *priv, int x, int y) { return (y*priv->xres)+x; } static uint32_t scroll(JakdawPrivate *priv, int x, int y) { int retval; if(y+6<=priv->yres) retval = ((y+6)*priv->xres)+x; else retval = ((priv->yres>>1)*priv->xres)+(priv->xres>>1); if (retval > priv->xres * priv->yres) return priv->xres * priv->yres; else if (retval < 0) return 0; else return retval; } static uint32_t zoom_rotate(JakdawPrivate *priv, int x, int y) { double ang=5.0*(3.14/180.0); int nx, ny; x-=(priv->xres>>1); y-=(priv->yres>>1); nx=x*cos(ang) + y*sin(ang); ny=y*cos(ang) - x*sin(ang); nx/=1.2; ny/=1.2; nx+=(priv->xres>>1); ny+=(priv->yres>>1); if(nx>=priv->xres || nx<0 || ny>=priv->yres || ny<0) { nx=0; ny=0; } if(nx<0 || nx>=priv->xres || ny<0 || ny>=priv->yres) { nx=priv->xres>>1; ny=priv->yres>>1; } return (ny*priv->xres)+nx; } static uint32_t zoom_ripple(JakdawPrivate *priv, int x, int y) { double dist; int nx, ny; x-=(priv->xres>>1); y-=(priv->yres>>1); dist=sqrt((x*x)+(y*y)); dist*=3.14*priv->zoom_ripplesize/sqrt((priv->xres*priv->xres)+(priv->yres*priv->yres)); nx=x*(priv->zoom_zoomfact+(priv->zoom_ripplefact*sin(dist))); ny=y*(priv->zoom_zoomfact+(priv->zoom_ripplefact*sin(dist))); nx+=(priv->xres>>1); ny+=(priv->yres>>1); if(nx<0 || nx>=priv->xres || ny<0 || ny>=priv->yres) { nx=priv->xres>>1; ny=priv->yres>>1; } return (ny*priv->xres)+nx; } static uint32_t zoom_ripplenew(JakdawPrivate *priv, int x, int y) { double dist; int nx, ny; x-=(priv->xres>>1); y-=(priv->yres>>1); dist=sqrt((x*x)+(y*y)); dist*=3.14*priv->zoom_ripplesize/sqrt((priv->xres*priv->xres)+(priv->yres*priv->yres)); // FIXME - implement the rest of this! nx=x; ny=y; nx+=(priv->xres>>1); ny+=(priv->yres>>1); if(nx<0 || nx>=priv->xres || ny<0 || ny>=priv->yres) { nx=priv->xres>>1; ny=priv->yres>>1; } return (ny*priv->xres)+nx; } static uint32_t into_screen(JakdawPrivate *priv, int x, int y) { double xfact, yfact; int nx,ny; x-=(priv->xres>>1); xfact=1.0+(0.05*((priv->yres-y)/(double)priv->yres)); yfact=1.05+(0.05*(y/(double)priv->yres)); nx=x*xfact; ny=y*yfact; nx+=(priv->xres>>1); if(nx<0 || nx>=priv->xres || ny<0 || ny>=priv->yres) { nx=priv->xres>>1; ny=priv->yres>>1; } return (ny*priv->xres)+nx; }