rlm@1: /** Code adapted from Exult source code by Forgotten rlm@1: ** Scale.cc - Trying to scale with bilinear interpolation. rlm@1: ** rlm@1: ** Written: 6/14/00 - JSF rlm@1: **/ rlm@1: rlm@1: #include "../common/System.h" rlm@1: rlm@1: static u8 row_cur[3 * 322]; rlm@1: static u8 row_next[3 * 322]; rlm@1: rlm@1: static u8 *rgb_row_cur = row_cur; rlm@1: static u8 *rgb_row_next = row_next; rlm@1: rlm@1: #ifdef RGB rlm@1: #undef RGB // wingdi.h has it rlm@1: #endif rlm@1: #define RGB(r, g, b) \ rlm@1: ((r) >> 3) << systemRedShift | \ rlm@1: ((g) >> 3) << systemGreenShift | \ rlm@1: ((b) >> 3) << systemBlueShift \ rlm@1: rlm@1: static void fill_rgb_row_16(u16 *from, int src_width, u8 *row, int width) rlm@1: { rlm@1: u8 *copy_start = row + src_width * 3; rlm@1: u8 *all_stop = row + width * 3; rlm@1: while (row < copy_start) rlm@1: { rlm@1: u16 color = *from++; rlm@1: *row++ = ((color >> systemRedShift) & 0x1f) << 3; rlm@1: *row++ = ((color >> systemGreenShift) & 0x1f) << 3; rlm@1: *row++ = ((color >> systemBlueShift) & 0x1f) << 3; rlm@1: } rlm@1: // any remaining elements to be written to 'row' are a replica of the rlm@1: // preceding pixel rlm@1: u8 *p = row - 3; rlm@1: while (row < all_stop) rlm@1: { rlm@1: // we're guaranteed three elements per pixel; could unroll the loop rlm@1: // further, especially with a Duff's Device, but the gains would be rlm@1: // probably limited (judging by profiler output) rlm@1: *row++ = *p++; rlm@1: *row++ = *p++; rlm@1: *row++ = *p++; rlm@1: } rlm@1: } rlm@1: rlm@1: static void fill_rgb_row_32(u32 *from, int src_width, u8 *row, int width) rlm@1: { rlm@1: u8 *copy_start = row + src_width * 3; rlm@1: u8 *all_stop = row + width * 3; rlm@1: while (row < copy_start) rlm@1: { rlm@1: u32 color = *from++; rlm@1: *row++ = ((color >> systemRedShift) & 0x1f) << 3; rlm@1: *row++ = ((color >> systemGreenShift) & 0x1f) << 3; rlm@1: *row++ = ((color >> systemBlueShift) & 0x1f) << 3; rlm@1: } rlm@1: // any remaining elements to be written to 'row' are a replica of the rlm@1: // preceding pixel rlm@1: u8 *p = row - 3; rlm@1: while (row < all_stop) rlm@1: { rlm@1: // we're guaranteed three elements per pixel; could unroll the loop rlm@1: // further, especially with a Duff's Device, but the gains would be rlm@1: // probably limited (judging by profiler output) rlm@1: *row++ = *p++; rlm@1: *row++ = *p++; rlm@1: *row++ = *p++; rlm@1: } rlm@1: } rlm@1: rlm@1: void Bilinear(u8 *srcPtr, u32 srcPitch, u8 * /* deltaPtr */, rlm@1: u8 *dstPtr, u32 dstPitch, int width, int height) rlm@1: { rlm@1: u16 *to = (u16 *)dstPtr; rlm@1: u16 *to_odd = (u16 *)(dstPtr + dstPitch); rlm@1: rlm@1: int from_width = width; rlm@1: u16 *from = (u16 *)srcPtr; rlm@1: fill_rgb_row_16(from, from_width, rgb_row_cur, width + 1); rlm@1: rlm@1: for (int y = 0; y < height; y++) rlm@1: { rlm@1: u16 *from_orig = from; rlm@1: u16 *to_orig = to; rlm@1: rlm@1: if (y + 1 < height) rlm@1: fill_rgb_row_16(from + width + 2, from_width, rgb_row_next, rlm@1: width + 1); rlm@1: else rlm@1: fill_rgb_row_16(from, from_width, rgb_row_next, width + 1); rlm@1: rlm@1: // every pixel in the src region, is extended to 4 pixels in the rlm@1: // destination, arranged in a square 'quad'; if the current src rlm@1: // pixel is 'a', then in what follows 'b' is the src pixel to the rlm@1: // right, 'c' is the src pixel below, and 'd' is the src pixel to rlm@1: // the right and down rlm@1: u8 *cur_row = rgb_row_cur; rlm@1: u8 *next_row = rgb_row_next; rlm@1: u8 *ar = cur_row++; rlm@1: u8 *ag = cur_row++; rlm@1: u8 *ab = cur_row++; rlm@1: u8 *cr = next_row++; rlm@1: u8 *cg = next_row++; rlm@1: u8 *cb = next_row++; rlm@1: for (int x = 0; x < width; x++) rlm@1: { rlm@1: u8 *br = cur_row++; rlm@1: u8 *bg = cur_row++; rlm@1: u8 *bb = cur_row++; rlm@1: u8 *dr = next_row++; rlm@1: u8 *dg = next_row++; rlm@1: u8 *db = next_row++; rlm@1: rlm@1: // upper left pixel in quad: just copy it in rlm@1: *to++ = RGB(*ar, *ag, *ab); rlm@1: rlm@1: // upper right rlm@1: *to++ = RGB((*ar + *br) >> 1, (*ag + *bg) >> 1, (*ab + *bb) >> 1); rlm@1: rlm@1: // lower left rlm@1: *to_odd++ = RGB((*ar + *cr) >> 1, (*ag + *cg) >> 1, (*ab + *cb) >> 1); rlm@1: rlm@1: // lower right rlm@1: *to_odd++ = RGB((*ar + *br + *cr + *dr) >> 2, rlm@1: (*ag + *bg + *cg + *dg) >> 2, rlm@1: (*ab + *bb + *cb + *db) >> 2); rlm@1: rlm@1: // 'b' becomes 'a', 'd' becomes 'c' rlm@1: ar = br; rlm@1: ag = bg; rlm@1: ab = bb; rlm@1: cr = dr; rlm@1: cg = dg; rlm@1: cb = db; rlm@1: } rlm@1: rlm@1: // the "next" rgb row becomes the current; the old current rgb row is rlm@1: // recycled and serves as the new "next" row rlm@1: u8 *temp; rlm@1: temp = rgb_row_cur; rlm@1: rgb_row_cur = rgb_row_next; rlm@1: rgb_row_next = temp; rlm@1: rlm@1: // update the pointers for start of next pair of lines rlm@1: from = (u16 *)((u8 *)from_orig + srcPitch); rlm@1: to = (u16 *)((u8 *)to_orig + (dstPitch << 1)); rlm@1: to_odd = (u16 *)((u8 *)to + dstPitch); rlm@1: } rlm@1: } rlm@1: rlm@1: void BilinearPlus(u8 *srcPtr, u32 srcPitch, u8 * /* deltaPtr */, rlm@1: u8 *dstPtr, u32 dstPitch, int width, int height) rlm@1: { rlm@1: u16 *to = (u16 *)dstPtr; rlm@1: u16 *to_odd = (u16 *)(dstPtr + dstPitch); rlm@1: rlm@1: int from_width = width; rlm@1: u16 *from = (u16 *)srcPtr; rlm@1: fill_rgb_row_16(from, from_width, rgb_row_cur, width + 1); rlm@1: rlm@1: for (int y = 0; y < height; y++) rlm@1: { rlm@1: u16 *from_orig = from; rlm@1: u16 *to_orig = to; rlm@1: rlm@1: if (y + 1 < height) rlm@1: fill_rgb_row_16(from + width + 2, from_width, rgb_row_next, rlm@1: width + 1); rlm@1: else rlm@1: fill_rgb_row_16(from, from_width, rgb_row_next, width + 1); rlm@1: rlm@1: // every pixel in the src region, is extended to 4 pixels in the rlm@1: // destination, arranged in a square 'quad'; if the current src rlm@1: // pixel is 'a', then in what follows 'b' is the src pixel to the rlm@1: // right, 'c' is the src pixel below, and 'd' is the src pixel to rlm@1: // the right and down rlm@1: u8 *cur_row = rgb_row_cur; rlm@1: u8 *next_row = rgb_row_next; rlm@1: u8 *ar = cur_row++; rlm@1: u8 *ag = cur_row++; rlm@1: u8 *ab = cur_row++; rlm@1: u8 *cr = next_row++; rlm@1: u8 *cg = next_row++; rlm@1: u8 *cb = next_row++; rlm@1: for (int x = 0; x < width; x++) rlm@1: { rlm@1: u8 *br = cur_row++; rlm@1: u8 *bg = cur_row++; rlm@1: u8 *bb = cur_row++; rlm@1: u8 *dr = next_row++; rlm@1: u8 *dg = next_row++; rlm@1: u8 *db = next_row++; rlm@1: rlm@1: // upper left pixel in quad: just copy it in rlm@1: //*to++ = manip.rgb(*ar, *ag, *ab); rlm@1: #ifdef USE_ORIGINAL_BILINEAR_PLUS rlm@1: *to++ = RGB( rlm@1: (((*ar) << 2) + ((*ar)) + (*cr + *br + *br)) >> 3, rlm@1: (((*ag) << 2) + ((*ag)) + (*cg + *bg + *bg)) >> 3, rlm@1: (((*ab) << 2) + ((*ab)) + (*cb + *bb + *bb)) >> 3); rlm@1: #else rlm@1: *to++ = RGB( rlm@1: (((*ar) << 3) + ((*ar) << 1) + (*cr + *br + *br + *cr)) >> 4, rlm@1: (((*ag) << 3) + ((*ag) << 1) + (*cg + *bg + *bg + *cg)) >> 4, rlm@1: (((*ab) << 3) + ((*ab) << 1) + (*cb + *bb + *bb + *cb)) >> 4); rlm@1: #endif rlm@1: rlm@1: // upper right rlm@1: *to++ = RGB((*ar + *br) >> 1, (*ag + *bg) >> 1, (*ab + *bb) >> 1); rlm@1: rlm@1: // lower left rlm@1: *to_odd++ = RGB((*ar + *cr) >> 1, (*ag + *cg) >> 1, (*ab + *cb) >> 1); rlm@1: rlm@1: // lower right rlm@1: *to_odd++ = RGB((*ar + *br + *cr + *dr) >> 2, rlm@1: (*ag + *bg + *cg + *dg) >> 2, rlm@1: (*ab + *bb + *cb + *db) >> 2); rlm@1: rlm@1: // 'b' becomes 'a', 'd' becomes 'c' rlm@1: ar = br; rlm@1: ag = bg; rlm@1: ab = bb; rlm@1: cr = dr; rlm@1: cg = dg; rlm@1: cb = db; rlm@1: } rlm@1: rlm@1: // the "next" rgb row becomes the current; the old current rgb row is rlm@1: // recycled and serves as the new "next" row rlm@1: u8 *temp; rlm@1: temp = rgb_row_cur; rlm@1: rgb_row_cur = rgb_row_next; rlm@1: rgb_row_next = temp; rlm@1: rlm@1: // update the pointers for start of next pair of lines rlm@1: from = (u16 *)((u8 *)from_orig + srcPitch); rlm@1: to = (u16 *)((u8 *)to_orig + (dstPitch << 1)); rlm@1: to_odd = (u16 *)((u8 *)to + dstPitch); rlm@1: } rlm@1: } rlm@1: rlm@1: void Bilinear32(u8 *srcPtr, u32 srcPitch, u8 * /* deltaPtr */, rlm@1: u8 *dstPtr, u32 dstPitch, int width, int height) rlm@1: { rlm@1: u32 *to = (u32 *)dstPtr; rlm@1: u32 *to_odd = (u32 *)(dstPtr + dstPitch); rlm@1: rlm@1: int from_width = width; rlm@1: if (width + 1 < from_width) rlm@1: from_width = width + 1; rlm@1: u32 *from = (u32 *)srcPtr; rlm@1: fill_rgb_row_32(from, from_width, rgb_row_cur, width + 1); rlm@1: rlm@1: for (int y = 0; y < height; y++) rlm@1: { rlm@1: u32 *from_orig = from; rlm@1: u32 *to_orig = to; rlm@1: rlm@1: if (y + 1 < height) rlm@1: fill_rgb_row_32(from + width + 1, from_width, rgb_row_next, rlm@1: width + 1); rlm@1: else rlm@1: fill_rgb_row_32(from, from_width, rgb_row_next, width + 1); rlm@1: rlm@1: // every pixel in the src region, is extended to 4 pixels in the rlm@1: // destination, arranged in a square 'quad'; if the current src rlm@1: // pixel is 'a', then in what follows 'b' is the src pixel to the rlm@1: // right, 'c' is the src pixel below, and 'd' is the src pixel to rlm@1: // the right and down rlm@1: u8 *cur_row = rgb_row_cur; rlm@1: u8 *next_row = rgb_row_next; rlm@1: u8 *ar = cur_row++; rlm@1: u8 *ag = cur_row++; rlm@1: u8 *ab = cur_row++; rlm@1: u8 *cr = next_row++; rlm@1: u8 *cg = next_row++; rlm@1: u8 *cb = next_row++; rlm@1: for (int x = 0; x < width; x++) rlm@1: { rlm@1: u8 *br = cur_row++; rlm@1: u8 *bg = cur_row++; rlm@1: u8 *bb = cur_row++; rlm@1: u8 *dr = next_row++; rlm@1: u8 *dg = next_row++; rlm@1: u8 *db = next_row++; rlm@1: rlm@1: // upper left pixel in quad: just copy it in rlm@1: *to++ = RGB(*ar, *ag, *ab); rlm@1: rlm@1: // upper right rlm@1: *to++ = RGB((*ar + *br) >> 1, (*ag + *bg) >> 1, (*ab + *bb) >> 1); rlm@1: rlm@1: // lower left rlm@1: *to_odd++ = RGB((*ar + *cr) >> 1, (*ag + *cg) >> 1, (*ab + *cb) >> 1); rlm@1: rlm@1: // lower right rlm@1: *to_odd++ = RGB((*ar + *br + *cr + *dr) >> 2, rlm@1: (*ag + *bg + *cg + *dg) >> 2, rlm@1: (*ab + *bb + *cb + *db) >> 2); rlm@1: rlm@1: // 'b' becomes 'a', 'd' becomes 'c' rlm@1: ar = br; rlm@1: ag = bg; rlm@1: ab = bb; rlm@1: cr = dr; rlm@1: cg = dg; rlm@1: cb = db; rlm@1: } rlm@1: rlm@1: // the "next" rgb row becomes the current; the old current rgb row is rlm@1: // recycled and serves as the new "next" row rlm@1: u8 *temp; rlm@1: temp = rgb_row_cur; rlm@1: rgb_row_cur = rgb_row_next; rlm@1: rgb_row_next = temp; rlm@1: rlm@1: // update the pointers for start of next pair of lines rlm@1: from = (u32 *)((u8 *)from_orig + srcPitch); rlm@1: to = (u32 *)((u8 *)to_orig + (dstPitch << 1)); rlm@1: to_odd = (u32 *)((u8 *)to + dstPitch); rlm@1: } rlm@1: } rlm@1: rlm@1: void BilinearPlus32(u8 *srcPtr, u32 srcPitch, u8 * /* deltaPtr */, rlm@1: u8 *dstPtr, u32 dstPitch, int width, int height) rlm@1: { rlm@1: u32 *to = (u32 *)dstPtr; rlm@1: u32 *to_odd = (u32 *)(dstPtr + dstPitch); rlm@1: rlm@1: int from_width = width; rlm@1: if (width + 1 < from_width) rlm@1: from_width = width + 1; rlm@1: u32 *from = (u32 *)srcPtr; rlm@1: fill_rgb_row_32(from, from_width, rgb_row_cur, width + 1); rlm@1: rlm@1: for (int y = 0; y < height; y++) rlm@1: { rlm@1: u32 *from_orig = from; rlm@1: u32 *to_orig = to; rlm@1: rlm@1: if (y + 1 < height) rlm@1: fill_rgb_row_32(from + width + 1, from_width, rgb_row_next, rlm@1: width + 1); rlm@1: else rlm@1: fill_rgb_row_32(from, from_width, rgb_row_next, width + 1); rlm@1: rlm@1: // every pixel in the src region, is extended to 4 pixels in the rlm@1: // destination, arranged in a square 'quad'; if the current src rlm@1: // pixel is 'a', then in what follows 'b' is the src pixel to the rlm@1: // right, 'c' is the src pixel below, and 'd' is the src pixel to rlm@1: // the right and down rlm@1: u8 *cur_row = rgb_row_cur; rlm@1: u8 *next_row = rgb_row_next; rlm@1: u8 *ar = cur_row++; rlm@1: u8 *ag = cur_row++; rlm@1: u8 *ab = cur_row++; rlm@1: u8 *cr = next_row++; rlm@1: u8 *cg = next_row++; rlm@1: u8 *cb = next_row++; rlm@1: for (int x = 0; x < width; x++) rlm@1: { rlm@1: u8 *br = cur_row++; rlm@1: u8 *bg = cur_row++; rlm@1: u8 *bb = cur_row++; rlm@1: u8 *dr = next_row++; rlm@1: u8 *dg = next_row++; rlm@1: u8 *db = next_row++; rlm@1: rlm@1: // upper left pixel in quad: just copy it in rlm@1: //*to++ = manip.rgb(*ar, *ag, *ab); rlm@1: #ifdef USE_ORIGINAL_BILINEAR_PLUS rlm@1: *to++ = RGB( rlm@1: (((*ar) << 2) + ((*ar)) + (*cr + *br + *br)) >> 3, rlm@1: (((*ag) << 2) + ((*ag)) + (*cg + *bg + *bg)) >> 3, rlm@1: (((*ab) << 2) + ((*ab)) + (*cb + *bb + *bb)) >> 3); rlm@1: #else rlm@1: *to++ = RGB( rlm@1: (((*ar) << 3) + ((*ar) << 1) + (*cr + *br + *br + *cr)) >> 4, rlm@1: (((*ag) << 3) + ((*ag) << 1) + (*cg + *bg + *bg + *cg)) >> 4, rlm@1: (((*ab) << 3) + ((*ab) << 1) + (*cb + *bb + *bb + *cb)) >> 4); rlm@1: #endif rlm@1: rlm@1: // upper right rlm@1: *to++ = RGB((*ar + *br) >> 1, (*ag + *bg) >> 1, (*ab + *bb) >> 1); rlm@1: rlm@1: // lower left rlm@1: *to_odd++ = RGB((*ar + *cr) >> 1, (*ag + *cg) >> 1, (*ab + *cb) >> 1); rlm@1: rlm@1: // lower right rlm@1: *to_odd++ = RGB((*ar + *br + *cr + *dr) >> 2, rlm@1: (*ag + *bg + *cg + *dg) >> 2, rlm@1: (*ab + *bb + *cb + *db) >> 2); rlm@1: rlm@1: // 'b' becomes 'a', 'd' becomes 'c' rlm@1: ar = br; rlm@1: ag = bg; rlm@1: ab = bb; rlm@1: cr = dr; rlm@1: cg = dg; rlm@1: cb = db; rlm@1: } rlm@1: rlm@1: // the "next" rgb row becomes the current; the old current rgb row is rlm@1: // recycled and serves as the new "next" row rlm@1: u8 *temp; rlm@1: temp = rgb_row_cur; rlm@1: rgb_row_cur = rgb_row_next; rlm@1: rgb_row_next = temp; rlm@1: rlm@1: // update the pointers for start of next pair of lines rlm@1: from = (u32 *)((u8 *)from_orig + srcPitch); rlm@1: to = (u32 *)((u8 *)to_orig + (dstPitch << 1)); rlm@1: to_odd = (u32 *)((u8 *)to + dstPitch); rlm@1: } rlm@1: } rlm@1: