1 /*
2 * Jakdaw's XMMS Plugin.
3 * Copyright (C) 1999, 2000, Christopher Wilson.
4 *
5 * Email: <Jakdaw@usa.net>
6 * Project Homepage: <http://www.jakdaw.ucam.org/xmms/>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 * USA
22 */
23 #include <math.h>
24
25 #include "feedback.h"
26
27 typedef uint32_t (*transform_function) (JakdawPrivate *priv, int x, int y);
28
29 static void init_table(JakdawPrivate *priv);
30 static void table_store(JakdawPrivate *priv, int x);
31 static void blur_then(JakdawPrivate *priv, int x, int y, transform_function func);
32
33 /* Transforms */
34 static uint32_t nothing(JakdawPrivate *priv, int x, int y);
35 static uint32_t scroll(JakdawPrivate *priv, int x, int y);
36 static uint32_t zoom_rotate(JakdawPrivate *priv, int x, int y);
37 static uint32_t zoom_ripple(JakdawPrivate *priv, int x, int y);
38 static uint32_t into_screen(JakdawPrivate *priv, int x, int y);
39 static uint32_t zoom_ripplenew(JakdawPrivate *priv, int x, int y);
40
_jakdaw_feedback_init(JakdawPrivate * priv,int x,int y)41 void _jakdaw_feedback_init(JakdawPrivate *priv, int x, int y)
42 {
43 int a, b;
44
45 init_table(priv);
46 priv->new_image= visual_mem_malloc0 (priv->xres*priv->yres*4);
47
48 for(b=0;b<priv->yres;b++)
49 for(a=0;a<priv->xres;a++)
50 {
51 switch(priv->zoom_mode)
52 {
53 case FEEDBACK_ZOOMRIPPLE: blur_then(priv, a,b,zoom_ripple); break;
54 case FEEDBACK_BLURONLY: blur_then(priv, a,b,nothing); break;
55 case FEEDBACK_ZOOMROTATE: blur_then(priv, a,b,zoom_rotate); break;
56 case FEEDBACK_SCROLL: blur_then(priv, a,b,scroll); break;
57 case FEEDBACK_INTOSCREEN: blur_then(priv, a,b,into_screen); break;
58 case FEEDBACK_NEWRIPPLE: blur_then(priv, a,b,zoom_ripplenew); break;
59 default: blur_then(priv, a,b,nothing);
60 }
61 }
62 }
63
_jakdaw_feedback_reset(JakdawPrivate * priv,int x,int y)64 void _jakdaw_feedback_reset(JakdawPrivate *priv, int x, int y)
65 {
66 // Check whether res or feedback type have changed here
67 _jakdaw_feedback_close(priv);
68 _jakdaw_feedback_init(priv, x,y);
69 }
70
_jakdaw_feedback_close(JakdawPrivate * priv)71 void _jakdaw_feedback_close(JakdawPrivate *priv)
72 {
73 if (priv->new_image != NULL)
74 visual_mem_free (priv->new_image);
75
76 if (priv->table != NULL)
77 visual_mem_free (priv->table);
78 }
79
_jakdaw_feedback_render(JakdawPrivate * priv,uint32_t * vscr)80 void _jakdaw_feedback_render(JakdawPrivate *priv, uint32_t *vscr)
81 {
82 int x,tptr,niptr,a;
83 int r,g,b;
84 int np, rdr, gdr, bdr;
85
86 /* Most feedback effects don't take well to the middle pixel becoming
87 * a bright colour - so we just blank it here. Most effects now rely on
88 * this as a black pixel to be used instead of those that fall off the
89 * edges of the screen. */
90
91 vscr[((priv->yres>>1)*priv->xres)+(priv->xres>>1)]=0;
92
93 tptr=niptr=0;
94
95 np=priv->xres*priv->yres;
96 rdr=priv->decay_rate<<2;
97 gdr=priv->decay_rate<<10;
98 bdr=priv->decay_rate<<18;
99
100 for(x=0;x<np;x++)
101 {
102 /* I dunno how good a job the C compiler makes at optimizing this
103 * loop. Since this is what the plugin spends pretty much all of
104 * it's time doing it might be worth looking into the possiblilty
105 * of optimizing it further. */
106
107 a=vscr[priv->table[tptr++]];
108 r=a&0xff;
109 g=a&0xff00;
110 b=a&0xff0000;
111
112 a=vscr[priv->table[tptr++]];
113 r+=a&0xff;
114 g+=a&0xff00;
115 b+=a&0xff0000;
116
117 a=vscr[priv->table[tptr++]];
118 r+=a&0xff;
119 g+=a&0xff00;
120 b+=a&0xff0000;
121
122 a=vscr[priv->table[tptr++]];
123 r+=a&0xff;
124 g+=a&0xff00;
125 b+=a&0xff0000;
126
127 r=r>rdr ? r-rdr : 0;
128 g=g>gdr ? g-gdr : 0;
129 b=b>bdr ? b-bdr : 0;
130
131 a=(r&0x3fc)|(g&0x3fc00)|(b&0x3fc0000);
132 a>>=2;
133
134 priv->new_image[niptr++]=a;
135
136 }
137
138 visual_mem_copy(vscr, priv->new_image, priv->xres*priv->yres*4);
139 }
140
init_table(JakdawPrivate * priv)141 static void init_table(JakdawPrivate *priv)
142 {
143 priv->table=visual_mem_malloc0(priv->xres*priv->yres*sizeof(uint32_t)*4); // 4 points / pixel
144 priv->tableptr=0;
145 }
146
table_store(JakdawPrivate * priv,int x)147 static void table_store(JakdawPrivate *priv, int x)
148 {
149 priv->table[priv->tableptr++]=x;
150 }
151
blur_then(JakdawPrivate * priv,int x,int y,transform_function func)152 static void blur_then(JakdawPrivate *priv, int x, int y, transform_function func)
153 {
154 uint32_t a;
155
156 a=x+1<priv->xres ? x+1 : x;
157 table_store(priv, func(priv,a,y));
158 a=x-1<0 ? 0 : x-1;
159 table_store(priv, func(priv,a,y));
160 a=y+1<priv->yres ? y+1 : y;
161 table_store(priv, func(priv,x,a));
162 a=y-1<0 ? 0 : y-1;
163 table_store(priv, func(priv,x,a));
164
165 return;
166 }
167
168 // Transform functions ---------------------------------------------------------
169
nothing(JakdawPrivate * priv,int x,int y)170 static uint32_t nothing(JakdawPrivate *priv, int x, int y)
171 {
172 return (y*priv->xres)+x;
173 }
174
scroll(JakdawPrivate * priv,int x,int y)175 static uint32_t scroll(JakdawPrivate *priv, int x, int y)
176 {
177 int retval;
178
179 if(y+6<=priv->yres)
180 retval = ((y+6)*priv->xres)+x;
181 else
182 retval = ((priv->yres>>1)*priv->xres)+(priv->xres>>1);
183
184 if (retval > priv->xres * priv->yres)
185 return priv->xres * priv->yres;
186 else if (retval < 0)
187 return 0;
188 else
189 return retval;
190 }
191
zoom_rotate(JakdawPrivate * priv,int x,int y)192 static uint32_t zoom_rotate(JakdawPrivate *priv, int x, int y)
193 {
194 double ang=5.0*(3.14/180.0);
195 int nx, ny;
196
197 x-=(priv->xres>>1);
198 y-=(priv->yres>>1);
199
200 nx=x*cos(ang) + y*sin(ang);
201 ny=y*cos(ang) - x*sin(ang);
202 nx/=1.2;
203 ny/=1.2;
204
205 nx+=(priv->xres>>1);
206 ny+=(priv->yres>>1);
207
208 if(nx>=priv->xres || nx<0 || ny>=priv->yres || ny<0)
209 {
210 nx=0; ny=0;
211 }
212
213 if(nx<0 || nx>=priv->xres || ny<0 || ny>=priv->yres) { nx=priv->xres>>1; ny=priv->yres>>1; }
214
215 return (ny*priv->xres)+nx;
216
217 }
218
zoom_ripple(JakdawPrivate * priv,int x,int y)219 static uint32_t zoom_ripple(JakdawPrivate *priv, int x, int y)
220 {
221 double dist;
222 int nx, ny;
223
224 x-=(priv->xres>>1);
225 y-=(priv->yres>>1);
226
227 dist=sqrt((x*x)+(y*y));
228
229 dist*=3.14*priv->zoom_ripplesize/sqrt((priv->xres*priv->xres)+(priv->yres*priv->yres));
230
231 nx=x*(priv->zoom_zoomfact+(priv->zoom_ripplefact*sin(dist)));
232 ny=y*(priv->zoom_zoomfact+(priv->zoom_ripplefact*sin(dist)));
233
234 nx+=(priv->xres>>1);
235 ny+=(priv->yres>>1);
236
237 if(nx<0 || nx>=priv->xres || ny<0 || ny>=priv->yres) { nx=priv->xres>>1; ny=priv->yres>>1; }
238
239 return (ny*priv->xres)+nx;
240 }
241
zoom_ripplenew(JakdawPrivate * priv,int x,int y)242 static uint32_t zoom_ripplenew(JakdawPrivate *priv, int x, int y)
243 {
244 double dist;
245 int nx, ny;
246
247 x-=(priv->xres>>1);
248 y-=(priv->yres>>1);
249
250 dist=sqrt((x*x)+(y*y));
251 dist*=3.14*priv->zoom_ripplesize/sqrt((priv->xres*priv->xres)+(priv->yres*priv->yres));
252
253 // FIXME - implement the rest of this!
254
255 nx=x;
256 ny=y;
257
258 nx+=(priv->xres>>1);
259 ny+=(priv->yres>>1);
260
261 if(nx<0 || nx>=priv->xres || ny<0 || ny>=priv->yres) { nx=priv->xres>>1; ny=priv->yres>>1; }
262
263 return (ny*priv->xres)+nx;
264 }
265
into_screen(JakdawPrivate * priv,int x,int y)266 static uint32_t into_screen(JakdawPrivate *priv, int x, int y)
267 {
268 double xfact, yfact;
269 int nx,ny;
270
271 x-=(priv->xres>>1);
272 xfact=1.0+(0.05*((priv->yres-y)/(double)priv->yres));
273 yfact=1.05+(0.05*(y/(double)priv->yres));
274
275 nx=x*xfact;
276 ny=y*yfact;
277
278 nx+=(priv->xres>>1);
279
280 if(nx<0 || nx>=priv->xres || ny<0 || ny>=priv->yres) { nx=priv->xres>>1; ny=priv->yres>>1; }
281
282 return (ny*priv->xres)+nx;
283 }
284
285