mirror of
https://github.com/dborth/vbagx.git
synced 2024-11-23 02:59:17 +01:00
433 lines
14 KiB
C++
433 lines
14 KiB
C++
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
|
|
// Copyright (C) 1999-2003 Forgotten
|
|
// Copyright (C) 2004 Forgotten and the VBA development team
|
|
|
|
// This program is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation; either version 2, or(at your option)
|
|
// any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software Foundation,
|
|
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
/** Code adapted from Exult source code by Forgotten
|
|
** Scale.cc - Trying to scale with bilinear interpolation.
|
|
**
|
|
** Written: 6/14/00 - JSF
|
|
**/
|
|
|
|
#include "System.h"
|
|
|
|
static u8 row_cur[3*322];
|
|
static u8 row_next[3*322];
|
|
|
|
static u8 *rgb_row_cur = row_cur;
|
|
static u8 *rgb_row_next = row_next;
|
|
|
|
#define RGB(r,g,b) ((r)>>3) << systemRedShift |\
|
|
((g) >> 3) << systemGreenShift |\
|
|
((b) >> 3) << systemBlueShift\
|
|
|
|
static void fill_rgb_row_16(u16 *from, int src_width, u8 *row, int width)
|
|
{
|
|
u8 *copy_start = row + src_width*3;
|
|
u8 *all_stop = row + width*3;
|
|
while (row < copy_start)
|
|
{
|
|
u16 color = *from++;
|
|
*row++ = ((color >> systemRedShift) & 0x1f) << 3;
|
|
*row++ = ((color >> systemGreenShift) & 0x1f) << 3;
|
|
*row++ = ((color >> systemBlueShift) & 0x1f) << 3;
|
|
}
|
|
// any remaining elements to be written to 'row' are a replica of the
|
|
// preceding pixel
|
|
u8 *p = row-3;
|
|
while (row < all_stop)
|
|
{
|
|
// we're guaranteed three elements per pixel; could unroll the loop
|
|
// further, especially with a Duff's Device, but the gains would be
|
|
// probably limited (judging by profiler output)
|
|
*row++ = *p++;
|
|
*row++ = *p++;
|
|
*row++ = *p++;
|
|
}
|
|
}
|
|
|
|
static void fill_rgb_row_32(u32 *from, int src_width, u8 *row, int width)
|
|
{
|
|
u8 *copy_start = row + src_width*3;
|
|
u8 *all_stop = row + width*3;
|
|
while (row < copy_start)
|
|
{
|
|
u32 color = *from++;
|
|
*row++ = ((color >> systemRedShift) & 0x1f) << 3;
|
|
*row++ = ((color >> systemGreenShift) & 0x1f) << 3;
|
|
*row++ = ((color >> systemBlueShift) & 0x1f) << 3;
|
|
}
|
|
// any remaining elements to be written to 'row' are a replica of the
|
|
// preceding pixel
|
|
u8 *p = row-3;
|
|
while (row < all_stop)
|
|
{
|
|
// we're guaranteed three elements per pixel; could unroll the loop
|
|
// further, especially with a Duff's Device, but the gains would be
|
|
// probably limited (judging by profiler output)
|
|
*row++ = *p++;
|
|
*row++ = *p++;
|
|
*row++ = *p++;
|
|
}
|
|
}
|
|
|
|
void Bilinear(u8 *srcPtr, u32 srcPitch, u8 * /* deltaPtr */,
|
|
u8 *dstPtr, u32 dstPitch, int width, int height)
|
|
{
|
|
u16 *to = (u16 *)dstPtr;
|
|
u16 *to_odd = (u16 *)(dstPtr + dstPitch);
|
|
|
|
int from_width = width;
|
|
u16 *from = (u16 *)srcPtr;
|
|
fill_rgb_row_16(from, from_width, rgb_row_cur, width+1);
|
|
|
|
for(int y = 0; y < height; y++)
|
|
{
|
|
u16 *from_orig = from;
|
|
u16 *to_orig = to;
|
|
|
|
if (y+1 < height)
|
|
fill_rgb_row_16(from+width+2, from_width, rgb_row_next,
|
|
width+1);
|
|
else
|
|
fill_rgb_row_16(from, from_width, rgb_row_next, width+1);
|
|
|
|
// every pixel in the src region, is extended to 4 pixels in the
|
|
// destination, arranged in a square 'quad'; if the current src
|
|
// pixel is 'a', then in what follows 'b' is the src pixel to the
|
|
// right, 'c' is the src pixel below, and 'd' is the src pixel to
|
|
// the right and down
|
|
u8 *cur_row = rgb_row_cur;
|
|
u8 *next_row = rgb_row_next;
|
|
u8 *ar = cur_row++;
|
|
u8 *ag = cur_row++;
|
|
u8 *ab = cur_row++;
|
|
u8 *cr = next_row++;
|
|
u8 *cg = next_row++;
|
|
u8 *cb = next_row++;
|
|
for(int x=0; x < width; x++)
|
|
{
|
|
u8 *br = cur_row++;
|
|
u8 *bg = cur_row++;
|
|
u8 *bb = cur_row++;
|
|
u8 *dr = next_row++;
|
|
u8 *dg = next_row++;
|
|
u8 *db = next_row++;
|
|
|
|
// upper left pixel in quad: just copy it in
|
|
*to++ = RGB(*ar, *ag, *ab);
|
|
|
|
// upper right
|
|
*to++ = RGB((*ar+*br)>>1, (*ag+*bg)>>1, (*ab+*bb)>>1);
|
|
|
|
// lower left
|
|
*to_odd++ = RGB((*ar+*cr)>>1, (*ag+*cg)>>1, (*ab+*cb)>>1);
|
|
|
|
// lower right
|
|
*to_odd++ = RGB((*ar+*br+*cr+*dr)>>2,
|
|
(*ag+*bg+*cg+*dg)>>2,
|
|
(*ab+*bb+*cb+*db)>>2);
|
|
|
|
// 'b' becomes 'a', 'd' becomes 'c'
|
|
ar = br;
|
|
ag = bg;
|
|
ab = bb;
|
|
cr = dr;
|
|
cg = dg;
|
|
cb = db;
|
|
}
|
|
|
|
// the "next" rgb row becomes the current; the old current rgb row is
|
|
// recycled and serves as the new "next" row
|
|
u8 *temp;
|
|
temp = rgb_row_cur;
|
|
rgb_row_cur = rgb_row_next;
|
|
rgb_row_next = temp;
|
|
|
|
// update the pointers for start of next pair of lines
|
|
from = (u16 *)((u8 *)from_orig + srcPitch);
|
|
to = (u16 *)((u8 *)to_orig + (dstPitch << 1));
|
|
to_odd = (u16 *)((u8 *)to + dstPitch);
|
|
}
|
|
}
|
|
|
|
void BilinearPlus(u8 *srcPtr, u32 srcPitch, u8 * /* deltaPtr */,
|
|
u8 *dstPtr, u32 dstPitch, int width, int height)
|
|
{
|
|
u16 *to = (u16 *)dstPtr;
|
|
u16 *to_odd = (u16 *)(dstPtr + dstPitch);
|
|
|
|
int from_width = width;
|
|
u16 *from = (u16 *)srcPtr;
|
|
fill_rgb_row_16(from, from_width, rgb_row_cur, width+1);
|
|
|
|
for(int y = 0; y < height; y++)
|
|
{
|
|
u16 *from_orig = from;
|
|
u16 *to_orig = to;
|
|
|
|
if (y+1 < height)
|
|
fill_rgb_row_16(from+width+2, from_width, rgb_row_next,
|
|
width+1);
|
|
else
|
|
fill_rgb_row_16(from, from_width, rgb_row_next, width+1);
|
|
|
|
// every pixel in the src region, is extended to 4 pixels in the
|
|
// destination, arranged in a square 'quad'; if the current src
|
|
// pixel is 'a', then in what follows 'b' is the src pixel to the
|
|
// right, 'c' is the src pixel below, and 'd' is the src pixel to
|
|
// the right and down
|
|
u8 *cur_row = rgb_row_cur;
|
|
u8 *next_row = rgb_row_next;
|
|
u8 *ar = cur_row++;
|
|
u8 *ag = cur_row++;
|
|
u8 *ab = cur_row++;
|
|
u8 *cr = next_row++;
|
|
u8 *cg = next_row++;
|
|
u8 *cb = next_row++;
|
|
for(int x=0; x < width; x++)
|
|
{
|
|
u8 *br = cur_row++;
|
|
u8 *bg = cur_row++;
|
|
u8 *bb = cur_row++;
|
|
u8 *dr = next_row++;
|
|
u8 *dg = next_row++;
|
|
u8 *db = next_row++;
|
|
|
|
// upper left pixel in quad: just copy it in
|
|
//*to++ = manip.rgb(*ar, *ag, *ab);
|
|
#ifdef USE_ORIGINAL_BILINEAR_PLUS
|
|
*to++ = RGB(
|
|
(((*ar)<<2) +((*ar)) + (*cr+*br+*br) )>> 3,
|
|
(((*ag)<<2) +((*ag)) + (*cg+*bg+*bg) )>> 3,
|
|
(((*ab)<<2) +((*ab)) + (*cb+*bb+*bb) )>> 3);
|
|
#else
|
|
*to++ = RGB(
|
|
(((*ar)<<3) +((*ar)<<1) + (*cr+*br+*br+*cr) )>> 4,
|
|
(((*ag)<<3) +((*ag)<<1) + (*cg+*bg+*bg+*cg) )>> 4,
|
|
(((*ab)<<3) +((*ab)<<1) + (*cb+*bb+*bb+*cb) )>> 4);
|
|
#endif
|
|
|
|
// upper right
|
|
*to++ = RGB((*ar+*br)>>1, (*ag+*bg)>>1, (*ab+*bb)>>1);
|
|
|
|
// lower left
|
|
*to_odd++ = RGB((*ar+*cr)>>1, (*ag+*cg)>>1, (*ab+*cb)>>1);
|
|
|
|
// lower right
|
|
*to_odd++ = RGB((*ar+*br+*cr+*dr)>>2,
|
|
(*ag+*bg+*cg+*dg)>>2,
|
|
(*ab+*bb+*cb+*db)>>2);
|
|
|
|
// 'b' becomes 'a', 'd' becomes 'c'
|
|
ar = br;
|
|
ag = bg;
|
|
ab = bb;
|
|
cr = dr;
|
|
cg = dg;
|
|
cb = db;
|
|
}
|
|
|
|
// the "next" rgb row becomes the current; the old current rgb row is
|
|
// recycled and serves as the new "next" row
|
|
u8 *temp;
|
|
temp = rgb_row_cur;
|
|
rgb_row_cur = rgb_row_next;
|
|
rgb_row_next = temp;
|
|
|
|
// update the pointers for start of next pair of lines
|
|
from = (u16 *)((u8 *)from_orig + srcPitch);
|
|
to = (u16 *)((u8 *)to_orig + (dstPitch << 1));
|
|
to_odd = (u16 *)((u8 *)to + dstPitch);
|
|
}
|
|
}
|
|
|
|
void Bilinear32(u8 *srcPtr, u32 srcPitch, u8 * /* deltaPtr */,
|
|
u8 *dstPtr, u32 dstPitch, int width, int height)
|
|
{
|
|
u32 *to = (u32 *)dstPtr;
|
|
u32 *to_odd = (u32 *)(dstPtr + dstPitch);
|
|
|
|
int from_width = width;
|
|
if(width+1 < from_width)
|
|
from_width = width+1;
|
|
u32 *from = (u32 *)srcPtr;
|
|
fill_rgb_row_32(from, from_width, rgb_row_cur, width+1);
|
|
|
|
for(int y = 0; y < height; y++)
|
|
{
|
|
u32 *from_orig = from;
|
|
u32 *to_orig = to;
|
|
|
|
if (y+1 < height)
|
|
fill_rgb_row_32(from+width+1, from_width, rgb_row_next,
|
|
width+1);
|
|
else
|
|
fill_rgb_row_32(from, from_width, rgb_row_next, width+1);
|
|
|
|
// every pixel in the src region, is extended to 4 pixels in the
|
|
// destination, arranged in a square 'quad'; if the current src
|
|
// pixel is 'a', then in what follows 'b' is the src pixel to the
|
|
// right, 'c' is the src pixel below, and 'd' is the src pixel to
|
|
// the right and down
|
|
u8 *cur_row = rgb_row_cur;
|
|
u8 *next_row = rgb_row_next;
|
|
u8 *ar = cur_row++;
|
|
u8 *ag = cur_row++;
|
|
u8 *ab = cur_row++;
|
|
u8 *cr = next_row++;
|
|
u8 *cg = next_row++;
|
|
u8 *cb = next_row++;
|
|
for(int x=0; x < width; x++)
|
|
{
|
|
u8 *br = cur_row++;
|
|
u8 *bg = cur_row++;
|
|
u8 *bb = cur_row++;
|
|
u8 *dr = next_row++;
|
|
u8 *dg = next_row++;
|
|
u8 *db = next_row++;
|
|
|
|
// upper left pixel in quad: just copy it in
|
|
*to++ = RGB(*ar, *ag, *ab);
|
|
|
|
// upper right
|
|
*to++ = RGB((*ar+*br)>>1, (*ag+*bg)>>1, (*ab+*bb)>>1);
|
|
|
|
// lower left
|
|
*to_odd++ = RGB((*ar+*cr)>>1, (*ag+*cg)>>1, (*ab+*cb)>>1);
|
|
|
|
// lower right
|
|
*to_odd++ = RGB((*ar+*br+*cr+*dr)>>2,
|
|
(*ag+*bg+*cg+*dg)>>2,
|
|
(*ab+*bb+*cb+*db)>>2);
|
|
|
|
// 'b' becomes 'a', 'd' becomes 'c'
|
|
ar = br;
|
|
ag = bg;
|
|
ab = bb;
|
|
cr = dr;
|
|
cg = dg;
|
|
cb = db;
|
|
}
|
|
|
|
// the "next" rgb row becomes the current; the old current rgb row is
|
|
// recycled and serves as the new "next" row
|
|
u8 *temp;
|
|
temp = rgb_row_cur;
|
|
rgb_row_cur = rgb_row_next;
|
|
rgb_row_next = temp;
|
|
|
|
// update the pointers for start of next pair of lines
|
|
from = (u32 *)((u8 *)from_orig + srcPitch);
|
|
to = (u32 *)((u8 *)to_orig + (dstPitch << 1));
|
|
to_odd = (u32 *)((u8 *)to + dstPitch);
|
|
}
|
|
}
|
|
|
|
void BilinearPlus32(u8 *srcPtr, u32 srcPitch, u8 * /* deltaPtr */,
|
|
u8 *dstPtr, u32 dstPitch, int width, int height)
|
|
{
|
|
u32 *to = (u32 *)dstPtr;
|
|
u32 *to_odd = (u32 *)(dstPtr + dstPitch);
|
|
|
|
int from_width = width;
|
|
if(width+1 < from_width)
|
|
from_width = width+1;
|
|
u32 *from = (u32 *)srcPtr;
|
|
fill_rgb_row_32(from, from_width, rgb_row_cur, width+1);
|
|
|
|
for(int y = 0; y < height; y++)
|
|
{
|
|
u32 *from_orig = from;
|
|
u32 *to_orig = to;
|
|
|
|
if (y+1 < height)
|
|
fill_rgb_row_32(from+width+1, from_width, rgb_row_next,
|
|
width+1);
|
|
else
|
|
fill_rgb_row_32(from, from_width, rgb_row_next, width+1);
|
|
|
|
// every pixel in the src region, is extended to 4 pixels in the
|
|
// destination, arranged in a square 'quad'; if the current src
|
|
// pixel is 'a', then in what follows 'b' is the src pixel to the
|
|
// right, 'c' is the src pixel below, and 'd' is the src pixel to
|
|
// the right and down
|
|
u8 *cur_row = rgb_row_cur;
|
|
u8 *next_row = rgb_row_next;
|
|
u8 *ar = cur_row++;
|
|
u8 *ag = cur_row++;
|
|
u8 *ab = cur_row++;
|
|
u8 *cr = next_row++;
|
|
u8 *cg = next_row++;
|
|
u8 *cb = next_row++;
|
|
for(int x=0; x < width; x++)
|
|
{
|
|
u8 *br = cur_row++;
|
|
u8 *bg = cur_row++;
|
|
u8 *bb = cur_row++;
|
|
u8 *dr = next_row++;
|
|
u8 *dg = next_row++;
|
|
u8 *db = next_row++;
|
|
|
|
// upper left pixel in quad: just copy it in
|
|
//*to++ = manip.rgb(*ar, *ag, *ab);
|
|
#ifdef USE_ORIGINAL_BILINEAR_PLUS
|
|
*to++ = RGB(
|
|
(((*ar)<<2) +((*ar)) + (*cr+*br+*br) )>> 3,
|
|
(((*ag)<<2) +((*ag)) + (*cg+*bg+*bg) )>> 3,
|
|
(((*ab)<<2) +((*ab)) + (*cb+*bb+*bb) )>> 3);
|
|
#else
|
|
*to++ = RGB(
|
|
(((*ar)<<3) +((*ar)<<1) + (*cr+*br+*br+*cr) )>> 4,
|
|
(((*ag)<<3) +((*ag)<<1) + (*cg+*bg+*bg+*cg) )>> 4,
|
|
(((*ab)<<3) +((*ab)<<1) + (*cb+*bb+*bb+*cb) )>> 4);
|
|
#endif
|
|
|
|
// upper right
|
|
*to++ = RGB((*ar+*br)>>1, (*ag+*bg)>>1, (*ab+*bb)>>1);
|
|
|
|
// lower left
|
|
*to_odd++ = RGB((*ar+*cr)>>1, (*ag+*cg)>>1, (*ab+*cb)>>1);
|
|
|
|
// lower right
|
|
*to_odd++ = RGB((*ar+*br+*cr+*dr)>>2,
|
|
(*ag+*bg+*cg+*dg)>>2,
|
|
(*ab+*bb+*cb+*db)>>2);
|
|
|
|
// 'b' becomes 'a', 'd' becomes 'c'
|
|
ar = br;
|
|
ag = bg;
|
|
ab = bb;
|
|
cr = dr;
|
|
cg = dg;
|
|
cb = db;
|
|
}
|
|
|
|
// the "next" rgb row becomes the current; the old current rgb row is
|
|
// recycled and serves as the new "next" row
|
|
u8 *temp;
|
|
temp = rgb_row_cur;
|
|
rgb_row_cur = rgb_row_next;
|
|
rgb_row_next = temp;
|
|
|
|
// update the pointers for start of next pair of lines
|
|
from = (u32 *)((u8 *)from_orig + srcPitch);
|
|
to = (u32 *)((u8 *)to_orig + (dstPitch << 1));
|
|
to_odd = (u32 *)((u8 *)to + dstPitch);
|
|
}
|
|
}
|
|
|