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