rename expr.cpp.h to expr.c.h
[rofl0r-VisualBoyAdvance.git] / src / bilinear.c
blobbf09ae57a67ef46ef6547caac86c2db0bdfa305c
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)
8 // any later version.
9 //
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
23 **/
25 #include "System.h"
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) {
42 u16 color = *from++;
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
48 // preceding pixel
49 u8 *p = row-3;
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)
54 *row++ = *p++;
55 *row++ = *p++;
56 *row++ = *p++;
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) {
65 u32 color = *from++;
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
71 // preceding pixel
72 u8 *p = row-3;
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)
77 *row++ = *p++;
78 *row++ = *p++;
79 *row++ = *p++;
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;
95 u16 *to_orig = to;
97 if (y+1 < height)
98 fill_rgb_row_16(from+width+2, from_width, rgb_row_next,
99 width+1);
100 else
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;
110 u8 *ar = cur_row++;
111 u8 *ag = cur_row++;
112 u8 *ab = cur_row++;
113 u8 *cr = next_row++;
114 u8 *cg = next_row++;
115 u8 *cb = next_row++;
116 for(int x=0; x < width; x++) {
117 u8 *br = cur_row++;
118 u8 *bg = cur_row++;
119 u8 *bb = cur_row++;
120 u8 *dr = next_row++;
121 u8 *dg = next_row++;
122 u8 *db = next_row++;
124 // upper left pixel in quad: just copy it in
125 *to++ = RGB(*ar, *ag, *ab);
127 // upper right
128 *to++ = RGB((*ar+*br)>>1, (*ag+*bg)>>1, (*ab+*bb)>>1);
130 // lower left
131 *to_odd++ = RGB((*ar+*cr)>>1, (*ag+*cg)>>1, (*ab+*cb)>>1);
133 // lower right
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'
139 ar = br;
140 ag = bg;
141 ab = bb;
142 cr = dr;
143 cg = dg;
144 cb = db;
147 // the "next" rgb row becomes the current; the old current rgb row is
148 // recycled and serves as the new "next" row
149 u8 *temp;
150 temp = rgb_row_cur;
151 rgb_row_cur = rgb_row_next;
152 rgb_row_next = temp;
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;
173 u16 *to_orig = to;
175 if (y+1 < height)
176 fill_rgb_row_16(from+width+2, from_width, rgb_row_next,
177 width+1);
178 else
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;
188 u8 *ar = cur_row++;
189 u8 *ag = cur_row++;
190 u8 *ab = cur_row++;
191 u8 *cr = next_row++;
192 u8 *cg = next_row++;
193 u8 *cb = next_row++;
194 for(int x=0; x < width; x++) {
195 u8 *br = cur_row++;
196 u8 *bg = cur_row++;
197 u8 *bb = cur_row++;
198 u8 *dr = next_row++;
199 u8 *dg = next_row++;
200 u8 *db = next_row++;
202 // upper left pixel in quad: just copy it in
203 //*to++ = manip.rgb(*ar, *ag, *ab);
204 #ifdef USE_ORIGINAL_BILINEAR_PLUS
205 *to++ = RGB(
206 (((*ar)<<2) +((*ar)) + (*cr+*br+*br) )>> 3,
207 (((*ag)<<2) +((*ag)) + (*cg+*bg+*bg) )>> 3,
208 (((*ab)<<2) +((*ab)) + (*cb+*bb+*bb) )>> 3);
209 #else
210 *to++ = RGB(
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);
214 #endif
216 // upper right
217 *to++ = RGB((*ar+*br)>>1, (*ag+*bg)>>1, (*ab+*bb)>>1);
219 // lower left
220 *to_odd++ = RGB((*ar+*cr)>>1, (*ag+*cg)>>1, (*ab+*cb)>>1);
222 // lower right
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'
228 ar = br;
229 ag = bg;
230 ab = bb;
231 cr = dr;
232 cg = dg;
233 cb = db;
236 // the "next" rgb row becomes the current; the old current rgb row is
237 // recycled and serves as the new "next" row
238 u8 *temp;
239 temp = rgb_row_cur;
240 rgb_row_cur = rgb_row_next;
241 rgb_row_next = temp;
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;
264 u32 *to_orig = to;
266 if (y+1 < height)
267 fill_rgb_row_32(from+width+1, from_width, rgb_row_next,
268 width+1);
269 else
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;
279 u8 *ar = cur_row++;
280 u8 *ag = cur_row++;
281 u8 *ab = cur_row++;
282 u8 *cr = next_row++;
283 u8 *cg = next_row++;
284 u8 *cb = next_row++;
285 for(int x=0; x < width; x++) {
286 u8 *br = cur_row++;
287 u8 *bg = cur_row++;
288 u8 *bb = cur_row++;
289 u8 *dr = next_row++;
290 u8 *dg = next_row++;
291 u8 *db = next_row++;
293 // upper left pixel in quad: just copy it in
294 *to++ = RGB(*ar, *ag, *ab);
296 // upper right
297 *to++ = RGB((*ar+*br)>>1, (*ag+*bg)>>1, (*ab+*bb)>>1);
299 // lower left
300 *to_odd++ = RGB((*ar+*cr)>>1, (*ag+*cg)>>1, (*ab+*cb)>>1);
302 // lower right
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'
308 ar = br;
309 ag = bg;
310 ab = bb;
311 cr = dr;
312 cg = dg;
313 cb = db;
316 // the "next" rgb row becomes the current; the old current rgb row is
317 // recycled and serves as the new "next" row
318 u8 *temp;
319 temp = rgb_row_cur;
320 rgb_row_cur = rgb_row_next;
321 rgb_row_next = temp;
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;
344 u32 *to_orig = to;
346 if (y+1 < height)
347 fill_rgb_row_32(from+width+1, from_width, rgb_row_next,
348 width+1);
349 else
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;
359 u8 *ar = cur_row++;
360 u8 *ag = cur_row++;
361 u8 *ab = cur_row++;
362 u8 *cr = next_row++;
363 u8 *cg = next_row++;
364 u8 *cb = next_row++;
365 for(int x=0; x < width; x++) {
366 u8 *br = cur_row++;
367 u8 *bg = cur_row++;
368 u8 *bb = cur_row++;
369 u8 *dr = next_row++;
370 u8 *dg = next_row++;
371 u8 *db = next_row++;
373 // upper left pixel in quad: just copy it in
374 //*to++ = manip.rgb(*ar, *ag, *ab);
375 #ifdef USE_ORIGINAL_BILINEAR_PLUS
376 *to++ = RGB(
377 (((*ar)<<2) +((*ar)) + (*cr+*br+*br) )>> 3,
378 (((*ag)<<2) +((*ag)) + (*cg+*bg+*bg) )>> 3,
379 (((*ab)<<2) +((*ab)) + (*cb+*bb+*bb) )>> 3);
380 #else
381 *to++ = RGB(
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);
385 #endif
387 // upper right
388 *to++ = RGB((*ar+*br)>>1, (*ag+*bg)>>1, (*ab+*bb)>>1);
390 // lower left
391 *to_odd++ = RGB((*ar+*cr)>>1, (*ag+*cg)>>1, (*ab+*cb)>>1);
393 // lower right
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'
399 ar = br;
400 ag = bg;
401 ab = bb;
402 cr = dr;
403 cg = dg;
404 cb = db;
407 // the "next" rgb row becomes the current; the old current rgb row is
408 // recycled and serves as the new "next" row
409 u8 *temp;
410 temp = rgb_row_cur;
411 rgb_row_cur = rgb_row_next;
412 rgb_row_next = temp;
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);