view src/filters/bilinear.cpp @ 615:bd664a9bd863

get license and readme.
author Robert McIntyre <rlm@mit.edu>
date Tue, 26 Feb 2013 11:28:45 +0000
parents f9f4f1b99eed
children
line wrap: on
line source
1 /** Code adapted from Exult source code by Forgotten
2 ** Scale.cc - Trying to scale with bilinear interpolation.
3 **
4 ** Written: 6/14/00 - JSF
5 **/
7 #include "../common/System.h"
9 static u8 row_cur[3 * 322];
10 static u8 row_next[3 * 322];
12 static u8 *rgb_row_cur = row_cur;
13 static u8 *rgb_row_next = row_next;
15 #ifdef RGB
16 #undef RGB // wingdi.h has it
17 #endif
18 #define RGB(r, g, b) \
19 ((r) >> 3) << systemRedShift | \
20 ((g) >> 3) << systemGreenShift | \
21 ((b) >> 3) << systemBlueShift \
23 static void fill_rgb_row_16(u16 *from, int src_width, u8 *row, int width)
24 {
25 u8 *copy_start = row + src_width * 3;
26 u8 *all_stop = row + width * 3;
27 while (row < copy_start)
28 {
29 u16 color = *from++;
30 *row++ = ((color >> systemRedShift) & 0x1f) << 3;
31 *row++ = ((color >> systemGreenShift) & 0x1f) << 3;
32 *row++ = ((color >> systemBlueShift) & 0x1f) << 3;
33 }
34 // any remaining elements to be written to 'row' are a replica of the
35 // preceding pixel
36 u8 *p = row - 3;
37 while (row < all_stop)
38 {
39 // we're guaranteed three elements per pixel; could unroll the loop
40 // further, especially with a Duff's Device, but the gains would be
41 // probably limited (judging by profiler output)
42 *row++ = *p++;
43 *row++ = *p++;
44 *row++ = *p++;
45 }
46 }
48 static void fill_rgb_row_32(u32 *from, int src_width, u8 *row, int width)
49 {
50 u8 *copy_start = row + src_width * 3;
51 u8 *all_stop = row + width * 3;
52 while (row < copy_start)
53 {
54 u32 color = *from++;
55 *row++ = ((color >> systemRedShift) & 0x1f) << 3;
56 *row++ = ((color >> systemGreenShift) & 0x1f) << 3;
57 *row++ = ((color >> systemBlueShift) & 0x1f) << 3;
58 }
59 // any remaining elements to be written to 'row' are a replica of the
60 // preceding pixel
61 u8 *p = row - 3;
62 while (row < all_stop)
63 {
64 // we're guaranteed three elements per pixel; could unroll the loop
65 // further, especially with a Duff's Device, but the gains would be
66 // probably limited (judging by profiler output)
67 *row++ = *p++;
68 *row++ = *p++;
69 *row++ = *p++;
70 }
71 }
73 void Bilinear(u8 *srcPtr, u32 srcPitch, u8 * /* deltaPtr */,
74 u8 *dstPtr, u32 dstPitch, int width, int height)
75 {
76 u16 *to = (u16 *)dstPtr;
77 u16 *to_odd = (u16 *)(dstPtr + dstPitch);
79 int from_width = width;
80 u16 *from = (u16 *)srcPtr;
81 fill_rgb_row_16(from, from_width, rgb_row_cur, width + 1);
83 for (int y = 0; y < height; y++)
84 {
85 u16 *from_orig = from;
86 u16 *to_orig = to;
88 if (y + 1 < height)
89 fill_rgb_row_16(from + width + 2, from_width, rgb_row_next,
90 width + 1);
91 else
92 fill_rgb_row_16(from, from_width, rgb_row_next, width + 1);
94 // every pixel in the src region, is extended to 4 pixels in the
95 // destination, arranged in a square 'quad'; if the current src
96 // pixel is 'a', then in what follows 'b' is the src pixel to the
97 // right, 'c' is the src pixel below, and 'd' is the src pixel to
98 // the right and down
99 u8 *cur_row = rgb_row_cur;
100 u8 *next_row = rgb_row_next;
101 u8 *ar = cur_row++;
102 u8 *ag = cur_row++;
103 u8 *ab = cur_row++;
104 u8 *cr = next_row++;
105 u8 *cg = next_row++;
106 u8 *cb = next_row++;
107 for (int x = 0; x < width; x++)
108 {
109 u8 *br = cur_row++;
110 u8 *bg = cur_row++;
111 u8 *bb = cur_row++;
112 u8 *dr = next_row++;
113 u8 *dg = next_row++;
114 u8 *db = next_row++;
116 // upper left pixel in quad: just copy it in
117 *to++ = RGB(*ar, *ag, *ab);
119 // upper right
120 *to++ = RGB((*ar + *br) >> 1, (*ag + *bg) >> 1, (*ab + *bb) >> 1);
122 // lower left
123 *to_odd++ = RGB((*ar + *cr) >> 1, (*ag + *cg) >> 1, (*ab + *cb) >> 1);
125 // lower right
126 *to_odd++ = RGB((*ar + *br + *cr + *dr) >> 2,
127 (*ag + *bg + *cg + *dg) >> 2,
128 (*ab + *bb + *cb + *db) >> 2);
130 // 'b' becomes 'a', 'd' becomes 'c'
131 ar = br;
132 ag = bg;
133 ab = bb;
134 cr = dr;
135 cg = dg;
136 cb = db;
137 }
139 // the "next" rgb row becomes the current; the old current rgb row is
140 // recycled and serves as the new "next" row
141 u8 *temp;
142 temp = rgb_row_cur;
143 rgb_row_cur = rgb_row_next;
144 rgb_row_next = temp;
146 // update the pointers for start of next pair of lines
147 from = (u16 *)((u8 *)from_orig + srcPitch);
148 to = (u16 *)((u8 *)to_orig + (dstPitch << 1));
149 to_odd = (u16 *)((u8 *)to + dstPitch);
150 }
151 }
153 void BilinearPlus(u8 *srcPtr, u32 srcPitch, u8 * /* deltaPtr */,
154 u8 *dstPtr, u32 dstPitch, int width, int height)
155 {
156 u16 *to = (u16 *)dstPtr;
157 u16 *to_odd = (u16 *)(dstPtr + dstPitch);
159 int from_width = width;
160 u16 *from = (u16 *)srcPtr;
161 fill_rgb_row_16(from, from_width, rgb_row_cur, width + 1);
163 for (int y = 0; y < height; y++)
164 {
165 u16 *from_orig = from;
166 u16 *to_orig = to;
168 if (y + 1 < height)
169 fill_rgb_row_16(from + width + 2, from_width, rgb_row_next,
170 width + 1);
171 else
172 fill_rgb_row_16(from, from_width, rgb_row_next, width + 1);
174 // every pixel in the src region, is extended to 4 pixels in the
175 // destination, arranged in a square 'quad'; if the current src
176 // pixel is 'a', then in what follows 'b' is the src pixel to the
177 // right, 'c' is the src pixel below, and 'd' is the src pixel to
178 // the right and down
179 u8 *cur_row = rgb_row_cur;
180 u8 *next_row = rgb_row_next;
181 u8 *ar = cur_row++;
182 u8 *ag = cur_row++;
183 u8 *ab = cur_row++;
184 u8 *cr = next_row++;
185 u8 *cg = next_row++;
186 u8 *cb = next_row++;
187 for (int x = 0; x < width; x++)
188 {
189 u8 *br = cur_row++;
190 u8 *bg = cur_row++;
191 u8 *bb = cur_row++;
192 u8 *dr = next_row++;
193 u8 *dg = next_row++;
194 u8 *db = next_row++;
196 // upper left pixel in quad: just copy it in
197 //*to++ = manip.rgb(*ar, *ag, *ab);
198 #ifdef USE_ORIGINAL_BILINEAR_PLUS
199 *to++ = RGB(
200 (((*ar) << 2) + ((*ar)) + (*cr + *br + *br)) >> 3,
201 (((*ag) << 2) + ((*ag)) + (*cg + *bg + *bg)) >> 3,
202 (((*ab) << 2) + ((*ab)) + (*cb + *bb + *bb)) >> 3);
203 #else
204 *to++ = RGB(
205 (((*ar) << 3) + ((*ar) << 1) + (*cr + *br + *br + *cr)) >> 4,
206 (((*ag) << 3) + ((*ag) << 1) + (*cg + *bg + *bg + *cg)) >> 4,
207 (((*ab) << 3) + ((*ab) << 1) + (*cb + *bb + *bb + *cb)) >> 4);
208 #endif
210 // upper right
211 *to++ = RGB((*ar + *br) >> 1, (*ag + *bg) >> 1, (*ab + *bb) >> 1);
213 // lower left
214 *to_odd++ = RGB((*ar + *cr) >> 1, (*ag + *cg) >> 1, (*ab + *cb) >> 1);
216 // lower right
217 *to_odd++ = RGB((*ar + *br + *cr + *dr) >> 2,
218 (*ag + *bg + *cg + *dg) >> 2,
219 (*ab + *bb + *cb + *db) >> 2);
221 // 'b' becomes 'a', 'd' becomes 'c'
222 ar = br;
223 ag = bg;
224 ab = bb;
225 cr = dr;
226 cg = dg;
227 cb = db;
228 }
230 // the "next" rgb row becomes the current; the old current rgb row is
231 // recycled and serves as the new "next" row
232 u8 *temp;
233 temp = rgb_row_cur;
234 rgb_row_cur = rgb_row_next;
235 rgb_row_next = temp;
237 // update the pointers for start of next pair of lines
238 from = (u16 *)((u8 *)from_orig + srcPitch);
239 to = (u16 *)((u8 *)to_orig + (dstPitch << 1));
240 to_odd = (u16 *)((u8 *)to + dstPitch);
241 }
242 }
244 void Bilinear32(u8 *srcPtr, u32 srcPitch, u8 * /* deltaPtr */,
245 u8 *dstPtr, u32 dstPitch, int width, int height)
246 {
247 u32 *to = (u32 *)dstPtr;
248 u32 *to_odd = (u32 *)(dstPtr + dstPitch);
250 int from_width = width;
251 if (width + 1 < from_width)
252 from_width = width + 1;
253 u32 *from = (u32 *)srcPtr;
254 fill_rgb_row_32(from, from_width, rgb_row_cur, width + 1);
256 for (int y = 0; y < height; y++)
257 {
258 u32 *from_orig = from;
259 u32 *to_orig = to;
261 if (y + 1 < height)
262 fill_rgb_row_32(from + width + 1, from_width, rgb_row_next,
263 width + 1);
264 else
265 fill_rgb_row_32(from, from_width, rgb_row_next, width + 1);
267 // every pixel in the src region, is extended to 4 pixels in the
268 // destination, arranged in a square 'quad'; if the current src
269 // pixel is 'a', then in what follows 'b' is the src pixel to the
270 // right, 'c' is the src pixel below, and 'd' is the src pixel to
271 // the right and down
272 u8 *cur_row = rgb_row_cur;
273 u8 *next_row = rgb_row_next;
274 u8 *ar = cur_row++;
275 u8 *ag = cur_row++;
276 u8 *ab = cur_row++;
277 u8 *cr = next_row++;
278 u8 *cg = next_row++;
279 u8 *cb = next_row++;
280 for (int x = 0; x < width; x++)
281 {
282 u8 *br = cur_row++;
283 u8 *bg = cur_row++;
284 u8 *bb = cur_row++;
285 u8 *dr = next_row++;
286 u8 *dg = next_row++;
287 u8 *db = next_row++;
289 // upper left pixel in quad: just copy it in
290 *to++ = RGB(*ar, *ag, *ab);
292 // upper right
293 *to++ = RGB((*ar + *br) >> 1, (*ag + *bg) >> 1, (*ab + *bb) >> 1);
295 // lower left
296 *to_odd++ = RGB((*ar + *cr) >> 1, (*ag + *cg) >> 1, (*ab + *cb) >> 1);
298 // lower right
299 *to_odd++ = RGB((*ar + *br + *cr + *dr) >> 2,
300 (*ag + *bg + *cg + *dg) >> 2,
301 (*ab + *bb + *cb + *db) >> 2);
303 // 'b' becomes 'a', 'd' becomes 'c'
304 ar = br;
305 ag = bg;
306 ab = bb;
307 cr = dr;
308 cg = dg;
309 cb = db;
310 }
312 // the "next" rgb row becomes the current; the old current rgb row is
313 // recycled and serves as the new "next" row
314 u8 *temp;
315 temp = rgb_row_cur;
316 rgb_row_cur = rgb_row_next;
317 rgb_row_next = temp;
319 // update the pointers for start of next pair of lines
320 from = (u32 *)((u8 *)from_orig + srcPitch);
321 to = (u32 *)((u8 *)to_orig + (dstPitch << 1));
322 to_odd = (u32 *)((u8 *)to + dstPitch);
323 }
324 }
326 void BilinearPlus32(u8 *srcPtr, u32 srcPitch, u8 * /* deltaPtr */,
327 u8 *dstPtr, u32 dstPitch, int width, int height)
328 {
329 u32 *to = (u32 *)dstPtr;
330 u32 *to_odd = (u32 *)(dstPtr + dstPitch);
332 int from_width = width;
333 if (width + 1 < from_width)
334 from_width = width + 1;
335 u32 *from = (u32 *)srcPtr;
336 fill_rgb_row_32(from, from_width, rgb_row_cur, width + 1);
338 for (int y = 0; y < height; y++)
339 {
340 u32 *from_orig = from;
341 u32 *to_orig = to;
343 if (y + 1 < height)
344 fill_rgb_row_32(from + width + 1, from_width, rgb_row_next,
345 width + 1);
346 else
347 fill_rgb_row_32(from, from_width, rgb_row_next, width + 1);
349 // every pixel in the src region, is extended to 4 pixels in the
350 // destination, arranged in a square 'quad'; if the current src
351 // pixel is 'a', then in what follows 'b' is the src pixel to the
352 // right, 'c' is the src pixel below, and 'd' is the src pixel to
353 // the right and down
354 u8 *cur_row = rgb_row_cur;
355 u8 *next_row = rgb_row_next;
356 u8 *ar = cur_row++;
357 u8 *ag = cur_row++;
358 u8 *ab = cur_row++;
359 u8 *cr = next_row++;
360 u8 *cg = next_row++;
361 u8 *cb = next_row++;
362 for (int x = 0; x < width; x++)
363 {
364 u8 *br = cur_row++;
365 u8 *bg = cur_row++;
366 u8 *bb = cur_row++;
367 u8 *dr = next_row++;
368 u8 *dg = next_row++;
369 u8 *db = next_row++;
371 // upper left pixel in quad: just copy it in
372 //*to++ = manip.rgb(*ar, *ag, *ab);
373 #ifdef USE_ORIGINAL_BILINEAR_PLUS
374 *to++ = RGB(
375 (((*ar) << 2) + ((*ar)) + (*cr + *br + *br)) >> 3,
376 (((*ag) << 2) + ((*ag)) + (*cg + *bg + *bg)) >> 3,
377 (((*ab) << 2) + ((*ab)) + (*cb + *bb + *bb)) >> 3);
378 #else
379 *to++ = RGB(
380 (((*ar) << 3) + ((*ar) << 1) + (*cr + *br + *br + *cr)) >> 4,
381 (((*ag) << 3) + ((*ag) << 1) + (*cg + *bg + *bg + *cg)) >> 4,
382 (((*ab) << 3) + ((*ab) << 1) + (*cb + *bb + *bb + *cb)) >> 4);
383 #endif
385 // upper right
386 *to++ = RGB((*ar + *br) >> 1, (*ag + *bg) >> 1, (*ab + *bb) >> 1);
388 // lower left
389 *to_odd++ = RGB((*ar + *cr) >> 1, (*ag + *cg) >> 1, (*ab + *cb) >> 1);
391 // lower right
392 *to_odd++ = RGB((*ar + *br + *cr + *dr) >> 2,
393 (*ag + *bg + *cg + *dg) >> 2,
394 (*ab + *bb + *cb + *db) >> 2);
396 // 'b' becomes 'a', 'd' becomes 'c'
397 ar = br;
398 ag = bg;
399 ab = bb;
400 cr = dr;
401 cg = dg;
402 cb = db;
403 }
405 // the "next" rgb row becomes the current; the old current rgb row is
406 // recycled and serves as the new "next" row
407 u8 *temp;
408 temp = rgb_row_cur;
409 rgb_row_cur = rgb_row_next;
410 rgb_row_next = temp;
412 // update the pointers for start of next pair of lines
413 from = (u32 *)((u8 *)from_orig + srcPitch);
414 to = (u32 *)((u8 *)to_orig + (dstPitch << 1));
415 to_odd = (u32 *)((u8 *)to + dstPitch);
416 }
417 }