1 // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
2 // Copyright (C) 1999-2003 Forgotten
3 // Copyright (C) 2004 Forgotten and the VBA development team
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2, or(at your option)
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 /** Code adapted from Exult source code by Forgotten
20 ** Scale.cc - Trying to scale with bilinear interpolation.
22 ** Written: 6/14/00 - JSF
27 static u8 row_cur
[3*322];
28 static u8 row_next
[3*322];
30 static u8
*rgb_row_cur
= row_cur
;
31 static u8
*rgb_row_next
= row_next
;
33 #define RGB(r,g,b) ((r)>>3) << systemRedShift |\
34 ((g) >> 3) << systemGreenShift |\
35 ((b) >> 3) << systemBlueShift\
37 static void fill_rgb_row_16(u16 *from, int src_width, u8 *row, int width)
39 u8
*copy_start
= row
+ src_width
*3;
40 u8
*all_stop
= row
+ width
*3;
41 while (row
< copy_start
) {
43 *row
++ = ((color
>> systemRedShift
) & 0x1f) << 3;
44 *row
++ = ((color
>> systemGreenShift
) & 0x1f) << 3;
45 *row
++ = ((color
>> systemBlueShift
) & 0x1f) << 3;
47 // any remaining elements to be written to 'row' are a replica of the
50 while (row
< all_stop
) {
51 // we're guaranteed three elements per pixel; could unroll the loop
52 // further, especially with a Duff's Device, but the gains would be
53 // probably limited (judging by profiler output)
60 static void fill_rgb_row_32(u32
*from
, int src_width
, u8
*row
, int width
)
62 u8
*copy_start
= row
+ src_width
*3;
63 u8
*all_stop
= row
+ width
*3;
64 while (row
< copy_start
) {
66 *row
++ = ((color
>> systemRedShift
) & 0x1f) << 3;
67 *row
++ = ((color
>> systemGreenShift
) & 0x1f) << 3;
68 *row
++ = ((color
>> systemBlueShift
) & 0x1f) << 3;
70 // any remaining elements to be written to 'row' are a replica of the
73 while (row
< all_stop
) {
74 // we're guaranteed three elements per pixel; could unroll the loop
75 // further, especially with a Duff's Device, but the gains would be
76 // probably limited (judging by profiler output)
83 void Bilinear(u8
*srcPtr
, u32 srcPitch
, u8
* /* deltaPtr */,
84 u8
*dstPtr
, u32 dstPitch
, int width
, int height
)
86 u16
*to
= (u16
*)dstPtr
;
87 u16
*to_odd
= (u16
*)(dstPtr
+ dstPitch
);
89 int from_width
= width
;
90 u16
*from
= (u16
*)srcPtr
;
91 fill_rgb_row_16(from
, from_width
, rgb_row_cur
, width
+1);
93 for(int y
= 0; y
< height
; y
++) {
94 u16
*from_orig
= from
;
98 fill_rgb_row_16(from
+width
+2, from_width
, rgb_row_next
,
101 fill_rgb_row_16(from
, from_width
, rgb_row_next
, width
+1);
103 // every pixel in the src region, is extended to 4 pixels in the
104 // destination, arranged in a square 'quad'; if the current src
105 // pixel is 'a', then in what follows 'b' is the src pixel to the
106 // right, 'c' is the src pixel below, and 'd' is the src pixel to
107 // the right and down
108 u8
*cur_row
= rgb_row_cur
;
109 u8
*next_row
= rgb_row_next
;
116 for(int x
=0; x
< width
; x
++) {
124 // upper left pixel in quad: just copy it in
125 *to
++ = RGB(*ar
, *ag
, *ab
);
128 *to
++ = RGB((*ar
+*br
)>>1, (*ag
+*bg
)>>1, (*ab
+*bb
)>>1);
131 *to_odd
++ = RGB((*ar
+*cr
)>>1, (*ag
+*cg
)>>1, (*ab
+*cb
)>>1);
134 *to_odd
++ = RGB((*ar
+*br
+*cr
+*dr
)>>2,
135 (*ag
+*bg
+*cg
+*dg
)>>2,
136 (*ab
+*bb
+*cb
+*db
)>>2);
138 // 'b' becomes 'a', 'd' becomes 'c'
147 // the "next" rgb row becomes the current; the old current rgb row is
148 // recycled and serves as the new "next" row
151 rgb_row_cur
= rgb_row_next
;
154 // update the pointers for start of next pair of lines
155 from
= (u16
*)((u8
*)from_orig
+ srcPitch
);
156 to
= (u16
*)((u8
*)to_orig
+ (dstPitch
<< 1));
157 to_odd
= (u16
*)((u8
*)to
+ dstPitch
);
161 void BilinearPlus(u8
*srcPtr
, u32 srcPitch
, u8
* /* deltaPtr */,
162 u8
*dstPtr
, u32 dstPitch
, int width
, int height
)
164 u16
*to
= (u16
*)dstPtr
;
165 u16
*to_odd
= (u16
*)(dstPtr
+ dstPitch
);
167 int from_width
= width
;
168 u16
*from
= (u16
*)srcPtr
;
169 fill_rgb_row_16(from
, from_width
, rgb_row_cur
, width
+1);
171 for(int y
= 0; y
< height
; y
++) {
172 u16
*from_orig
= from
;
176 fill_rgb_row_16(from
+width
+2, from_width
, rgb_row_next
,
179 fill_rgb_row_16(from
, from_width
, rgb_row_next
, width
+1);
181 // every pixel in the src region, is extended to 4 pixels in the
182 // destination, arranged in a square 'quad'; if the current src
183 // pixel is 'a', then in what follows 'b' is the src pixel to the
184 // right, 'c' is the src pixel below, and 'd' is the src pixel to
185 // the right and down
186 u8
*cur_row
= rgb_row_cur
;
187 u8
*next_row
= rgb_row_next
;
194 for(int x
=0; x
< width
; x
++) {
202 // upper left pixel in quad: just copy it in
203 //*to++ = manip.rgb(*ar, *ag, *ab);
204 #ifdef USE_ORIGINAL_BILINEAR_PLUS
206 (((*ar
)<<2) +((*ar
)) + (*cr
+*br
+*br
) )>> 3,
207 (((*ag
)<<2) +((*ag
)) + (*cg
+*bg
+*bg
) )>> 3,
208 (((*ab
)<<2) +((*ab
)) + (*cb
+*bb
+*bb
) )>> 3);
211 (((*ar
)<<3) +((*ar
)<<1) + (*cr
+*br
+*br
+*cr
) )>> 4,
212 (((*ag
)<<3) +((*ag
)<<1) + (*cg
+*bg
+*bg
+*cg
) )>> 4,
213 (((*ab
)<<3) +((*ab
)<<1) + (*cb
+*bb
+*bb
+*cb
) )>> 4);
217 *to
++ = RGB((*ar
+*br
)>>1, (*ag
+*bg
)>>1, (*ab
+*bb
)>>1);
220 *to_odd
++ = RGB((*ar
+*cr
)>>1, (*ag
+*cg
)>>1, (*ab
+*cb
)>>1);
223 *to_odd
++ = RGB((*ar
+*br
+*cr
+*dr
)>>2,
224 (*ag
+*bg
+*cg
+*dg
)>>2,
225 (*ab
+*bb
+*cb
+*db
)>>2);
227 // 'b' becomes 'a', 'd' becomes 'c'
236 // the "next" rgb row becomes the current; the old current rgb row is
237 // recycled and serves as the new "next" row
240 rgb_row_cur
= rgb_row_next
;
243 // update the pointers for start of next pair of lines
244 from
= (u16
*)((u8
*)from_orig
+ srcPitch
);
245 to
= (u16
*)((u8
*)to_orig
+ (dstPitch
<< 1));
246 to_odd
= (u16
*)((u8
*)to
+ dstPitch
);
250 void Bilinear32(u8
*srcPtr
, u32 srcPitch
, u8
* /* deltaPtr */,
251 u8
*dstPtr
, u32 dstPitch
, int width
, int height
)
253 u32
*to
= (u32
*)dstPtr
;
254 u32
*to_odd
= (u32
*)(dstPtr
+ dstPitch
);
256 int from_width
= width
;
257 if(width
+1 < from_width
)
258 from_width
= width
+1;
259 u32
*from
= (u32
*)srcPtr
;
260 fill_rgb_row_32(from
, from_width
, rgb_row_cur
, width
+1);
262 for(int y
= 0; y
< height
; y
++) {
263 u32
*from_orig
= from
;
267 fill_rgb_row_32(from
+width
+1, from_width
, rgb_row_next
,
270 fill_rgb_row_32(from
, from_width
, rgb_row_next
, width
+1);
272 // every pixel in the src region, is extended to 4 pixels in the
273 // destination, arranged in a square 'quad'; if the current src
274 // pixel is 'a', then in what follows 'b' is the src pixel to the
275 // right, 'c' is the src pixel below, and 'd' is the src pixel to
276 // the right and down
277 u8
*cur_row
= rgb_row_cur
;
278 u8
*next_row
= rgb_row_next
;
285 for(int x
=0; x
< width
; x
++) {
293 // upper left pixel in quad: just copy it in
294 *to
++ = RGB(*ar
, *ag
, *ab
);
297 *to
++ = RGB((*ar
+*br
)>>1, (*ag
+*bg
)>>1, (*ab
+*bb
)>>1);
300 *to_odd
++ = RGB((*ar
+*cr
)>>1, (*ag
+*cg
)>>1, (*ab
+*cb
)>>1);
303 *to_odd
++ = RGB((*ar
+*br
+*cr
+*dr
)>>2,
304 (*ag
+*bg
+*cg
+*dg
)>>2,
305 (*ab
+*bb
+*cb
+*db
)>>2);
307 // 'b' becomes 'a', 'd' becomes 'c'
316 // the "next" rgb row becomes the current; the old current rgb row is
317 // recycled and serves as the new "next" row
320 rgb_row_cur
= rgb_row_next
;
323 // update the pointers for start of next pair of lines
324 from
= (u32
*)((u8
*)from_orig
+ srcPitch
);
325 to
= (u32
*)((u8
*)to_orig
+ (dstPitch
<< 1));
326 to_odd
= (u32
*)((u8
*)to
+ dstPitch
);
330 void BilinearPlus32(u8
*srcPtr
, u32 srcPitch
, u8
* /* deltaPtr */,
331 u8
*dstPtr
, u32 dstPitch
, int width
, int height
)
333 u32
*to
= (u32
*)dstPtr
;
334 u32
*to_odd
= (u32
*)(dstPtr
+ dstPitch
);
336 int from_width
= width
;
337 if(width
+1 < from_width
)
338 from_width
= width
+1;
339 u32
*from
= (u32
*)srcPtr
;
340 fill_rgb_row_32(from
, from_width
, rgb_row_cur
, width
+1);
342 for(int y
= 0; y
< height
; y
++) {
343 u32
*from_orig
= from
;
347 fill_rgb_row_32(from
+width
+1, from_width
, rgb_row_next
,
350 fill_rgb_row_32(from
, from_width
, rgb_row_next
, width
+1);
352 // every pixel in the src region, is extended to 4 pixels in the
353 // destination, arranged in a square 'quad'; if the current src
354 // pixel is 'a', then in what follows 'b' is the src pixel to the
355 // right, 'c' is the src pixel below, and 'd' is the src pixel to
356 // the right and down
357 u8
*cur_row
= rgb_row_cur
;
358 u8
*next_row
= rgb_row_next
;
365 for(int x
=0; x
< width
; x
++) {
373 // upper left pixel in quad: just copy it in
374 //*to++ = manip.rgb(*ar, *ag, *ab);
375 #ifdef USE_ORIGINAL_BILINEAR_PLUS
377 (((*ar
)<<2) +((*ar
)) + (*cr
+*br
+*br
) )>> 3,
378 (((*ag
)<<2) +((*ag
)) + (*cg
+*bg
+*bg
) )>> 3,
379 (((*ab
)<<2) +((*ab
)) + (*cb
+*bb
+*bb
) )>> 3);
382 (((*ar
)<<3) +((*ar
)<<1) + (*cr
+*br
+*br
+*cr
) )>> 4,
383 (((*ag
)<<3) +((*ag
)<<1) + (*cg
+*bg
+*bg
+*cg
) )>> 4,
384 (((*ab
)<<3) +((*ab
)<<1) + (*cb
+*bb
+*bb
+*cb
) )>> 4);
388 *to
++ = RGB((*ar
+*br
)>>1, (*ag
+*bg
)>>1, (*ab
+*bb
)>>1);
391 *to_odd
++ = RGB((*ar
+*cr
)>>1, (*ag
+*cg
)>>1, (*ab
+*cb
)>>1);
394 *to_odd
++ = RGB((*ar
+*br
+*cr
+*dr
)>>2,
395 (*ag
+*bg
+*cg
+*dg
)>>2,
396 (*ab
+*bb
+*cb
+*db
)>>2);
398 // 'b' becomes 'a', 'd' becomes 'c'
407 // the "next" rgb row becomes the current; the old current rgb row is
408 // recycled and serves as the new "next" row
411 rgb_row_cur
= rgb_row_next
;
414 // update the pointers for start of next pair of lines
415 from
= (u32
*)((u8
*)from_orig
+ srcPitch
);
416 to
= (u32
*)((u8
*)to_orig
+ (dstPitch
<< 1));
417 to_odd
= (u32
*)((u8
*)to
+ dstPitch
);