blob: 2dae0a0de9c8b9079a03d4fd9e5c66345efead2c [file] [log] [blame] [raw]
#include <math.h>
#include "tedmem.h"
#include "video.h"
//
/* ---------- Inline functions ---------- */
static double myMin(double a, double b)
{
return a>b ? b : a;
}
static double myMax(double a, double b)
{
return a>b ? a : b;
}
inline static void RGB82YCrCb(double R, double G, double B, double &Yc, double &Cb, double &Cr)
{
// The equations for color conversion used here, probably aren't
// exact, but they seem to do an OK _fdc.
Yc = 16 + 1.0 / 256.0 * ( 65.738 * R + 129.057 * G + 25.064 * B);
Cb = 0.0 + 1.0 / 256.0 * ( - 37.945 * R - 74.494 * G + 112.439 * B);
Cr = 0.0 + 1.0 / 256.0 * ( 112.439 * R - 94.154 * G - 18.285 * B);
}
inline static void RGB2YUV(double R, double G, double B, Yuv &yuv)
{
// RGB -> YUV
yuv.y = (int)(0.299*R + 0.587*G + 0.114*B + 0.5);
yuv.u = (int)(- 0.14713*R - 0.28886*G + 0.436*B + 0.5); // U = 0.492111 (B'-Y')
yuv.v = (int)(0.615*R - 0.51499*G - 0.10001*B + 0.5); // V = 0.877283 (R'-Y')
}
static unsigned int palette[256];
static Yuv yuvPalette[256];
void init_palette(TED *videoChip)
{
unsigned int i;
double Uc, Vc, Yc, PI = 3.14159265;
i = videoChip->getColorCount();
// calculate palette based on the HUE values
for (unsigned int ix = 0; ix < i; ix++) {
Color c = videoChip->getColor(ix);
double bsat = c.saturation;
Uc = bsat * ((double) cos( c.hue * PI / 180.0 ));
Vc = bsat * ((double) sin( c.hue * PI / 180.0 ));
Yc = c.luma ? (c.luma - 2.0) * 255.0 / (5.0 - 2.0) : 0;
// RED, GREEN and BLUE component
Uint8 Rc = (Uint8) myMax(myMin((Yc + Vc / 0.877283), 255.0), 0);
Uint8 Gc = (Uint8) myMax(myMin((Yc - 0.39465 * Uc - 0.58060 * Vc ), 255.0), 0);
Uint8 Bc = (Uint8) myMax(myMin((Yc + Uc / 0.492111), 255.0), 0);
palette[ix + 128] = palette[ix] = Bc | (Gc << 8) | (Rc << 16);
#if 1
yuvPalette[ix].y = (unsigned char)(Yc);
yuvPalette[ix].u = (int)(Uc + 128);
yuvPalette[ix].v = (int)(Vc + 128);
#else
rgb2yuv(Bc, Gc, Rc, yuvPalette[ix].y, yuvPalette[ix].u, yuvPalette[ix].v);
#endif
yuvPalette[ix + 128] = yuvPalette[ix];
}
}
unsigned int *palette_get_rgb()
{
return palette;
}
static bool doubleScan = true;
static unsigned int evenFrame = 0;
void video_convert_buffer(unsigned int *pImage, unsigned int srcpitch, unsigned char *screenptr)
{
int i;
int Uc[4], Vc[4], Up[4], Vp[4];
const Yuv *yuvLookup = yuvPalette;
const int interlace = 0;
// const int thisFrameInterlaced = !evenFrame && doubleScan ? 1 : 0;
unsigned char *fb = screenptr;
unsigned char *prevLine = fb;
// unsigned char *currLine = fb;
i = SCREENY; /// 2;
Up[0] = Up[1] = Up[2] = Up[3] = Vp[0] = Vp[1] = Vp[2] = Vp[3] = 0;
do {
int k = doubleScan & !interlace;
do {
int shade = doubleScan && !k ? 85 : 100;
int j = 0;
const Yuv *yuvBuffer = yuvLookup;
// const unsigned int lineVphase = (i & 1) ^ thisFrameInterlaced;
const unsigned int invertPhase = 0; //(vPhase[0] ^ (lineVphase) && isPalMode) ? -1 : 0;
const unsigned int invertPhaseNext = 0; //((vPhase[1] ^ (lineVphase ^ 1)) && isPalMode) ? -1 : 0;
Yuv yuv = yuvBuffer[*fb];
Uc[0] = Uc[1] = Uc[2] = Uc[3] = yuv.u;
Vc[0] = Vc[1] = Vc[2] = Vc[3] = yuv.v ^ invertPhase;
do {
int Y0, Y1;
int filtX = j % 3;
// current row
yuv = yuvBuffer[fb[j << 1]];
Y0 = (int)(yuv.y) * shade / 100;
Uc[filtX] = yuv.u;
Vc[filtX] = yuv.v ^ invertPhase;
// previous one
yuv = yuvBuffer[prevLine[j << 1]];
Up[filtX] = yuv.u;
Vp[filtX] = yuv.v ^ invertPhaseNext;
// move one pixel
yuv = yuvBuffer[fb[(j << 1) + 1]];
Y1 = (int)(yuv.y) * shade / 100;
Uc[(filtX + 1) % 3] = yuv.u;
Vc[(filtX + 1) % 3] = yuv.v ^ invertPhase;
// previous row
yuv = yuvBuffer[prevLine[(j << 1) + 1]];
Up[(filtX + 1) % 3] = yuv.u;
Vp[(filtX + 1) % 3] = yuv.v ^ invertPhaseNext;
// average color signal
// approximately a 13 -> 1.3 MHz Butterworth filter
const unsigned char U = (Uc[0] + Uc[1] + Uc[2] +
Up[0] + Up[1] + Up[2]) / 6; // U
const unsigned char V = (Uc[0] + Vc[1] + Vc[2] +
Vp[0] + Vp[1] + Vp[2]) / 6; // V
// store result
*(pImage + j) =
(U << 0)
| (Y0 << 8)
| (V << 16)
| (Y1 << 24);
} while (j++ < SCREENX / 2);
// take care of double scan
if (k == 0) {
prevLine = fb;
}
pImage += srcpitch << interlace;// << doubleScan;
} while (k--);
fb += srcpitch;
} while (--i);
evenFrame = !evenFrame;
}