mirror of
https://github.com/Pecusx/libretro-atari800.git
synced 2026-05-21 06:39:36 +02:00
265 lines
7.9 KiB
C
265 lines
7.9 KiB
C
/*
|
|
* pal_blending.c - blitting functions that emulate PAL delay line accurately
|
|
*
|
|
* Copyright (C) 2013 Tomasz Krasuski
|
|
* Copyright (C) 2013 Atari800 development team (see DOC/CREDITS)
|
|
*
|
|
* This file is part of the Atari800 emulator project which emulates
|
|
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
|
|
|
* Atari800 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 of the License, or
|
|
* (at your option) any later version.
|
|
|
|
* Atari800 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 Atari800; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#include "pal_blending.h"
|
|
|
|
#include "artifact.h"
|
|
#include "atari.h"
|
|
#include "colours.h"
|
|
#include "colours_pal.h"
|
|
#include "platform.h"
|
|
#include "screen.h"
|
|
|
|
#if SUPPORTS_CHANGE_VIDEOMODE
|
|
#include "videomode.h"
|
|
#endif /* SUPPORTS_CHANGE_VIDEOMODE */
|
|
|
|
static union {
|
|
UWORD bpp16[2][256]; /* 16-bit palette */
|
|
ULONG bpp32[2][256]; /* 32-bit palette */
|
|
} palette;
|
|
|
|
static ULONG shift_mask;
|
|
|
|
void PAL_BLENDING_UpdateLookup(void)
|
|
{
|
|
if (ARTIFACT_mode == ARTIFACT_PAL_BLEND) {
|
|
double yuv_table[256*5];
|
|
int even_pal[256];
|
|
int odd_pal[256];
|
|
int i;
|
|
double *ptr = yuv_table;
|
|
PLATFORM_pixel_format_t format;
|
|
|
|
COLOURS_PAL_GetYUV(yuv_table);
|
|
|
|
for (i = 0; i < 256; ++i) {
|
|
double y = *ptr++;
|
|
double even_u = *ptr++;
|
|
double odd_u = *ptr++;
|
|
double even_v = *ptr++;
|
|
double odd_v = *ptr++;
|
|
double r, g, b;
|
|
Colours_YUV2RGB(y, even_u, even_v, &r, &g, &b);
|
|
if (!COLOURS_PAL_external.loaded || COLOURS_PAL_external.adjust) {
|
|
r = Colours_Gamma2Linear(r, COLOURS_PAL_setup.gamma);
|
|
g = Colours_Gamma2Linear(g, COLOURS_PAL_setup.gamma);
|
|
b = Colours_Gamma2Linear(b, COLOURS_PAL_setup.gamma);
|
|
r = Colours_Linear2sRGB(r);
|
|
g = Colours_Linear2sRGB(g);
|
|
b = Colours_Linear2sRGB(b);
|
|
}
|
|
Colours_SetRGB(i, (int) (r * 255), (int) (g * 255), (int) (b * 255), even_pal);
|
|
Colours_YUV2RGB(y, odd_u, odd_v, &r, &g, &b);
|
|
if (!COLOURS_PAL_external.loaded || COLOURS_PAL_external.adjust) {
|
|
r = Colours_Gamma2Linear(r, COLOURS_PAL_setup.gamma);
|
|
g = Colours_Gamma2Linear(g, COLOURS_PAL_setup.gamma);
|
|
b = Colours_Gamma2Linear(b, COLOURS_PAL_setup.gamma);
|
|
r = Colours_Linear2sRGB(r);
|
|
g = Colours_Linear2sRGB(g);
|
|
b = Colours_Linear2sRGB(b);
|
|
}
|
|
Colours_SetRGB(i, (int) (r * 255), (int) (g * 255), (int) (b * 255), odd_pal);
|
|
}
|
|
PLATFORM_GetPixelFormat(&format);
|
|
shift_mask = (format.rmask & ~(format.rmask << 1)) | (format.gmask & ~(format.gmask << 1)) | (format.bmask & ~(format.bmask << 1));
|
|
switch (format.bpp) {
|
|
case 16:
|
|
PLATFORM_MapRGB(palette.bpp16[0], even_pal, 256);
|
|
PLATFORM_MapRGB(palette.bpp16[1], odd_pal, 256);
|
|
shift_mask |= shift_mask << 16;
|
|
break;
|
|
case 32:
|
|
PLATFORM_MapRGB(palette.bpp32[0], even_pal, 256);
|
|
PLATFORM_MapRGB(palette.bpp32[1], odd_pal, 256);
|
|
}
|
|
shift_mask = ~shift_mask;
|
|
}
|
|
}
|
|
|
|
void PAL_BLENDING_Blit16(ULONG *dest, UBYTE *src, int pitch, int width, int height, int start_odd)
|
|
{
|
|
register ULONG quad, quad_prev;
|
|
register UBYTE c;
|
|
register int pos;
|
|
UBYTE *src_prev = src;
|
|
int odd_prev = start_odd ^ 1;
|
|
int width_32;
|
|
if (width & 0x01)
|
|
width_32 = width + 1;
|
|
else
|
|
width_32 = width;
|
|
while (height > 0) {
|
|
pos = width_32;
|
|
do {
|
|
pos--;
|
|
c = src[pos];
|
|
/* Make QUAD_PREV have the same Y component as the current line's pixel. */
|
|
quad_prev = palette.bpp16[odd_prev][(src_prev[pos] & 0xf0) | (c & 0x0f)] << 16;
|
|
quad = palette.bpp16[start_odd][c] << 16;
|
|
pos--;
|
|
c = src[pos];
|
|
quad_prev |= palette.bpp16[odd_prev][(src_prev[pos] & 0xf0) | (c & 0x0f)];
|
|
quad |= palette.bpp16[start_odd][c];
|
|
/* Since QUAD_PREV and QUAD have the same Y component, computing
|
|
averages of even U/V and odd U/V is equal to computing averages
|
|
of even and odd RGB components. */
|
|
/* dest[pos >> 1] = ((quad+quad_prev) & shift_mask)/2; */
|
|
dest[pos >> 1] = (quad & quad_prev) + (((quad ^ quad_prev) & shift_mask) >> 1);
|
|
} while (pos > 0);
|
|
src_prev = src;
|
|
src += Screen_WIDTH;
|
|
dest += pitch;
|
|
height--;
|
|
start_odd ^= 1;
|
|
odd_prev ^= 1;
|
|
}
|
|
}
|
|
|
|
void PAL_BLENDING_Blit32(ULONG *dest, UBYTE *src, int pitch, int width, int height, int start_odd)
|
|
{
|
|
register ULONG quad, quad_prev;
|
|
register UBYTE c;
|
|
register int pos;
|
|
UBYTE *src_prev = src;
|
|
int odd_prev = start_odd ^ 1;
|
|
while (height > 0) {
|
|
pos = width;
|
|
do {
|
|
pos--;
|
|
c = src[pos];
|
|
/* Make QUAD_PREV have the same Y component as the current line's pixel. */
|
|
quad_prev = palette.bpp32[odd_prev][(src_prev[pos] & 0xf0) | (c & 0x0f)];
|
|
quad = palette.bpp32[start_odd][c];
|
|
/* Since QUAD_PREV and QUAD have the same Y component, computing
|
|
averages of even U/V and odd U/V is equal to computing averages
|
|
of even and odd RGB components. */
|
|
/* dest[pos] = ((quad+quad_prev) & shift_mask)/2; */
|
|
dest[pos] = (quad & quad_prev) + (((quad ^ quad_prev) & shift_mask) >> 1);
|
|
} while (pos > 0);
|
|
src_prev = src;
|
|
src += Screen_WIDTH;
|
|
dest += pitch;
|
|
height--;
|
|
start_odd ^= 1;
|
|
odd_prev ^= 1;
|
|
}
|
|
}
|
|
|
|
void PAL_BLENDING_BlitScaled16(ULONG *dest, UBYTE *src, int pitch, int width, int height, int dest_width, int dest_height, int start_odd)
|
|
{
|
|
register ULONG quad, quad_prev;
|
|
register int x;
|
|
int y = 0x10000;
|
|
int w1 = dest_width / 2 - 1;
|
|
int w = width << 16;
|
|
int h = height << 16;
|
|
int pos;
|
|
register int dx = w / dest_width;
|
|
int dy = h / dest_height;
|
|
int init_x = (width << 16) - 0x4000;
|
|
UBYTE *src_prev = src;
|
|
int odd_prev = start_odd ^ 1;
|
|
|
|
UBYTE c;
|
|
|
|
while (dest_height > 0) {
|
|
x = init_x;
|
|
pos = w1;
|
|
while (pos >= 0) {
|
|
c = src[x >> 16];
|
|
/* Make QUAD_PREV have the same Y component as the current line's pixel. */
|
|
quad_prev = palette.bpp16[odd_prev][(src_prev[x >> 16] & 0xf0) | (c & 0x0f)] << 16;
|
|
quad = palette.bpp16[start_odd][c] << 16;
|
|
x -= dx;
|
|
c = src[x >> 16];
|
|
quad_prev |= palette.bpp16[odd_prev][(src_prev[x >> 16] & 0xf0) | (c & 0x0f)];
|
|
quad |= palette.bpp16[start_odd][c];
|
|
x -= dx;
|
|
/* Since QUAD_PREV and QUAD have the same Y component, computing
|
|
averages of even U/V and odd U/V is equal to computing averages
|
|
of even and odd RGB components. */
|
|
/* dest[pos] = ((quad+quad_prev) & shift_mask)/2; */
|
|
dest[pos] = (quad & quad_prev) + (((quad ^ quad_prev) & shift_mask) >> 1);
|
|
pos--;
|
|
}
|
|
dest += pitch;
|
|
y -= dy;
|
|
--dest_height;
|
|
if (y < 0) {
|
|
y += 0x10000;
|
|
src_prev = src;
|
|
src += Screen_WIDTH;
|
|
start_odd ^= 1;
|
|
odd_prev ^= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
void PAL_BLENDING_BlitScaled32(ULONG *dest, UBYTE *src, int pitch, int width, int height, int dest_width, int dest_height, int start_odd)
|
|
{
|
|
register ULONG quad, quad_prev;
|
|
register int x;
|
|
int y = 0x10000;
|
|
int w1 = dest_width - 1;
|
|
int w = width << 16;
|
|
int h = height << 16;
|
|
int pos;
|
|
register int dx = w / dest_width;
|
|
int dy = h / dest_height;
|
|
int init_x = w - 0x4000;
|
|
UBYTE *src_prev = src;
|
|
int odd_prev = start_odd ^ 1;
|
|
|
|
UBYTE c;
|
|
|
|
while (dest_height > 0) {
|
|
x = init_x;
|
|
pos = w1;
|
|
while (pos >= 0) {
|
|
c = src[x >> 16];
|
|
/* Make QUAD_PREV have the same Y component as the current line's pixel. */
|
|
quad_prev = palette.bpp32[odd_prev][(src_prev[x >> 16] & 0xf0) | (c & 0x0f)];
|
|
quad = palette.bpp32[start_odd][c];
|
|
x -= dx;
|
|
/* Since QUAD_PREV and QUAD have the same Y component, computing
|
|
averages of even U/V and odd U/V is equal to computing averages
|
|
of even and odd RGB components. */
|
|
/* dest[pos] = ((quad+quad_prev) & shift_mask)/2; */
|
|
dest[pos] = (quad & quad_prev) + (((quad ^ quad_prev) & shift_mask) >> 1);
|
|
pos--;
|
|
}
|
|
dest += pitch;
|
|
y -= dy;
|
|
--dest_height;
|
|
if (y < 0) {
|
|
y += 0x10000;
|
|
src_prev = src;
|
|
src += Screen_WIDTH;
|
|
start_odd ^= 1;
|
|
odd_prev ^= 1;
|
|
}
|
|
}
|
|
}
|