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