annotate src/filters/bilinear.cpp @ 354:4141489d1406

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