apply a mutated bisqwit's deemph approach instead
This commit is contained in:
parent
75f75d6900
commit
52d00c97b7
|
@ -86,8 +86,6 @@ pal *palo;
|
|||
(type) (y + to_rgb [4] * i + to_rgb [5] * q)\
|
||||
)
|
||||
|
||||
|
||||
|
||||
static void ApplyDeemphasisNTSC(int entry, u8& r, u8& g, u8& b)
|
||||
{
|
||||
static float const to_float = 1.0f / 0xFF;
|
||||
|
@ -155,10 +153,101 @@ static void ApplyDeemphasisNTSC(int entry, u8& r, u8& g, u8& b)
|
|||
{ 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f };
|
||||
fb = YIQ_TO_RGB( y, i, q, default_decoder, float, fr, fg );
|
||||
|
||||
#define CLAMP(x) (x<0?0:(x>1.0f?1.0f:x))
|
||||
#define CLAMP(x) ((x)<0?0:((x)>1.0f?1.0f:(x)))
|
||||
r = (u8)(CLAMP(fr)*255);
|
||||
g = (u8)(CLAMP(fg)*255);
|
||||
b = (u8)(CLAMP(fb)*255);
|
||||
|
||||
//doesnt help
|
||||
//float gamma=1.8f;
|
||||
// auto gammafix = [=](float f) { return f < 0.f ? 0.f : std::pow(f, 2.2f / gamma); };
|
||||
// auto clamp = [](int v) { return v<0 ? 0 : v>255 ? 255 : v; };
|
||||
// r = clamp(255 * gammafix(y + 0.946882f*i + 0.623557f*q));
|
||||
// g = clamp(255 * gammafix(y + -0.274788f*i + -0.635691f*q));
|
||||
// b = clamp(255 * gammafix(y + -1.108545f*i + 1.709007f*q));
|
||||
}
|
||||
|
||||
float bisqwit_gammafix(float f, float gamma) { return f < 0.f ? 0.f : std::pow(f, 2.2f / gamma); }
|
||||
int bisqwit_clamp(int v) { return v<0 ? 0 : v>255 ? 255 : v; }
|
||||
|
||||
// Calculate the luma and chroma by emulating the relevant circuits:
|
||||
int bisqwit_wave(int p, int color) { return (color+p+8)%12 < 6; }
|
||||
|
||||
static void ApplyDeemphasisBisqwit(int entry, u8& r, u8& g, u8& b)
|
||||
{
|
||||
if(entry<64) return;
|
||||
int myr, myg, myb;
|
||||
// The input value is a NES color index (with de-emphasis bits).
|
||||
// We need RGB values. Convert the index into RGB.
|
||||
// For most part, this process is described at:
|
||||
// http://wiki.nesdev.com/w/index.php/NTSC_video
|
||||
|
||||
// Decode the color index
|
||||
int color = (entry & 0x0F), level = color<0xE ? (entry>>4) & 3 : 1;
|
||||
|
||||
// Voltage levels, relative to synch voltage
|
||||
static const float black=.518f, white=1.962f, attenuation=.746f,
|
||||
levels[8] = {.350f, .518f, .962f,1.550f, // Signal low
|
||||
1.094f,1.506f,1.962f,1.962f}; // Signal high
|
||||
|
||||
float lo_and_hi[2] = { levels[level + 4 * (color == 0x0)],
|
||||
levels[level + 4 * (color < 0xD)] };
|
||||
|
||||
|
||||
|
||||
//fceux alteration: two passes
|
||||
//1st pass calculates bisqwit's base color
|
||||
//2nd pass calculates it with deemph
|
||||
//finally, we'll do something dumb: find a 'scale factor' between them and apply it to the input palette. (later, we could pregenerate the scale factors)
|
||||
//whatever, it gets the job done.
|
||||
for(int pass=0;pass<2;pass++)
|
||||
{
|
||||
float y=0.f, i=0.f, q=0.f, gamma=1.8f;
|
||||
for(int p=0; p<12; ++p) // 12 clock cycles per pixel.
|
||||
{
|
||||
// NES NTSC modulator (square wave between two voltage levels):
|
||||
float spot = lo_and_hi[bisqwit_wave(p,color)];
|
||||
|
||||
// De-emphasis bits attenuate a part of the signal:
|
||||
if(pass==1)
|
||||
{
|
||||
if(((entry & 0x40) && bisqwit_wave(p,12))
|
||||
|| ((entry & 0x80) && bisqwit_wave(p, 4))
|
||||
|| ((entry &0x100) && bisqwit_wave(p, 8))) spot *= attenuation;
|
||||
}
|
||||
|
||||
// Normalize:
|
||||
float v = (spot - black) / (white-black) / 12.f;
|
||||
|
||||
// Ideal TV NTSC demodulator:
|
||||
y += v;
|
||||
i += v * std::cos(3.141592653 * p / 6);
|
||||
q += v * std::sin(3.141592653 * p / 6); // Or cos(... p-3 ... )
|
||||
// Note: Integrating cos() and sin() for p-0.5 .. p+0.5 range gives
|
||||
// the exactly same result, scaled by a factor of 2*cos(pi/12).
|
||||
}
|
||||
|
||||
// Convert YIQ into RGB according to FCC-sanctioned conversion matrix.
|
||||
|
||||
int rt = bisqwit_clamp(255 * bisqwit_gammafix(y + 0.946882f*i + 0.623557f*q,gamma));
|
||||
int gt = bisqwit_clamp(255 * bisqwit_gammafix(y + -0.274788f*i + -0.635691f*q,gamma));
|
||||
int bt = bisqwit_clamp(255 * bisqwit_gammafix(y + -1.108545f*i + 1.709007f*q,gamma));
|
||||
|
||||
if(pass==0) myr = rt, myg = gt, myb = bt;
|
||||
else
|
||||
{
|
||||
float rscale = (float)rt / myr;
|
||||
float gscale = (float)gt / myg;
|
||||
float bscale = (float)bt / myb;
|
||||
#define BCLAMP(x) ((x)<0?0:((x)>255?255:(x)))
|
||||
if(myr!=0) r = (u8)(BCLAMP(r*rscale));
|
||||
if(myg!=0) g = (u8)(BCLAMP(g*gscale));
|
||||
if(myb!=0) b = (u8)(BCLAMP(b*bscale));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
//classic algorithm
|
||||
|
@ -195,7 +284,7 @@ static void ApplyDeemphasisComplete(pal* pal512)
|
|||
for(int p=0;p<64;p++,idx++)
|
||||
{
|
||||
pal512[idx] = pal512[p];
|
||||
ApplyDeemphasisNTSC(idx,pal512[idx].r,pal512[idx].g,pal512[idx].b);
|
||||
ApplyDeemphasisBisqwit(idx,pal512[idx].r,pal512[idx].g,pal512[idx].b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue