1 /*
2  *  fx/Filter.cpp
3  *
4  *  Copyright 2009 Peter Barth
5  *
6  *  This file is part of Milkytracker.
7  *
8  *  Milkytracker 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 3 of the License, or
11  *  (at your option) any later version.
12  *
13  *  Milkytracker 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 Milkytracker.  If not, see <http://www.gnu.org/licenses/>.
20  *
21  */
22 
23 #include "BasicTypes.h"
24 #include "fpmath.h"
25 #include "Filter.h"
26 
27 #define PRGB2Short(r,g,b) ((((r))<<11)+(((g))<<5)+((b)))
28 
applyRadialToSector(unsigned short * buffer,int width,int height,int pitch,int xCenter,int yCenter,int xBound,int yBound,int radius,int style)29 void Filter::applyRadialToSector(unsigned short *buffer,
30 								 int width, int height,int pitch,
31 								 int xCenter,int yCenter,int xBound,int yBound,
32 								 int radius, int style)
33 {
34 
35     int stx=-1,sty=-1;
36 
37 	if (yBound>yCenter)
38         sty=1;
39     if (xBound>xCenter)
40         stx=1;
41 
42 	int i = yCenter;
43 
44 	switch (style)
45 	{
46 		case 0:
47 			while (i!=yBound)
48 			{
49 				int j = xCenter;
50 
51 				unsigned short *line = buffer+i*pitch;
52 
53 				int vs = (((yCenter-i)*radius))+(i<<16);
54 				int v0=(vs>>16)*pitch;
55 				int b=(vs>>11)&31;
56 				int v1=v0+pitch;
57 
58 				while (j!=xBound)
59 				{
60 					int h0,h1,h2,h3;
61 					int at;//,c,col;
62 					int u0,u1;
63 					int us = (((xCenter-j)*radius))+(j<<16);
64 
65 					unsigned int mask=0x07e0f81f;
66 
67 					u0=(us>>16);
68 					at=(us>>11)&31;
69 					u1=u0+1;
70 					h0=buffer[(u0+v0)]; h2=buffer[(u0+v1)];
71 					h1=buffer[(u1+v0)]; h3=buffer[(u1+v1)];
72 
73 					h1 = ((h1<<16) | h1)&mask;
74 					h2 = ((h2<<16) | h2)&mask;
75 					h3 = ((h3<<16) | h3)&mask;
76 					h0 = ((h0<<16) | h0)&mask;
77 
78 					int blend_top =((((h1-h0)*(at))>>5)+h0)&mask;
79 
80 					int blend_bot =((((h3-h2)*(at))>>5)+h2)&mask;
81 
82 					int total = ((((blend_bot - blend_top)*(b))>>5)+blend_top)&mask;
83 
84 					int source = line[j];
85 
86 					source = ((source<<16) | source)&mask;
87 
88 					int mix =((((source-total)*(15))>>5)+total)&mask;
89 					line[j]	= (mix | (mix>>16))&0xffff;//( (total & 0xF7DE) >> 1) + ( (source & 0xF7DE) >> 1);
90 
91 					j+=stx;
92 				}
93 
94 				i+=sty;
95 
96 			}
97 			break;
98 
99 		case 1:
100 			while (i!=yBound)
101 			{
102 				int j = xCenter;
103 
104 				unsigned short *line = buffer+i*pitch;
105 
106 				int vs = (((yCenter-i)*radius))+(i<<16);
107 				int v0=(vs>>16)*pitch;
108 				int b=(vs>>11)&31;
109 				int v1=v0+pitch;
110 
111 				while (j!=xBound)
112 				{
113 					int h0,h1,h2,h3;
114 					int at;//,c,col;
115 					int u0,u1;
116 					int us = (((xCenter-j)*radius))+(j<<16);
117 
118 					unsigned int mask=0x07e0f81f;
119 
120 					u0=(us>>16);
121 					at=(us>>11)&31;
122 					u1=u0+1;
123 					h0=buffer[(u0+v0)]; h2=buffer[(u0+v1)];
124 					h1=buffer[(u1+v0)]; h3=buffer[(u1+v1)];
125 
126 					h1 = ((h1<<16) | h1)&mask;
127 					h2 = ((h2<<16) | h2)&mask;
128 					h3 = ((h3<<16) | h3)&mask;
129 					h0 = ((h0<<16) | h0)&mask;
130 
131 					int blend_top =((((h1-h0)*(at))>>5)+h0)&mask;
132 
133 					int blend_bot =((((h3-h2)*(at))>>5)+h2)&mask;
134 
135 					int total = ((((blend_bot - blend_top)*(b))>>5)+blend_top)&mask;
136 
137 					int source = line[j];
138 
139 					total = (total | (total>>16))&0xffff;
140 					int r = ((source>>11)+((total>>11))); r-=4; if (r<0) r = 0; if (r>0x1f) r = 0x1f;
141 					int g = (((source>>5)&0x3f)+(((total>>5)&0x3f)));  g-=8; if (g<0) g = 0; if (g>0x3f) g = 0x3f;
142 					int bc = ((source&0x1f)+((total&0x1f)));  bc-=4; if (bc<0) bc = 0; if (bc>0x1f) bc = 0x1f;
143 
144 					line[j] = (r<<11)+(g<<5)+bc;
145 
146 					j+=stx;
147 				}
148 
149 				i+=sty;
150 
151 			}
152 			break;
153 
154 	}
155 
156 }
157 
applyRadial(unsigned short * buffer,int width,int height,int pitch,int xCenter,int yCenter,int radius,int style)158 void Filter::applyRadial(unsigned short *buffer,
159 						 int width, int height,int pitch,
160 						 int xCenter,int yCenter,
161 						 int radius, int style)
162 {
163 
164 	applyRadialToSector(buffer,width, height, pitch, xCenter-1, yCenter-1, 0,     0,      radius, style);
165 	applyRadialToSector(buffer,width, height, pitch, xCenter,   yCenter-1, width, 0,      radius, style);
166 	applyRadialToSector(buffer,width, height, pitch, xCenter-1, yCenter,   0,     height, radius, style);
167 	applyRadialToSector(buffer,width, height, pitch, xCenter,   yCenter,   width, height, radius, style);
168 
169 }
170 
applyHorizontal(unsigned short * src,unsigned short * dst,int width,int height,int pitch,int boxw)171 void Filter::applyHorizontal(unsigned short *src,
172 							 unsigned short *dst,
173 							 int width, int height, int pitch,
174 							 int boxw)
175 {
176 	int x,y;
177 
178 	if (boxw<0)
179 	{
180 		memcpy(dst,src,pitch*height*2); // deal with degenerate kernel sizes
181 		return;
182 	}
183 	if (boxw>=width) boxw=width-1;
184 	int mul=65536/(boxw*2+1);
185 	for (y=0;y<height;y++)
186 	{
187 		int totr=0;
188 		int totg=0;
189 		int totb=0;
190 		for (x=0;x<boxw;x++) {
191 			totr+=src[x]>>11;
192 			totg+=(src[x]>>5)&0x3f;
193 			totb+=src[x]&0x1f;
194 		}
195 
196 		for (x=0;x<width;x++)
197 		{
198 			if (x>boxw) {
199 				totr-=src[(-boxw-1)]>>11;
200 				totg-=(src[(-boxw-1)]>>5)&0x3f;
201 				totb-=src[(-boxw-1)]&0x1f;
202 			}
203 
204 			if (x+boxw<width) {
205 				totr+=src[boxw]>>11;
206 				totg+=(src[boxw]>>5)&0x3f;
207 				totb+=src[boxw]&0x1f;
208 			}
209 			int finalr = (totr*mul)>>16;
210 			int finalg = (totg*mul)>>16;
211 			int finalb = (totb*mul)>>16;
212 			*dst = (finalr<<11)+(finalg<<5)+finalb;
213 			dst++;
214 			src++;
215 		}
216 	}
217 }
218 
applyVertical(unsigned short * src,unsigned short * dst,int width,int height,int pitch,int boxw)219 void Filter::applyVertical(unsigned short *src,
220 						   unsigned short *dst,
221 						   int width, int height, int pitch,
222 						   int boxw)
223 {
224 	int x,y;
225 
226 	if (boxw<0)
227 	{
228 		memcpy(dst,src,pitch*height*2); // deal with degenerate kernel sizes
229 		return;
230 	}
231 	if (boxw>=width) boxw=width-1;
232 	int mul=65536/(boxw*2+1);
233 	for (x=0;x<width;x++)
234 	{
235 		int totr=0;
236 		int totg=0;
237 		int totb=0;
238 
239 		unsigned short* srcPtr = src+x;
240 
241 		for (y=0;y<boxw;y++) {
242 			totr+=*srcPtr>>11;
243 			totg+=(*srcPtr>>5)&0x3f;
244 			totb+=*srcPtr&0x1f;
245 			srcPtr+=width;
246 		}
247 
248 		srcPtr = src+x;
249 		unsigned short* dstPtr = dst+x;
250 
251 		int offsm = (-boxw-1)*pitch;
252 		int offsp = boxw*pitch;
253 
254 		for (y=0;y<height;y++)
255 		{
256 			if (y>boxw) {
257 				totr-=srcPtr[offsm]>>11;
258 				totg-=(srcPtr[offsm]>>5)&0x3f;
259 				totb-=srcPtr[offsm]&0x1f;
260 			}
261 
262 			if (y+boxw<height) {
263 				totr+=srcPtr[offsp]>>11;
264 				totg+=(srcPtr[offsp]>>5)&0x3f;
265 				totb+=srcPtr[offsp]&0x1f;
266 			}
267 			int finalr = (totr*mul)>>16;
268 			int finalg = (totg*mul)>>16;
269 			int finalb = (totb*mul)>>16;
270 			*dstPtr = (finalr<<11)+(finalg<<5)+finalb;
271 			dstPtr+=width;
272 			srcPtr+=width;
273 		}
274 	}
275 }
276 
applyBoxed(unsigned short * srcImage,unsigned short * dstImage,int width,int height,int pitch,int boxw)277 void Filter::applyBoxed(unsigned short *srcImage,
278 						unsigned short *dstImage,
279 						int width, int height, int pitch,
280 						int boxw)
281 {
282 	if (boxw<0)
283 	{
284 		return;
285 	}
286 
287 
288 	//int pitch = width;
289 	int x,y;
290 	int mul = 65536/(boxw*2+1);
291 
292 	{
293 		unsigned short* src = srcImage;
294 
295 		if (boxw>=width) boxw=width-1;
296 		for (y=0;y<height;y++)
297 		{
298 			int totr=0;
299 			int totg=0;
300 			int totb=0;
301 			for (x=0;x<boxw;x++) {
302 				totr+=src[x]>>11;
303 				totg+=(src[x]>>5)&0x3f;
304 				totb+=src[x]&0x1f;
305 			}
306 
307 			unsigned short* dst = dstImage+y;
308 
309 			for (x=0;x<width;x++)
310 			{
311 				if (x>boxw) {
312 					totr-=src[(-boxw-1)]>>11;
313 					totg-=(src[(-boxw-1)]>>5)&0x3f;
314 					totb-=src[(-boxw-1)]&0x1f;
315 				}
316 
317 				if (x+boxw<width) {
318 					totr+=src[boxw]>>11;
319 					totg+=(src[boxw]>>5)&0x3f;
320 					totb+=src[boxw]&0x1f;
321 				}
322 				int finalr = (totr*mul)>>16;
323 				int finalg = (totg*mul)>>16;
324 				int finalb = (totb*mul)>>16;
325 				*dst = (finalr<<11)+(finalg<<5)+finalb;
326 
327 				dst+=height;
328 				src++;
329 			}
330 		}
331 
332 	}
333 
334 	{
335 
336 		if (boxw>=height) boxw=height-1;
337 
338 		unsigned short* src = dstImage;
339 
340 		for (x=0;x<width;x++)
341 		{
342 			int totr=0;
343 			int totg=0;
344 			int totb=0;
345 			for (y=0;y<boxw;y++) {
346 				totr+=src[y]>>11;
347 				totg+=(src[y]>>5)&0x3f;
348 				totb+=src[y]&0x1f;
349 			}
350 
351 			unsigned short* dst = srcImage+x;
352 
353 			for (y=0;y<height;y++)
354 			{
355 				if (y>boxw) {
356 					totr-=src[(-boxw-1)]>>11;
357 					totg-=(src[(-boxw-1)]>>5)&0x3f;
358 					totb-=src[(-boxw-1)]&0x1f;
359 				}
360 
361 				if (y+boxw<height) {
362 					totr+=src[boxw]>>11;
363 					totg+=(src[boxw]>>5)&0x3f;
364 					totb+=src[boxw]&0x1f;
365 				}
366 				int finalr = (totr*mul)>>16;
367 				int finalg = (totg*mul)>>16;
368 				int finalb = (totb*mul)>>16;
369 				*dst = (finalr<<11)+(finalg<<5)+finalb;
370 				//*dst = *src;
371 
372 				src++;
373 				dst+=width;
374 			}
375 		}
376 
377 	}
378 
379 
380 }
381 
stylize(unsigned short * srcImage,unsigned short * tmpImage,int width,int height,int srcPitch,int tmpPitch,int minr,int ming,int minb,int maxr,int maxg,int maxb)382 void Filter::stylize(unsigned short* srcImage,
383 							unsigned short* tmpImage,
384 							int width, int height, int srcPitch, int tmpPitch,
385 							int minr, int ming, int minb,
386 							int maxr, int maxg, int maxb)
387 {
388 	int x,y;
389 
390 	minb>>=3;
391 	ming>>=2; ming<<=5;
392 	minr>>=3; minr<<=11;
393 
394 	maxb>>=3;
395 	maxg>>=2; maxg<<=5;
396 	maxr>>=3; maxr<<=11;
397 
398 	unsigned short* dst = srcImage;
399 	unsigned short* src = tmpImage;
400 
401 	unsigned int* dstDW = (unsigned int*)dst;
402 	unsigned int* srcDW = (unsigned int*)src;
403 
404 	for (y = 0; y < height; y++)
405 	{
406 		for (x = 0; x < width>>1; x++)
407 		{
408 			*srcDW = *dstDW;
409 			srcDW++; dstDW++;
410 		}
411 		srcDW+=(tmpPitch-width)>>1;
412 		dstDW+=(srcPitch-width)>>1;
413 	}
414 
415 	dst = srcImage;
416 	src = tmpImage;
417 
418 	//memcpy(tmpImage, srcImage, pitch*height*2);
419 
420 	int y2;
421 
422 	for (y = 0; y < height; y++)
423 	{
424 		for (x = 0; x < width; x++)
425 		{
426 
427 			//if (*src > RGB2SHORT(50,50,150) &&
428 			//	*src < RGB2SHORT(150,120,200))
429 
430 			if ((*src&0x1f) > (minb) &&
431 				(*src&0x1f) < (maxb) &&
432 				(*src&(0x3f<<5)) > (ming) &&
433 				(*src&(0x3f<<5)) < (maxg) &&
434 				(*src&(0x1f<<11)) > (minr) &&
435 				(*src&(0x1f<<11)) < (maxr))
436 			{
437 
438 				int b = (*src&0x1f)>>2;
439 				int g = ((*src>>5)&0x3f)>>2;
440 				int r = ((*src>>11)&0x1f)>>2;
441 
442 				int from = y-64;
443 				int to = y+64;
444 				int adder = 256/64;
445 				int shade = 0;
446 
447 				if (from < 0)
448 				{
449 					shade+=-from*adder;
450 					from = 0;
451 				}
452 				if (to>height)
453 					to = height;
454 
455 				unsigned short* ptr = srcImage+(from*srcPitch+x);
456 				for (y2 = from; y2 < to; y2++)
457 				{
458 					if (y2 == y)
459 						adder = -adder;
460 					int r2 = ((*ptr>>11)&0x1f) + ((r*shade)>>8);
461 					int g2 = ((*ptr>>5)&0x3f) + ((g*shade)>>8);
462 					int b2 = (*ptr&0x1f) + ((b*shade)>>8);
463 					if (r2 > 0x1f) r2 = 0x1f;
464 					if (g2 > 0x3f) g2 = 0x3f;
465 					if (b2 > 0x1f) b2 = 0x1f;
466 
467 					*ptr = PRGB2SHORT(r2,g2,b2);
468 					ptr+=width;
469 					shade+=adder;
470 				}
471 
472 				from = x-64;
473 				to = x+64;
474 				shade = 0;
475 				adder = 256/64;
476 
477 				if (from < 0)
478 				{
479 					shade+=-from*adder;
480 					from = 0;
481 				}
482 				if (to>width)
483 					to = width;
484 
485 				ptr = srcImage+(y*srcPitch+from);
486 				for (y2 = from; y2 < to; y2++)
487 				{
488 					if (y2 == x)
489 						adder = -adder;
490 					int r2 = ((*ptr>>11)&0x1f) + ((r*shade)>>8);
491 					int g2 = ((*ptr>>5)&0x3f) + ((g*shade)>>8);
492 					int b2 = (*ptr&0x1f) + ((b*shade)>>8);
493 					if (r2 > 0x1f) r2 = 0x1f;
494 					if (g2 > 0x3f) g2 = 0x3f;
495 					if (b2 > 0x1f) b2 = 0x1f;
496 
497 					*ptr = PRGB2SHORT(r2,g2,b2);
498 					ptr++;
499 					shade+=adder;
500 				}
501 
502 			}
503 
504 			src++;
505 		}
506 
507 		src+=tmpPitch-width;
508 
509 	}
510 }
511 
glow(unsigned short * srcImage,int width,int height,int pitch,unsigned short * glowBuffer1,unsigned short * glowBuffer2,unsigned int cellSizeShift,unsigned int scale,unsigned int boxw)512 void Filter::glow(unsigned short* srcImage,
513 				  int width, int height, int pitch,
514 				  unsigned short* glowBuffer1,
515 				  unsigned short* glowBuffer2,
516 				  unsigned int cellSizeShift,
517 				  unsigned int scale, unsigned int boxw)
518 {
519 
520 	if (scale < 512)
521 		scale = 512;
522 
523 	int gWidth = width>>cellSizeShift;
524 	int gHeight = height>>cellSizeShift;
525 
526 	int x,y,x2,y2;
527 
528 	unsigned short* ptr = glowBuffer1;
529 	for (y = 0; y < gHeight; y++)
530 		for (x = 0; x < gWidth; x++)
531 			*ptr++ = srcImage[(y<<cellSizeShift)*pitch+(x<<cellSizeShift)];
532 
533 	applyBoxed(glowBuffer1, glowBuffer2, gWidth, gHeight, gWidth, boxw);
534 
535 	//int scale = 65536*5;
536 
537 	for (y = 0; y < gHeight; y++)
538 		for (x = 0; x < gWidth; x++)
539 		{
540 
541 			int offset = y*gWidth+x;
542 			int hOffs = 1;
543 			int vOffs = gWidth;
544 			if (x == gWidth-1)
545 				hOffs = 0;
546 			if (y == gHeight-1)
547 				vOffs = 0;
548 
549 			unsigned int rgb1, rgb2, rgb3, rgb4;
550 
551 			rgb1 = glowBuffer1[offset];
552 			rgb2 = glowBuffer1[offset+hOffs];
553 			rgb3 = glowBuffer1[offset+vOffs+hOffs];
554 			rgb4 = glowBuffer1[offset+vOffs];
555 
556 			int r1 = fpmul((rgb1>>11)<<16,scale), g1 = fpmul((rgb1&0x7E0)<<11,scale), b1 = fpmul((rgb1&31)<<16,scale);
557 			int r2 = fpmul((rgb2>>11)<<16,scale), g2 = fpmul((rgb2&0x7E0)<<11,scale), b2 = fpmul((rgb2&31)<<16,scale);
558 			int r3 = fpmul((rgb3>>11)<<16,scale), g3 = fpmul((rgb3&0x7E0)<<11,scale), b3 = fpmul((rgb3&31)<<16,scale);
559 			int r4 = fpmul((rgb4>>11)<<16,scale), g4 = fpmul((rgb4&0x7E0)<<11,scale), b4 = fpmul((rgb4&31)<<16,scale);
560 
561 			int dr1 = (r4-r1)>>cellSizeShift;
562 			int dr2 = (r3-r2)>>cellSizeShift;
563 
564 			int dg1 = (g4-g1)>>cellSizeShift;
565 			int dg2 = (g3-g2)>>cellSizeShift;
566 
567 			int db1 = (b4-b1)>>cellSizeShift;
568 			int db2 = (b3-b2)>>cellSizeShift;
569 
570 			ptr = srcImage+(y<<cellSizeShift)*pitch+(x<<cellSizeShift);
571 
572 			for (y2=0;y2<(1<<cellSizeShift);y2++)
573 			{
574 				int fr = (r2-r1)>>cellSizeShift;
575 				int sr = r1;
576 
577 				int fg = (g2-g1)>>cellSizeShift;
578 				int sg = g1;
579 
580 				int fb = (b2-b1)>>cellSizeShift;
581 				int sb = b1;
582 
583 				for (x2=0;x2<(1<<cellSizeShift);x2++)
584 				{
585 					int r = (sr>>16) + ((*ptr>>11)&31); if (r>31) r = 31;
586 					int g = (sg>>16) + ((*ptr>>5)&63); if (g>63) g = 63;
587 					int b = (sb>>16) + ((*ptr>>0)&31); if (b>31) b = 31;
588 
589 					*ptr++ = PRGB2Short(r,g,b);
590 					sr+=fr;
591 					sg+=fg;
592 					sb+=fb;
593 				}
594 
595 				ptr+=(pitch-(1<<cellSizeShift));
596 
597 				r1+=dr1;
598 				r2+=dr2;
599 
600 				g1+=dg1;
601 				g2+=dg2;
602 
603 				b1+=db1;
604 				b2+=db2;
605 			}
606 
607 		}
608 
609 }
610