mirror of https://github.com/stella-emu/stella.git
OK, Blargg is now officially in the codebase! There's still quite a bit
left to do, but the basic functionality is now there. Alt 1 - Alt 6 selects among TV modes as follows: off, composite, svideo, rgb, bad and custom. The latter is just composite at this point; there's no code to actually change specific adjustables yet. Alt 7/Shift-Alt 7 increases/ decreases scanline blend intensity (20% - 100%). git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2456 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
parent
1e8f45a10f
commit
e3fa8da1f9
|
@ -27,24 +27,21 @@
|
|||
#include "FBSurfaceTIA.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FBSurfaceTIA::FBSurfaceTIA(FrameBufferGL& buffer, uInt32 baseWidth, uInt32 baseHeight,
|
||||
uInt32 imgX, uInt32 imgY, uInt32 imgW, uInt32 imgH)
|
||||
FBSurfaceTIA::FBSurfaceTIA(FrameBufferGL& buffer)
|
||||
: myFB(buffer),
|
||||
myGL(myFB.p_gl),
|
||||
myTexture(NULL),
|
||||
myVBOID(0),
|
||||
myImageX(imgX),
|
||||
myImageY(imgY),
|
||||
myImageW(imgW),
|
||||
myImageH(imgH)
|
||||
myScanlinesEnabled(false),
|
||||
myScanlineIntensityI(50),
|
||||
myScanlineIntensityF(0.5)
|
||||
{
|
||||
myTexID[0] = myTexID[1] = 0;
|
||||
|
||||
// Fill buffer struct with valid data
|
||||
myTexWidth = FrameBufferGL::power_of_two(baseWidth);
|
||||
myTexHeight = FrameBufferGL::power_of_two(baseHeight);
|
||||
myTexCoordW = (GLfloat) baseWidth / myTexWidth;
|
||||
myTexCoordH = (GLfloat) baseHeight / myTexHeight;
|
||||
// Texture width is set to contain all possible sizes for a TIA image,
|
||||
// including Blargg filtering
|
||||
myTexWidth = FrameBufferGL::power_of_two(ATARI_NTSC_OUT_WIDTH(160));
|
||||
myTexHeight = FrameBufferGL::power_of_two(320);
|
||||
|
||||
// Based on experimentation, the following are the fastest 16-bit
|
||||
// formats for OpenGL (on all platforms)
|
||||
|
@ -56,10 +53,6 @@ FBSurfaceTIA::FBSurfaceTIA(FrameBufferGL& buffer, uInt32 baseWidth, uInt32 baseH
|
|||
0x0000f800, 0x000007c0, 0x0000003e, 0x00000000);
|
||||
#endif
|
||||
myPitch = myTexture->pitch >> 1;
|
||||
|
||||
// Associate the SDL surface with a GL texture object
|
||||
updateCoords();
|
||||
reload();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -98,6 +91,8 @@ void FBSurfaceTIA::update()
|
|||
uInt32 height = myTIA->height();
|
||||
uInt16* buffer = (uInt16*) myTexture->pixels;
|
||||
|
||||
// TODO - Eventually 'phosphor' won't be a separate mode, and will become
|
||||
// a post-processing filter by blending several frames.
|
||||
switch(myFB.myFilterType)
|
||||
{
|
||||
case FrameBufferGL::kNone:
|
||||
|
@ -137,6 +132,14 @@ void FBSurfaceTIA::update()
|
|||
|
||||
case FrameBufferGL::kBlarggNTSC:
|
||||
{
|
||||
#ifdef HAVE_GL_BGRA
|
||||
#define BLIT16 blit_1555
|
||||
#else
|
||||
#define BLIT16 blit_5551
|
||||
#endif
|
||||
myFB.myNTSCFilter.BLIT16(currentFrame, width,
|
||||
myTexture->w, height,
|
||||
buffer, myTexture->pitch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -163,11 +166,10 @@ void FBSurfaceTIA::update()
|
|||
myGL.TexCoordPointer(2, GL_FLOAT, 0, (const GLvoid*)(8*sizeof(GLfloat)));
|
||||
myGL.DrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
#if 0
|
||||
if(1)//myFB.myScanlinesEnabled)
|
||||
if(myScanlinesEnabled)
|
||||
{
|
||||
myGL.Enable(GL_BLEND);
|
||||
myGL.Color4f(1.0f, 1.0f, 1.0f, 0.5f);
|
||||
myGL.Color4f(1.0f, 1.0f, 1.0f, myScanlineIntensityF);
|
||||
myGL.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
myGL.BindTexture(GL_TEXTURE_2D, myTexID[1]);
|
||||
myGL.VertexPointer(2, GL_FLOAT, 0, (const GLvoid*)(16*sizeof(GLfloat)));
|
||||
|
@ -175,7 +177,6 @@ void FBSurfaceTIA::update()
|
|||
myGL.DrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
myGL.Disable(GL_BLEND);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -183,11 +184,10 @@ void FBSurfaceTIA::update()
|
|||
myGL.TexCoordPointer(2, GL_FLOAT, 0, myCoord+8);
|
||||
myGL.DrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
#if 0
|
||||
if(1)//myFB.myScanlinesEnabled)
|
||||
if(myScanlinesEnabled)
|
||||
{
|
||||
myGL.Enable(GL_BLEND);
|
||||
myGL.Color4f(1.0f, 1.0f, 1.0f, 0.5f);
|
||||
myGL.Color4f(1.0f, 1.0f, 1.0f, myScanlineIntensityF);
|
||||
myGL.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
myGL.BindTexture(GL_TEXTURE_2D, myTexID[1]);
|
||||
myGL.VertexPointer(2, GL_FLOAT, 0, myCoord+16);
|
||||
|
@ -195,7 +195,6 @@ void FBSurfaceTIA::update()
|
|||
myGL.DrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
myGL.Disable(GL_BLEND);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
myGL.DisableClientState(GL_VERTEX_ARRAY);
|
||||
|
@ -279,9 +278,7 @@ void FBSurfaceTIA::reload()
|
|||
void FBSurfaceTIA::setFilter(const string& name)
|
||||
{
|
||||
// We only do GL_NEAREST or GL_LINEAR for now
|
||||
GLint filter = GL_NEAREST;
|
||||
if(name == "linear")
|
||||
filter = GL_LINEAR;
|
||||
GLint filter = name == "linear" ? GL_LINEAR : GL_NEAREST;
|
||||
|
||||
myGL.BindTexture(GL_TEXTURE_2D, myTexID[0]);
|
||||
myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
|
||||
|
@ -290,9 +287,28 @@ void FBSurfaceTIA::setFilter(const string& name)
|
|||
myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FBSurfaceTIA::updateCoords(uInt32 baseH,
|
||||
uInt32 imgX, uInt32 imgY, uInt32 imgW, uInt32 imgH)
|
||||
{
|
||||
myBaseH = baseH;
|
||||
myImageX = imgX; myImageY = imgY;
|
||||
myImageW = imgW; myImageH = imgH;
|
||||
|
||||
updateCoords();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FBSurfaceTIA::updateCoords()
|
||||
{
|
||||
// Normal TIA rendering and TV effects use different widths
|
||||
// We use the same buffer, and only pick the width we need
|
||||
myBaseW = myFB.myFilterType == FrameBufferGL::kBlarggNTSC ?
|
||||
ATARI_NTSC_OUT_WIDTH(160) : 160;
|
||||
|
||||
myTexCoordW = (GLfloat) myBaseW / myTexWidth;
|
||||
myTexCoordH = (GLfloat) myBaseH / myTexHeight;
|
||||
|
||||
// Vertex coordinates for texture 0 (main texture)
|
||||
// Upper left (x,y)
|
||||
myCoord[0] = (GLfloat)myImageX;
|
||||
|
@ -344,10 +360,10 @@ void FBSurfaceTIA::updateCoords()
|
|||
myCoord[27] = 0.0f;
|
||||
// Lower left (x,y+h)
|
||||
myCoord[28] = 0.0f;
|
||||
myCoord[29] = (GLfloat)(myImageH/myFB.myZoomLevel);
|
||||
myCoord[29] = GLfloat(myImageH) / (myImageH / myBaseH);
|
||||
// Lower right (x+w,y+h)
|
||||
myCoord[30] = 1.0f;
|
||||
myCoord[31] = (GLfloat)(myImageH/myFB.myZoomLevel);
|
||||
myCoord[31] = GLfloat(myImageH) / (myImageH / myBaseH);
|
||||
|
||||
// Cache vertex and texture coordinates using vertex buffer object
|
||||
if(myFB.myVBOAvailable)
|
||||
|
@ -360,7 +376,7 @@ void FBSurfaceTIA::updateCoords()
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FBSurfaceTIA::setTIAPalette(const uInt32* palette)
|
||||
{
|
||||
myNTSCFilter.setTIAPalette(palette);
|
||||
myFB.myNTSCFilter.setTIAPalette(palette);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include "bspf.hxx"
|
||||
#include "FrameBuffer.hxx"
|
||||
#include "FrameBufferGL.hxx"
|
||||
#include "NTSCFilter.hxx"
|
||||
|
||||
/**
|
||||
A surface suitable for OpenGL rendering mode, but specifically for
|
||||
|
@ -40,8 +39,7 @@ class FBSurfaceTIA : public FBSurface
|
|||
friend class FrameBufferGL;
|
||||
|
||||
public:
|
||||
FBSurfaceTIA(FrameBufferGL& buffer, uInt32 baseWidth, uInt32 baseHeight,
|
||||
uInt32 imgX, uInt32 imgY, uInt32 imgW, uInt32 imgH);
|
||||
FBSurfaceTIA(FrameBufferGL& buffer);
|
||||
virtual ~FBSurfaceTIA();
|
||||
|
||||
// TIA surfaces don't implement most of the drawing primitives,
|
||||
|
@ -59,6 +57,8 @@ class FBSurfaceTIA : public FBSurface
|
|||
void setTIA(const TIA& tia) { myTIA = &tia; }
|
||||
void setTIAPalette(const uInt32* palette);
|
||||
void setFilter(const string& name);
|
||||
void enableScanlines(bool enable) { myScanlinesEnabled = enable; }
|
||||
void updateCoords(uInt32 baseH, uInt32 imgX, uInt32 imgY, uInt32 imgW, uInt32 imgH);
|
||||
void updateCoords();
|
||||
|
||||
private:
|
||||
|
@ -66,15 +66,19 @@ class FBSurfaceTIA : public FBSurface
|
|||
const FrameBufferGL::GLpointers& myGL;
|
||||
const TIA* myTIA;
|
||||
SDL_Surface* myTexture;
|
||||
NTSCFilter myNTSCFilter;
|
||||
uInt32 myPitch;
|
||||
|
||||
GLuint myTexID[2], myVBOID;
|
||||
GLsizei myTexWidth;
|
||||
GLsizei myTexHeight;
|
||||
GLuint myBaseW, myBaseH;
|
||||
GLuint myImageX, myImageY, myImageW, myImageH;
|
||||
GLfloat myTexCoordW, myTexCoordH;
|
||||
GLfloat myCoord[32];
|
||||
|
||||
bool myScanlinesEnabled;
|
||||
GLuint myScanlineIntensityI;
|
||||
GLfloat myScanlineIntensityF;
|
||||
};
|
||||
|
||||
#endif // DISPLAY_OPENGL
|
||||
|
|
|
@ -200,19 +200,16 @@ string FrameBufferGL::about() const
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool FrameBufferGL::setVidMode(VideoMode& mode)
|
||||
{
|
||||
bool inUIMode =
|
||||
myOSystem->eventHandler().state() == EventHandler::S_LAUNCHER ||
|
||||
myOSystem->eventHandler().state() == EventHandler::S_DEBUGGER;
|
||||
bool inTIAMode =
|
||||
myOSystem->eventHandler().state() != EventHandler::S_LAUNCHER &&
|
||||
myOSystem->eventHandler().state() != EventHandler::S_DEBUGGER;
|
||||
|
||||
// Grab the initial width and height before it's updated below
|
||||
uInt32 baseWidth = mode.image_w / mode.gfxmode.zoom;
|
||||
// Grab the initial height before it's updated below
|
||||
// We need it for the creating the TIA surface
|
||||
uInt32 baseHeight = mode.image_h / mode.gfxmode.zoom;
|
||||
|
||||
// Set the zoom level
|
||||
myZoomLevel = mode.gfxmode.zoom;
|
||||
|
||||
// Aspect ratio and fullscreen stretching only applies to the TIA
|
||||
if(!inUIMode)
|
||||
if(inTIAMode)
|
||||
{
|
||||
// Aspect ratio (depends on whether NTSC or PAL is detected)
|
||||
// Not available in 'small' resolutions
|
||||
|
@ -225,18 +222,36 @@ bool FrameBufferGL::setVidMode(VideoMode& mode)
|
|||
}
|
||||
|
||||
// Fullscreen mode stretching
|
||||
if(fullScreen() && myOSystem->settings().getBool("gl_fsmax") &&
|
||||
if(fullScreen() &&
|
||||
(mode.image_w < mode.screen_w) && (mode.image_h < mode.screen_h))
|
||||
{
|
||||
float stretchFactor = 1.0;
|
||||
float scaleX = float(mode.image_w) / mode.screen_w;
|
||||
float scaleY = float(mode.image_h) / mode.screen_h;
|
||||
|
||||
if(scaleX > scaleY)
|
||||
stretchFactor = float(mode.screen_w) / mode.image_w;
|
||||
// Scale to actual or integral factors
|
||||
if(myOSystem->settings().getBool("gl_fsscale"))
|
||||
{
|
||||
// Scale to full (non-integral) available space
|
||||
if(scaleX > scaleY)
|
||||
stretchFactor = float(mode.screen_w) / mode.image_w;
|
||||
else
|
||||
stretchFactor = float(mode.screen_h) / mode.image_h;
|
||||
}
|
||||
else
|
||||
stretchFactor = float(mode.screen_h) / mode.image_h;
|
||||
|
||||
{
|
||||
// Only scale to an integral amount
|
||||
if(scaleX > scaleY)
|
||||
{
|
||||
int bw = mode.image_w / mode.gfxmode.zoom;
|
||||
stretchFactor = float(int(mode.screen_w / bw) * bw) / mode.image_w;
|
||||
}
|
||||
else
|
||||
{
|
||||
int bh = mode.image_h / mode.gfxmode.zoom;
|
||||
stretchFactor = float(int(mode.screen_h / bh) * bh) / mode.image_h;
|
||||
}
|
||||
}
|
||||
mode.image_w = (Uint16) (stretchFactor * mode.image_w);
|
||||
mode.image_h = (Uint16) (stretchFactor * mode.image_h);
|
||||
}
|
||||
|
@ -296,62 +311,34 @@ bool FrameBufferGL::setVidMode(VideoMode& mode)
|
|||
p_gl.MatrixMode(GL_MODELVIEW);
|
||||
p_gl.LoadIdentity();
|
||||
|
||||
/*
|
||||
#if 0
|
||||
cerr << "dimensions: " << (fullScreen() ? "(full)" : "") << endl
|
||||
<< " screen w = " << mode.screen_w << endl
|
||||
<< " screen h = " << mode.screen_h << endl
|
||||
<< " image x = " << mode.image_x << endl
|
||||
<< " image y = " << mode.image_y << endl
|
||||
<< " image w = " << mode.image_w << endl
|
||||
<< " image h = " << mode.image_h << endl
|
||||
<< " base w = " << baseWidth << endl
|
||||
<< " base h = " << baseHeight << endl
|
||||
<< endl;
|
||||
*/
|
||||
<< mode << endl;
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Note that the following must be done in the order given
|
||||
// Basically, all surfaces must first be free'd before being
|
||||
// recreated
|
||||
// So, we delete the TIA surface first, then reset all other surfaces
|
||||
// (which frees all surfaces and then reloads all surfaces), then
|
||||
// re-create the TIA surface (if necessary)
|
||||
// In this way, all free()'s come before all reload()'s
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
// We try to re-use the TIA surface whenever possible
|
||||
if(!inUIMode && !(myTiaSurface &&
|
||||
myTiaSurface->getWidth() == mode.image_w &&
|
||||
myTiaSurface->getHeight() == mode.image_h))
|
||||
// The framebuffer only takes responsibility for TIA surfaces
|
||||
// Other surfaces (such as the ones used for dialogs) are allocated
|
||||
// in the Dialog class
|
||||
if(inTIAMode)
|
||||
{
|
||||
delete myTiaSurface; myTiaSurface = NULL;
|
||||
// Since we have free hardware stretching, the base TIA surface is created
|
||||
// only once, and its texture coordinates changed when we want to draw a
|
||||
// smaller or larger image
|
||||
if(!myTiaSurface)
|
||||
myTiaSurface = new FBSurfaceTIA(*this);
|
||||
|
||||
myTiaSurface->updateCoords(baseHeight, mode.image_x, mode.image_y,
|
||||
mode.image_w, mode.image_h);
|
||||
|
||||
myTiaSurface->setFilter(myOSystem->settings().getString("gl_filter"));
|
||||
myTiaSurface->enableScanlines(myFilterType == kBlarggNTSC);
|
||||
myTiaSurface->setTIA(myOSystem->console().tia());
|
||||
}
|
||||
|
||||
// Any previously allocated textures currently in use by various UI items
|
||||
// need to be refreshed as well (only seems to be required for OSX)
|
||||
resetSurfaces(myTiaSurface);
|
||||
|
||||
// The framebuffer only takes responsibility for TIA surfaces
|
||||
// Other surfaces (such as the ones used for dialogs) are allocated
|
||||
// in the Dialog class
|
||||
if(!inUIMode)
|
||||
{
|
||||
// The actual TIA image is only half of that specified by baseWidth
|
||||
// The stretching can be done in hardware now that the TIA surface
|
||||
// and other UI surfaces are no longer tied together
|
||||
// Note that this may change in the future, when we add more
|
||||
// complex filters/scalers, but for now it's fine
|
||||
//
|
||||
// Also note that TV filtering is always available since we'll always
|
||||
// have access to Blargg filtering
|
||||
if(!myTiaSurface)
|
||||
myTiaSurface = new FBSurfaceTIA(*this, baseWidth>>1, baseHeight,
|
||||
mode.image_x, mode.image_y, mode.image_w, mode.image_h);
|
||||
|
||||
myTiaSurface->setFilter(myOSystem->settings().getString("gl_filter"));
|
||||
myTiaSurface->setTIA(myOSystem->console().tia());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -392,12 +379,32 @@ void FrameBufferGL::enablePhosphor(bool enable, int blend)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferGL::enableNTSC(bool enable)
|
||||
{
|
||||
if(enable)
|
||||
myFilterType = kBlarggNTSC;
|
||||
else
|
||||
myFilterType = myUsePhosphor ? kPhosphor : kNone;
|
||||
if(myTiaSurface)
|
||||
{
|
||||
myFilterType = enable ? kBlarggNTSC : myUsePhosphor ? kPhosphor : kNone;
|
||||
myTiaSurface->updateCoords();
|
||||
myTiaSurface->enableScanlines(myFilterType == kBlarggNTSC);
|
||||
myRedrawEntireFrame = true;
|
||||
}
|
||||
}
|
||||
|
||||
myRedrawEntireFrame = true;
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 FrameBufferGL::changeScanlines(int relative, int absolute)
|
||||
{
|
||||
uInt32 intensity = myTiaSurface->myScanlineIntensityI;
|
||||
if(myTiaSurface)
|
||||
{
|
||||
if(relative == 0) intensity = absolute;
|
||||
else intensity += relative;
|
||||
intensity = BSPF_max(20u, intensity);
|
||||
intensity = BSPF_min(100u, intensity);
|
||||
|
||||
myTiaSurface->myScanlineIntensityI = (GLuint)intensity;
|
||||
myTiaSurface->myScanlineIntensityF = (GLfloat)intensity / 100;
|
||||
|
||||
myRedrawEntireFrame = true;
|
||||
}
|
||||
return intensity;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -91,6 +91,20 @@ class FrameBufferGL : public FrameBuffer
|
|||
Enable/disable NTSC filtering effects.
|
||||
*/
|
||||
void enableNTSC(bool enable);
|
||||
bool ntscEnabled() const { return myFilterType == kBlarggNTSC; }
|
||||
|
||||
/**
|
||||
Change scanline intensity.
|
||||
relative = -1 means decrease current intensity by 'directin
|
||||
direction = 0 means to reload the current video mode
|
||||
direction = +1 means go to the next higher video mode
|
||||
|
||||
|
||||
@param relative If non-zero, change current intensity by
|
||||
'relative' amount, otherwise set to 'absolute'
|
||||
@return New current intensity
|
||||
*/
|
||||
uInt32 changeScanlines(int relative, int absolute = 50);
|
||||
|
||||
/**
|
||||
Set up the TIA/emulation palette for a screen of any depth > 8.
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FrameBufferSoft::FrameBufferSoft(OSystem* osystem)
|
||||
: FrameBuffer(osystem),
|
||||
myZoomLevel(2),
|
||||
myRenderType(kSoftZoom_16),
|
||||
myTiaDirty(false),
|
||||
myInUIMode(false),
|
||||
|
|
|
@ -58,11 +58,6 @@ class FrameBufferSoft : public FrameBuffer
|
|||
*/
|
||||
void enablePhosphor(bool enable, int blend);
|
||||
|
||||
/**
|
||||
Enable/disable NTSC filtering effects (not supported in software mode).
|
||||
*/
|
||||
void enableNTSC(bool enable) { }
|
||||
|
||||
/**
|
||||
This method is called to retrieve the R/G/B data from the given pixel.
|
||||
|
||||
|
@ -155,6 +150,7 @@ class FrameBufferSoft : public FrameBuffer
|
|||
string about() const;
|
||||
|
||||
private:
|
||||
int myZoomLevel;
|
||||
int myBytesPerPixel;
|
||||
int myBaseOffset;
|
||||
int myPitch;
|
||||
|
|
|
@ -17,20 +17,26 @@
|
|||
// $Id$
|
||||
//============================================================================
|
||||
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "NTSCFilter.hxx"
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.141592653589793
|
||||
#endif
|
||||
// Limits for the adjustable values.
|
||||
#define FILTER_NTSC_SHARPNESS_MIN -1.0
|
||||
#define FILTER_NTSC_SHARPNESS_MAX 1.0
|
||||
#define FILTER_NTSC_RESOLUTION_MIN -1.0
|
||||
#define FILTER_NTSC_RESOLUTION_MAX 1.0
|
||||
#define FILTER_NTSC_ARTIFACTS_MIN -1.0
|
||||
#define FILTER_NTSC_ARTIFACTS_MAX 1.0
|
||||
#define FILTER_NTSC_FRINGING_MIN -1.0
|
||||
#define FILTER_NTSC_FRINGING_MAX 1.0
|
||||
#define FILTER_NTSC_BLEED_MIN -1.0
|
||||
#define FILTER_NTSC_BLEED_MAX 1.0
|
||||
#define FILTER_NTSC_BURST_PHASE_MIN -1.0
|
||||
#define FILTER_NTSC_BURST_PHASE_MAX 1.0
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
NTSCFilter::NTSCFilter()
|
||||
: mySetup(atari_ntsc_composite),
|
||||
myCurrentModeNum(0)
|
||||
myCustomSetup(atari_ntsc_composite)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -55,258 +61,52 @@ void NTSCFilter::setTIAPalette(const uInt32* palette)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void NTSCFilter::updateFilter()
|
||||
string NTSCFilter::setPreset(Preset preset)
|
||||
{
|
||||
double yiq_table[384];
|
||||
|
||||
updateYIQTable(yiq_table, mySetup.burst_phase * M_PI);
|
||||
|
||||
/* The gamma setting is not used in atari_ntsc (palette generation is
|
||||
placed in another module), so below we do not set the gamma field
|
||||
of the mySetup structure. */
|
||||
|
||||
// According to how Atari800 defines 'external', we're using an external
|
||||
// palette (since it is generated outside of the COLOUR_NTSC routines)
|
||||
/* External palette must not be adjusted, so FILTER_NTSC
|
||||
settings are set to defaults so they don't change the source
|
||||
palette in any way. */
|
||||
mySetup.hue = 0.0;
|
||||
mySetup.saturation = 0.0;
|
||||
mySetup.contrast = 0.0;
|
||||
mySetup.brightness = 0.0;
|
||||
|
||||
mySetup.yiq_palette = yiq_table;
|
||||
atari_ntsc_init(&myFilter, &mySetup);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void NTSCFilter::restoreDefaults()
|
||||
{
|
||||
mySetup = atari_ntsc_composite;
|
||||
string msg = "disabled";
|
||||
switch(preset)
|
||||
{
|
||||
case PRESET_COMPOSITE:
|
||||
mySetup = atari_ntsc_composite;
|
||||
msg = "COMPOSITE";
|
||||
break;
|
||||
case PRESET_SVIDEO:
|
||||
mySetup = atari_ntsc_svideo;
|
||||
msg = "S-VIDEO";
|
||||
break;
|
||||
case PRESET_RGB:
|
||||
mySetup = atari_ntsc_rgb;
|
||||
msg = "RGB";
|
||||
break;
|
||||
case PRESET_BAD:
|
||||
mySetup = atari_ntsc_bad;
|
||||
msg = "BAD";
|
||||
break;
|
||||
case PRESET_CUSTOM:
|
||||
mySetup = myCustomSetup;
|
||||
msg = "CUSTOM";
|
||||
break;
|
||||
default:
|
||||
return msg;
|
||||
}
|
||||
updateFilter();
|
||||
return msg;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void NTSCFilter::setPreset(int preset)
|
||||
{
|
||||
if (preset < PRESET_CUSTOM) {
|
||||
mySetup = *presets[preset];
|
||||
updateFilter();
|
||||
|
||||
#if 0 // FIXME - what are these items for??
|
||||
/* Copy settings from the preset to NTSC setup. */
|
||||
COLOURS_NTSC_specific_setup.hue = mySetup.hue;
|
||||
COLOURS_NTSC_setup.saturation = mySetup.saturation;
|
||||
COLOURS_NTSC_setup.contrast = mySetup.contrast;
|
||||
COLOURS_NTSC_setup.brightness = mySetup.brightness;
|
||||
COLOURS_NTSC_setup.gamma = mySetup.gamma;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
int NTSCFilter::getPreset()
|
||||
{
|
||||
// FIXME - for now just return composite
|
||||
return 0;
|
||||
#if 0
|
||||
int i;
|
||||
|
||||
for (i = 0; i < PRESET_SIZE; i ++) {
|
||||
if (Util_almostequal(mySetup.sharpness, presets[i]->sharpness, 0.001) &&
|
||||
Util_almostequal(mySetup.resolution, presets[i]->resolution, 0.001) &&
|
||||
Util_almostequal(mySetup.artifacts, presets[i]->artifacts, 0.001) &&
|
||||
Util_almostequal(mySetup.fringing, presets[i]->fringing, 0.001) &&
|
||||
Util_almostequal(mySetup.bleed, presets[i]->bleed, 0.001) &&
|
||||
Util_almostequal(mySetup.burst_phase, presets[i]->burst_phase, 0.001) &&
|
||||
Util_almostequal(COLOURS_NTSC_specific_setup.hue, presets[i]->hue, 0.001) &&
|
||||
Util_almostequal(COLOURS_NTSC_setup.saturation, presets[i]->saturation, 0.001) &&
|
||||
Util_almostequal(COLOURS_NTSC_setup.contrast, presets[i]->contrast, 0.001) &&
|
||||
Util_almostequal(COLOURS_NTSC_setup.brightness, presets[i]->brightness, 0.001) &&
|
||||
Util_almostequal(COLOURS_NTSC_setup.gamma, presets[i]->gamma, 0.001))
|
||||
return i;
|
||||
}
|
||||
return PRESET_CUSTOM;
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void NTSCFilter::nextPreset()
|
||||
void NTSCFilter::updateAdjustables(const atari_ntsc_setup_t& setup)
|
||||
{
|
||||
int preset = getPreset();
|
||||
|
||||
if (preset == PRESET_CUSTOM)
|
||||
preset = PRESET_COMPOSITE;
|
||||
else
|
||||
preset = (preset + 1) % PRESET_SIZE;
|
||||
setPreset(preset);
|
||||
}
|
||||
|
||||
#if 0 // FIXME
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
int NTSCFilter::FILTER_NTSC_ReadConfig(char *option, char *ptr)
|
||||
{
|
||||
if (strcmp(option, "FILTER_NTSC_SHARPNESS") == 0)
|
||||
return Util_sscandouble(ptr, &mySetup.sharpness);
|
||||
else if (strcmp(option, "FILTER_NTSC_RESOLUTION") == 0)
|
||||
return Util_sscandouble(ptr, &mySetup.resolution);
|
||||
else if (strcmp(option, "FILTER_NTSC_ARTIFACTS") == 0)
|
||||
return Util_sscandouble(ptr, &mySetup.artifacts);
|
||||
else if (strcmp(option, "FILTER_NTSC_FRINGING") == 0)
|
||||
return Util_sscandouble(ptr, &mySetup.fringing);
|
||||
else if (strcmp(option, "FILTER_NTSC_BLEED") == 0)
|
||||
return Util_sscandouble(ptr, &mySetup.bleed);
|
||||
else if (strcmp(option, "FILTER_NTSC_BURST_PHASE") == 0)
|
||||
return Util_sscandouble(ptr, &mySetup.burst_phase);
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void NTSCFilter::FILTER_NTSC_WriteConfig(FILE *fp)
|
||||
{
|
||||
fprintf(fp, "FILTER_NTSC_SHARPNESS=%g\n", mySetup.sharpness);
|
||||
fprintf(fp, "FILTER_NTSC_RESOLUTION=%g\n", mySetup.resolution);
|
||||
fprintf(fp, "FILTER_NTSC_ARTIFACTS=%g\n", mySetup.artifacts);
|
||||
fprintf(fp, "FILTER_NTSC_FRINGING=%g\n", mySetup.fringing);
|
||||
fprintf(fp, "FILTER_NTSC_BLEED=%g\n", mySetup.bleed);
|
||||
fprintf(fp, "FILTER_NTSC_BURST_PHASE=%g\n", mySetup.burst_phase);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
int NTSCFilter::FILTER_NTSC_Initialise(int *argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
|
||||
for (i = j = 1; i < *argc; i++) {
|
||||
int i_a = (i + 1 < *argc); /* is argument available? */
|
||||
int a_m = FALSE; /* error, argument missing! */
|
||||
|
||||
if (strcmp(argv[i], "-ntsc-sharpness") == 0) {
|
||||
if (i_a)
|
||||
mySetup.sharpness = atof(argv[++i]);
|
||||
else a_m = TRUE;
|
||||
}
|
||||
else if (strcmp(argv[i], "-ntsc-resolution") == 0) {
|
||||
if (i_a)
|
||||
mySetup.resolution = atof(argv[++i]);
|
||||
else a_m = TRUE;
|
||||
}
|
||||
else if (strcmp(argv[i], "-ntsc-artifacts") == 0) {
|
||||
if (i_a)
|
||||
mySetup.artifacts = atof(argv[++i]);
|
||||
else a_m = TRUE;
|
||||
}
|
||||
else if (strcmp(argv[i], "-ntsc-fringing") == 0) {
|
||||
if (i_a)
|
||||
mySetup.fringing = atof(argv[++i]);
|
||||
else a_m = TRUE;
|
||||
}
|
||||
else if (strcmp(argv[i], "-ntsc-bleed") == 0) {
|
||||
if (i_a)
|
||||
mySetup.bleed = atof(argv[++i]);
|
||||
else a_m = TRUE;
|
||||
}
|
||||
else if (strcmp(argv[i], "-ntsc-burstphase") == 0) {
|
||||
if (i_a)
|
||||
mySetup.burst_phase = atof(argv[++i]);
|
||||
else a_m = TRUE;
|
||||
}
|
||||
else if (strcmp(argv[i], "-ntsc-filter-preset") == 0) {
|
||||
if (i_a) {
|
||||
int idx = CFG_MatchTextParameter(argv[++i], preset_cfg_strings, FILTER_NTSC_PRESET_SIZE);
|
||||
if (idx < 0) {
|
||||
Log_print("Invalid value for -ntsc-filter-preset");
|
||||
return FALSE;
|
||||
}
|
||||
setPreset(idx);
|
||||
} else a_m = TRUE;
|
||||
}
|
||||
else {
|
||||
if (strcmp(argv[i], "-help") == 0) {
|
||||
Log_print("\t-ntsc-sharpness <n> Set sharpness for NTSC filter (default %.2g)", mySetup.sharpness);
|
||||
Log_print("\t-ntsc-resolution <n> Set resolution for NTSC filter (default %.2g)", mySetup.resolution);
|
||||
Log_print("\t-ntsc-artifacts <n> Set luma artifacts ratio for NTSC filter (default %.2g)", mySetup.artifacts);
|
||||
Log_print("\t-ntsc-fringing <n> Set chroma fringing ratio for NTSC filter (default %.2g)", mySetup.fringing);
|
||||
Log_print("\t-ntsc-bleed <n> Set bleed for NTSC filter (default %.2g)", mySetup.bleed);
|
||||
Log_print("\t-ntsc-burstphase <n> Set burst phase (artifact colours) for NTSC filter (default %.2g)", mySetup.burst_phase);
|
||||
Log_print("\t-ntsc-filter-preset composite|svideo|rgb|monochrome");
|
||||
Log_print("\t Use one of predefined NTSC filter adjustments");
|
||||
}
|
||||
argv[j++] = argv[i];
|
||||
}
|
||||
|
||||
if (a_m) {
|
||||
Log_print("Missing argument for '%s'", argv[i]);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
*argc = j;
|
||||
|
||||
return TRUE;
|
||||
myAdjustables.hue = setup.hue;
|
||||
myAdjustables.saturation = setup.saturation;
|
||||
myAdjustables.contrast = setup.contrast;
|
||||
myAdjustables.brightness = setup.brightness;
|
||||
myAdjustables.sharpness = setup.sharpness;
|
||||
myAdjustables.gamma = setup.gamma;
|
||||
myAdjustables.resolution = setup.resolution;
|
||||
myAdjustables.artifacts = setup.artifacts;
|
||||
myAdjustables.fringing = setup.fringing;
|
||||
myAdjustables.bleed = setup.bleed;
|
||||
myAdjustables.burst_phase = setup.burst_phase;
|
||||
}
|
||||
#endif
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void NTSCFilter::updateYIQTable(double yiq_table[384], double start_angle)
|
||||
{
|
||||
// FIXME - const double start_saturation = 0.0; // calculated internally
|
||||
// FIXME - const double gamma = 1; // 1 - COLOURS_NTSC_setup.gamma / 2.0;
|
||||
uInt8* ext_ptr = myTIAPalette;
|
||||
int n;
|
||||
|
||||
start_angle = - ((213.0f) * M_PI / 180.0f) - start_angle;
|
||||
|
||||
for (n = 0; n < 128; n ++) {
|
||||
/* Convert RGB values from external palette to YIQ. */
|
||||
double r = (double)*ext_ptr++ / 255.0;
|
||||
double g = (double)*ext_ptr++ / 255.0;
|
||||
double b = (double)*ext_ptr++ / 255.0;
|
||||
double y = 0.299 * r + 0.587 * g + 0.114 * b;
|
||||
double i = 0.595716 * r - 0.274453 * g - 0.321263 * b;
|
||||
double q = 0.211456 * r - 0.522591 * g + 0.311135 * b;
|
||||
double s = sin(start_angle);
|
||||
double c = cos(start_angle);
|
||||
double tmp_i = i;
|
||||
i = tmp_i * c - q * s;
|
||||
q = tmp_i * s + q * c;
|
||||
#if 0
|
||||
/* Optionally adjust external palette. */
|
||||
if (COLOURS_NTSC_external.adjust) {
|
||||
y = pow(y, gamma);
|
||||
y *= COLOURS_NTSC_setup.contrast * 0.5 + 1;
|
||||
y += COLOURS_NTSC_setup.brightness * 0.5;
|
||||
if (y > 1.0)
|
||||
y = 1.0;
|
||||
else if (y < 0.0)
|
||||
y = 0.0;
|
||||
i *= start_saturation + 1;
|
||||
q *= start_saturation + 1;
|
||||
}
|
||||
#endif
|
||||
*yiq_table++ = y;
|
||||
*yiq_table++ = i;
|
||||
*yiq_table++ = q;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
atari_ntsc_setup_t const * const NTSCFilter::presets[NTSCFilter::PRESET_SIZE] = {
|
||||
&atari_ntsc_composite,
|
||||
&atari_ntsc_svideo,
|
||||
&atari_ntsc_rgb,
|
||||
&atari_ntsc_monochrome,
|
||||
&atari_ntsc_bad,
|
||||
&atari_ntsc_horrible
|
||||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
static char const * const preset_cfg_strings[NTSCFilter::PRESET_SIZE] = {
|
||||
"COMPOSITE",
|
||||
"SVIDEO",
|
||||
"RGB",
|
||||
"MONOCHROME",
|
||||
"BAD",
|
||||
"HORRIBLE"
|
||||
};
|
||||
|
|
|
@ -22,29 +22,17 @@
|
|||
|
||||
#include "bspf.hxx"
|
||||
#include "Array.hxx"
|
||||
#include "Settings.hxx"
|
||||
#include "atari_ntsc.h"
|
||||
|
||||
// Limits for the adjustable values.
|
||||
#define FILTER_NTSC_SHARPNESS_MIN -1.0
|
||||
#define FILTER_NTSC_SHARPNESS_MAX 1.0
|
||||
#define FILTER_NTSC_RESOLUTION_MIN -1.0
|
||||
#define FILTER_NTSC_RESOLUTION_MAX 1.0
|
||||
#define FILTER_NTSC_ARTIFACTS_MIN -1.0
|
||||
#define FILTER_NTSC_ARTIFACTS_MAX 1.0
|
||||
#define FILTER_NTSC_FRINGING_MIN -1.0
|
||||
#define FILTER_NTSC_FRINGING_MAX 1.0
|
||||
#define FILTER_NTSC_BLEED_MIN -1.0
|
||||
#define FILTER_NTSC_BLEED_MAX 1.0
|
||||
#define FILTER_NTSC_BURST_PHASE_MIN -1.0
|
||||
#define FILTER_NTSC_BURST_PHASE_MAX 1.0
|
||||
|
||||
/**
|
||||
This class is based on the Blargg NTSC filter code from Atari800,
|
||||
and is derived from 'filter_ntsc.(h|c)'.
|
||||
and is derived from 'filter_ntsc.(h|c)'. Original code based on
|
||||
implementation from http://www.slack.net/~ant.
|
||||
|
||||
Original code based on implementation from http://www.slack.net/~ant.
|
||||
|
||||
Atari TIA NTSC composite video to RGB emulator/blitter.
|
||||
The class is basically a thin wrapper around atari_ntsc_xxx structs
|
||||
and methods, so that the rest of the codebase isn't affected by
|
||||
updated versions of Blargg code.
|
||||
*/
|
||||
class NTSCFilter
|
||||
{
|
||||
|
@ -52,18 +40,23 @@ class NTSCFilter
|
|||
NTSCFilter();
|
||||
virtual ~NTSCFilter();
|
||||
|
||||
/* Set/get one of the available preset adjustments: Composite, S-Video, RGB,
|
||||
Monochrome. */
|
||||
enum {
|
||||
public:
|
||||
// Set one of the available preset adjustments (Composite, S-Video, RGB, etc)
|
||||
enum Preset {
|
||||
PRESET_OFF,
|
||||
PRESET_COMPOSITE,
|
||||
PRESET_SVIDEO,
|
||||
PRESET_RGB,
|
||||
PRESET_MONOCHROME,
|
||||
PRESET_BAD,
|
||||
PRESET_HORRIBLE,
|
||||
PRESET_CUSTOM,
|
||||
/* Number of "normal" (not including CUSTOM) values in enumerator */
|
||||
PRESET_SIZE = PRESET_CUSTOM
|
||||
PRESET_CUSTOM
|
||||
};
|
||||
|
||||
/* Normally used in conjunction with custom mode, contains all
|
||||
aspects currently adjustable in NTSC TV emulation. */
|
||||
struct Adjustable {
|
||||
double hue, saturation, contrast, brightness, gamma,
|
||||
sharpness, resolution, artifacts, fringing, bleed,
|
||||
burst_phase;
|
||||
};
|
||||
|
||||
public:
|
||||
|
@ -73,49 +66,58 @@ class NTSCFilter
|
|||
*/
|
||||
void setTIAPalette(const uInt32* palette);
|
||||
|
||||
/* Restores default values for NTSC-filter-specific colour controls.
|
||||
updateFilter should be called afterwards to apply changes. */
|
||||
void restoreDefaults();
|
||||
// The following are meant to be used strictly for toggling from the GUI
|
||||
string setPreset(Preset preset);
|
||||
|
||||
/* updateFilter should be called afterwards these functions to apply changes. */
|
||||
void setPreset(int preset);
|
||||
int getPreset();
|
||||
void nextPreset();
|
||||
// Reinitialises the NTSC filter (automatically called after settings
|
||||
// have changed)
|
||||
void updateFilter()
|
||||
{
|
||||
mySetup.palette = myTIAPalette;
|
||||
atari_ntsc_init(&myFilter, &mySetup);
|
||||
}
|
||||
|
||||
#if 0 // FIXME
|
||||
/* Read/write to configuration file. */
|
||||
int FILTER_NTSC_ReadConfig(char *option, char *ptr);
|
||||
void FILTER_NTSC_WriteConfig(FILE *fp);
|
||||
// Load and save NTSC-related settings
|
||||
void loadConfig(const Settings& settings);
|
||||
void saveSettings(Settings& settings) const;
|
||||
|
||||
/* NTSC filter initialisation and processing of command-line arguments. */
|
||||
int FILTER_NTSC_Initialise(int *argc, char *argv[]);
|
||||
#endif
|
||||
private:
|
||||
/* Reinitialises the an NTSC filter. Should be called after changing
|
||||
palette setup or loading/unloading an external palette. */
|
||||
void updateFilter();
|
||||
|
||||
// The following function is originally from colours_ntsc.
|
||||
/* Creates YIQ_TABLE from external palette. START_ANGLE and START_SATURATIION
|
||||
are provided as parameters, because NTSC_FILTER needs to set these values
|
||||
according to its internal setup (burst_phase etc).
|
||||
*/
|
||||
void updateYIQTable(double yiq_table[768], double start_angle);
|
||||
// Perform Blargg filtering on input buffer, place results in
|
||||
// output buffer
|
||||
void blit_5551(uInt8* src_buf, long src_row_width,
|
||||
int src_width, int src_height,
|
||||
uInt16* dest_buf, long dest_pitch)
|
||||
{
|
||||
atari_ntsc_blit_5551(&myFilter, src_buf, src_row_width,
|
||||
src_width, src_height,
|
||||
dest_buf, dest_pitch);
|
||||
}
|
||||
void blit_1555(uInt8* src_buf, long src_row_width,
|
||||
int src_width, int src_height,
|
||||
uInt16* dest_buf, long dest_pitch)
|
||||
{
|
||||
atari_ntsc_blit_1555(&myFilter, src_buf, src_row_width,
|
||||
src_width, src_height,
|
||||
dest_buf, dest_pitch);
|
||||
}
|
||||
|
||||
private:
|
||||
// Pointer to the NTSC filter structure
|
||||
// The NTSC filter structure
|
||||
atari_ntsc_t myFilter;
|
||||
|
||||
// Contains controls used to adjust the palette in the NTSC filter
|
||||
// This is the main setup object used by the underlying ntsc code
|
||||
atari_ntsc_setup_t mySetup;
|
||||
|
||||
uInt8 myTIAPalette[384]; // 128 colours by 3 components per colour
|
||||
// This setup is used only in custom mode (after it is modified,
|
||||
// it is copied to mySetup)
|
||||
atari_ntsc_setup_t myCustomSetup;
|
||||
|
||||
int myCurrentModeNum;
|
||||
Common::Array<atari_ntsc_setup_t> myModeList;
|
||||
// Contains adjustable settings for the current preset
|
||||
// (including the custom mode)
|
||||
Adjustable myAdjustables;
|
||||
|
||||
static atari_ntsc_setup_t const * const presets[PRESET_SIZE];
|
||||
static char const * const preset_cfg_strings[PRESET_SIZE];
|
||||
// 128 colours by 3 components per colour
|
||||
uInt8 myTIAPalette[128 * 3];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -31,30 +31,25 @@
|
|||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* Atari change: removal and addition of structure fields.
|
||||
Values of resolution and sharpness adjusted to make NTSC artifacts look better. */
|
||||
atari_ntsc_setup_t const atari_ntsc_composite =
|
||||
{ 0.0, 0.0, 0.0, 0.0 , -0.5, .3, -0.1 , 0.0, 0.0, 0.0, 0, 0, 0, 0. };
|
||||
atari_ntsc_setup_t const atari_ntsc_svideo =
|
||||
{ 0.0, 0.0, 0.0, 0.0 , -0.3, .3, 0.2 , -1.0, -1.0, 0.0, 0, 0, 0, 0. };
|
||||
atari_ntsc_setup_t const atari_ntsc_rgb =
|
||||
{ 0.0, 0.0, 0.0, 0.0 , -0.3, .3, 0.7 , -1.0, -1.0, -1.0, 0, 0, 0, 0. };
|
||||
atari_ntsc_setup_t const atari_ntsc_monochrome =
|
||||
{ 0.0, -1.0, 0.0, 0.0 , -0.3, .3, 0.2 , -0.2, -0.2, -1.0, 0, 0, 0, 0. };
|
||||
atari_ntsc_setup_t const atari_ntsc_bad =
|
||||
{ 0.1, -0.3, 0.3, 0.25, 0.2, 0, 0.1 , 0.5, 0.5, 0.5, 0, 0, 0, 0. };
|
||||
atari_ntsc_setup_t const atari_ntsc_horrible =
|
||||
{ -0.1, -0.5, 0.6, 0.43, 0.4, 0, 0.05, 0.7, -0.8, -0.7, 0, 0, 0, 0. };
|
||||
atari_ntsc_setup_t const atari_ntsc_composite = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.15, 0.0, 0.0, 0.0, 0, 0, 0, 0 };
|
||||
atari_ntsc_setup_t const atari_ntsc_svideo = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.45, -1.0, -1.0, 0.0, 0, 0, 0, 0 };
|
||||
atari_ntsc_setup_t const atari_ntsc_rgb = { 0.0, 0.0, 0.0, 0.0, 0.2, 0.0, 0.70, -1.0, -1.0, -1.0, 0, 0, 0, 0 };
|
||||
atari_ntsc_setup_t const atari_ntsc_bad = { 0.1, -0.3, 0.3, 0.25, 0.2, 0.0, 0.1, 0.5, 0.5, 0.5, 0, 0, 0, 0 };
|
||||
atari_ntsc_setup_t const atari_ntsc_horrible = { -0.1, -0.5, 0.6, 0.43, 0.4, 0.0, 0.05, 0.7, -0.8, -0.7, 0, 0, 0, 0 };
|
||||
|
||||
#define alignment_count 2
|
||||
#define burst_count 1
|
||||
#define rescale_in 8
|
||||
#define rescale_out 7
|
||||
|
||||
#define artifacts_mid 1.0f
|
||||
#define artifacts_mid 1.5f
|
||||
#define artifacts_max 2.5f
|
||||
#define fringing_mid 1.0f
|
||||
#define std_decoder_hue 0
|
||||
|
||||
#define gamma_size 256
|
||||
#define default_palette_contrast 1.0f
|
||||
|
||||
#include "atari_ntsc_impl.h"
|
||||
|
||||
/* 2 input pixels -> 8 composite samples */
|
||||
|
@ -81,48 +76,43 @@ void atari_ntsc_init( atari_ntsc_t* ntsc, atari_ntsc_setup_t const* setup )
|
|||
if ( !setup )
|
||||
setup = &atari_ntsc_composite;
|
||||
init( &impl, setup );
|
||||
|
||||
// Palette stores R/G/B data for 'atari_ntsc_palette_size' entries
|
||||
atari_ntsc_in_t* palette = ( atari_ntsc_in_t*) setup->palette;
|
||||
|
||||
/* Atari change: no alternating burst phases - remove code for merge_fields. */
|
||||
// Burst-phase (TODO - how is this actually used?)
|
||||
// float start_angle = - ((213.0f) * M_PI / 180.0f) - setup->burst_phase * M_PI;
|
||||
|
||||
for (int entry = 0; entry < atari_ntsc_palette_size; entry++ )
|
||||
{
|
||||
double* yiq_ptr = setup->yiq_palette + 3 * entry;
|
||||
double y = *yiq_ptr++;
|
||||
double i = *yiq_ptr++;
|
||||
double q = *yiq_ptr++;
|
||||
float r = impl.to_float [*palette++];
|
||||
float g = impl.to_float [*palette++];
|
||||
float b = impl.to_float [*palette++];
|
||||
|
||||
i *= rgb_unit;
|
||||
q *= rgb_unit;
|
||||
y *= rgb_unit;
|
||||
y += rgb_offset;
|
||||
float y, i, q = RGB_TO_YIQ( r, g, b, y, i );
|
||||
|
||||
// Generate kernel
|
||||
int ir, ig, ib = YIQ_TO_RGB( y, i, q, impl.to_rgb, int, ir, ig );
|
||||
atari_ntsc_rgb_t rgb = PACK_RGB( ir, ig, ib ); //(ib < 0x3E0 ? ib: 0x3E0)
|
||||
|
||||
/* Generate kernel */
|
||||
int r, g, b = YIQ_TO_RGB( y, i, q, impl.to_rgb, int, r, g );
|
||||
/* blue tends to overflow, so clamp it */
|
||||
atari_ntsc_rgb_t rgb = PACK_RGB( r, g, (b < 0x3E0 ? b: 0x3E0) );
|
||||
|
||||
if ( setup->palette_out )
|
||||
RGB_PALETTE_OUT( rgb, &setup->palette_out [entry * 3] );
|
||||
|
||||
if ( ntsc )
|
||||
{
|
||||
atari_ntsc_rgb_t* kernel = ntsc->table [entry];
|
||||
gen_kernel( &impl, y, i, q, kernel );
|
||||
/* Atari change: no alternating burst phases - remove code for merge_fields. */
|
||||
correct_errors( rgb, kernel );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void atari_ntsc_blit_rgb16( atari_ntsc_t const* ntsc, ATARI_NTSC_IN_T const* atari_in,
|
||||
void atari_ntsc_blit_5551( atari_ntsc_t const* ntsc, atari_ntsc_in_t const* atari_in,
|
||||
long in_row_width, int in_width, int in_height,
|
||||
void* rgb_out, long out_pitch )
|
||||
{
|
||||
int const chunk_count = (in_width - 1) / atari_ntsc_in_chunk;
|
||||
while ( in_height-- )
|
||||
{
|
||||
ATARI_NTSC_IN_T const* line_in = atari_in;
|
||||
ATARI_NTSC_BEGIN_ROW( ntsc, atari_ntsc_black, ATARI_NTSC_ADJ_IN( *(line_in[0]) ) );
|
||||
atari_ntsc_in_t const* line_in = atari_in;
|
||||
ATARI_NTSC_BEGIN_ROW( ntsc, atari_ntsc_black, ATARI_NTSC_ADJ_IN( line_in[0] ) );
|
||||
atari_ntsc_out_t* restrict line_out = (atari_ntsc_out_t*) rgb_out;
|
||||
int n;
|
||||
++line_in;
|
||||
|
@ -130,16 +120,16 @@ void atari_ntsc_blit_rgb16( atari_ntsc_t const* ntsc, ATARI_NTSC_IN_T const* ata
|
|||
for ( n = chunk_count; n; --n )
|
||||
{
|
||||
/* order of input and output pixels must not be altered */
|
||||
ATARI_NTSC_COLOR_IN( 0, ntsc, ATARI_NTSC_ADJ_IN( *(line_in [0]) ) ); //CHANGED TO DEREFERENCE POINTER
|
||||
ATARI_NTSC_RGB_OUT_RGB16( 0, line_out [0] );
|
||||
ATARI_NTSC_RGB_OUT_RGB16( 1, line_out [1] );
|
||||
ATARI_NTSC_RGB_OUT_RGB16( 2, line_out [2] );
|
||||
ATARI_NTSC_RGB_OUT_RGB16( 3, line_out [3] );
|
||||
ATARI_NTSC_COLOR_IN( 0, ntsc, ATARI_NTSC_ADJ_IN( line_in[0] ) );
|
||||
ATARI_NTSC_RGB_OUT_5551( 0, line_out [0] );
|
||||
ATARI_NTSC_RGB_OUT_5551( 1, line_out [1] );
|
||||
ATARI_NTSC_RGB_OUT_5551( 2, line_out [2] );
|
||||
ATARI_NTSC_RGB_OUT_5551( 3, line_out [3] );
|
||||
|
||||
ATARI_NTSC_COLOR_IN( 1, ntsc, ATARI_NTSC_ADJ_IN( *(line_in [1]) ) ); //CHANGED TO DEREFERENCE POINTER
|
||||
ATARI_NTSC_RGB_OUT_RGB16( 4, line_out [4] );
|
||||
ATARI_NTSC_RGB_OUT_RGB16( 5, line_out [5] );
|
||||
ATARI_NTSC_RGB_OUT_RGB16( 6, line_out [6] );
|
||||
ATARI_NTSC_COLOR_IN( 1, ntsc, ATARI_NTSC_ADJ_IN( line_in[1] ) );
|
||||
ATARI_NTSC_RGB_OUT_5551( 4, line_out [4] );
|
||||
ATARI_NTSC_RGB_OUT_5551( 5, line_out [5] );
|
||||
ATARI_NTSC_RGB_OUT_5551( 6, line_out [6] );
|
||||
|
||||
line_in += 2;
|
||||
line_out += 7;
|
||||
|
@ -147,30 +137,30 @@ void atari_ntsc_blit_rgb16( atari_ntsc_t const* ntsc, ATARI_NTSC_IN_T const* ata
|
|||
|
||||
/* finish final pixels */
|
||||
ATARI_NTSC_COLOR_IN( 0, ntsc, atari_ntsc_black );
|
||||
ATARI_NTSC_RGB_OUT_RGB16( 0, line_out [0] );
|
||||
ATARI_NTSC_RGB_OUT_RGB16( 1, line_out [1] );
|
||||
ATARI_NTSC_RGB_OUT_RGB16( 2, line_out [2] );
|
||||
ATARI_NTSC_RGB_OUT_RGB16( 3, line_out [3] );
|
||||
ATARI_NTSC_RGB_OUT_5551( 0, line_out [0] );
|
||||
ATARI_NTSC_RGB_OUT_5551( 1, line_out [1] );
|
||||
ATARI_NTSC_RGB_OUT_5551( 2, line_out [2] );
|
||||
ATARI_NTSC_RGB_OUT_5551( 3, line_out [3] );
|
||||
|
||||
ATARI_NTSC_COLOR_IN( 1, ntsc, atari_ntsc_black );
|
||||
ATARI_NTSC_RGB_OUT_RGB16( 4, line_out [4] );
|
||||
ATARI_NTSC_RGB_OUT_RGB16( 5, line_out [5] );
|
||||
ATARI_NTSC_RGB_OUT_RGB16( 6, line_out [6] );
|
||||
ATARI_NTSC_RGB_OUT_5551( 4, line_out [4] );
|
||||
ATARI_NTSC_RGB_OUT_5551( 5, line_out [5] );
|
||||
ATARI_NTSC_RGB_OUT_5551( 6, line_out [6] );
|
||||
|
||||
atari_in += in_row_width;
|
||||
rgb_out = (char*) rgb_out + out_pitch;
|
||||
}
|
||||
}
|
||||
|
||||
void atari_ntsc_blit_bgr16( atari_ntsc_t const* ntsc, ATARI_NTSC_IN_T const* atari_in,
|
||||
void atari_ntsc_blit_1555( atari_ntsc_t const* ntsc, atari_ntsc_in_t const* atari_in,
|
||||
long in_row_width, int in_width, int in_height,
|
||||
void* rgb_out, long out_pitch )
|
||||
{
|
||||
int const chunk_count = (in_width - 1) / atari_ntsc_in_chunk;
|
||||
while ( in_height-- )
|
||||
{
|
||||
ATARI_NTSC_IN_T const* line_in = atari_in;
|
||||
ATARI_NTSC_BEGIN_ROW( ntsc, atari_ntsc_black, ATARI_NTSC_ADJ_IN( *(line_in[0]) ) );
|
||||
atari_ntsc_in_t const* line_in = atari_in;
|
||||
ATARI_NTSC_BEGIN_ROW( ntsc, atari_ntsc_black, ATARI_NTSC_ADJ_IN( line_in[0] ) );
|
||||
atari_ntsc_out_t* restrict line_out = (atari_ntsc_out_t*) rgb_out;
|
||||
int n;
|
||||
++line_in;
|
||||
|
@ -178,16 +168,16 @@ void atari_ntsc_blit_bgr16( atari_ntsc_t const* ntsc, ATARI_NTSC_IN_T const* ata
|
|||
for ( n = chunk_count; n; --n )
|
||||
{
|
||||
/* order of input and output pixels must not be altered */
|
||||
ATARI_NTSC_COLOR_IN( 0, ntsc, ATARI_NTSC_ADJ_IN( *(line_in [0]) ) ); //CHANGED TO DEREFERENCE POINTER
|
||||
ATARI_NTSC_RGB_OUT_BGR16( 0, line_out [0] );
|
||||
ATARI_NTSC_RGB_OUT_BGR16( 1, line_out [1] );
|
||||
ATARI_NTSC_RGB_OUT_BGR16( 2, line_out [2] );
|
||||
ATARI_NTSC_RGB_OUT_BGR16( 3, line_out [3] );
|
||||
ATARI_NTSC_COLOR_IN( 0, ntsc, ATARI_NTSC_ADJ_IN( line_in[0] ) );
|
||||
ATARI_NTSC_RGB_OUT_1555( 0, line_out [0] );
|
||||
ATARI_NTSC_RGB_OUT_1555( 1, line_out [1] );
|
||||
ATARI_NTSC_RGB_OUT_1555( 2, line_out [2] );
|
||||
ATARI_NTSC_RGB_OUT_1555( 3, line_out [3] );
|
||||
|
||||
ATARI_NTSC_COLOR_IN( 1, ntsc, ATARI_NTSC_ADJ_IN( *(line_in [1]) ) ); //CHANGED TO DEREFERENCE POINTER
|
||||
ATARI_NTSC_RGB_OUT_BGR16( 4, line_out [4] );
|
||||
ATARI_NTSC_RGB_OUT_BGR16( 5, line_out [5] );
|
||||
ATARI_NTSC_RGB_OUT_BGR16( 6, line_out [6] );
|
||||
ATARI_NTSC_COLOR_IN( 1, ntsc, ATARI_NTSC_ADJ_IN( line_in[1] ) );
|
||||
ATARI_NTSC_RGB_OUT_1555( 4, line_out [4] );
|
||||
ATARI_NTSC_RGB_OUT_1555( 5, line_out [5] );
|
||||
ATARI_NTSC_RGB_OUT_1555( 6, line_out [6] );
|
||||
|
||||
line_in += 2;
|
||||
line_out += 7;
|
||||
|
@ -195,15 +185,15 @@ void atari_ntsc_blit_bgr16( atari_ntsc_t const* ntsc, ATARI_NTSC_IN_T const* ata
|
|||
|
||||
/* finish final pixels */
|
||||
ATARI_NTSC_COLOR_IN( 0, ntsc, atari_ntsc_black );
|
||||
ATARI_NTSC_RGB_OUT_BGR16( 0, line_out [0] );
|
||||
ATARI_NTSC_RGB_OUT_BGR16( 1, line_out [1] );
|
||||
ATARI_NTSC_RGB_OUT_BGR16( 2, line_out [2] );
|
||||
ATARI_NTSC_RGB_OUT_BGR16( 3, line_out [3] );
|
||||
ATARI_NTSC_RGB_OUT_1555( 0, line_out [0] );
|
||||
ATARI_NTSC_RGB_OUT_1555( 1, line_out [1] );
|
||||
ATARI_NTSC_RGB_OUT_1555( 2, line_out [2] );
|
||||
ATARI_NTSC_RGB_OUT_1555( 3, line_out [3] );
|
||||
|
||||
ATARI_NTSC_COLOR_IN( 1, ntsc, atari_ntsc_black );
|
||||
ATARI_NTSC_RGB_OUT_BGR16( 4, line_out [4] );
|
||||
ATARI_NTSC_RGB_OUT_BGR16( 5, line_out [5] );
|
||||
ATARI_NTSC_RGB_OUT_BGR16( 6, line_out [6] );
|
||||
ATARI_NTSC_RGB_OUT_1555( 4, line_out [4] );
|
||||
ATARI_NTSC_RGB_OUT_1555( 5, line_out [5] );
|
||||
ATARI_NTSC_RGB_OUT_1555( 6, line_out [6] );
|
||||
|
||||
atari_in += in_row_width;
|
||||
rgb_out = (char*) rgb_out + out_pitch;
|
||||
|
|
|
@ -26,9 +26,9 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Type of input pixel values. You'll probably use unsigned short
|
||||
if you enable emphasis above. */
|
||||
#define ATARI_NTSC_IN_T unsigned char *
|
||||
/* Type of input and output pixel values. */
|
||||
typedef unsigned char atari_ntsc_in_t;
|
||||
typedef unsigned short atari_ntsc_out_t;
|
||||
|
||||
/* Each raw pixel input value is passed through this. You might want to mask
|
||||
the pixel index if you use the high bits as flags, etc. */
|
||||
|
@ -61,16 +61,13 @@ typedef struct atari_ntsc_setup_t
|
|||
double burst_phase; /* Phase at which colorburst signal is turned on;
|
||||
this defines colors of artifacts.
|
||||
In radians; -1.0 = -180 degrees, 1.0 = +180 degrees */
|
||||
double* yiq_palette;
|
||||
} atari_ntsc_setup_t;
|
||||
|
||||
/* Video format presets */
|
||||
extern atari_ntsc_setup_t const atari_ntsc_monochrome;/* desaturated + artifacts */
|
||||
extern atari_ntsc_setup_t const atari_ntsc_composite; /* color bleeding + artifacts */
|
||||
extern atari_ntsc_setup_t const atari_ntsc_svideo; /* color bleeding only */
|
||||
extern atari_ntsc_setup_t const atari_ntsc_rgb; /* crisp image */
|
||||
extern atari_ntsc_setup_t const atari_ntsc_bad;
|
||||
extern atari_ntsc_setup_t const atari_ntsc_horrible; /* desaturated + artifacts */
|
||||
|
||||
enum { atari_ntsc_palette_size = 128 };
|
||||
|
||||
|
@ -81,12 +78,11 @@ void atari_ntsc_init( atari_ntsc_t* ntsc, atari_ntsc_setup_t const* setup );
|
|||
|
||||
/* Filters one or more rows of pixels. Input pixels are 8-bit Atari palette colors.
|
||||
In_row_width is the number of pixels to get to the next input row. Out_pitch
|
||||
is the number of *bytes* to get to the next output row. Output pixel format
|
||||
is set by ATARI_NTSC_OUT_DEPTH (defaults to 16-bit RGB). */
|
||||
void atari_ntsc_blit_rgb16( atari_ntsc_t const* ntsc, ATARI_NTSC_IN_T const* atari_in,
|
||||
is the number of *bytes* to get to the next output row. */
|
||||
void atari_ntsc_blit_5551( atari_ntsc_t const* ntsc, atari_ntsc_in_t const* atari_in,
|
||||
long in_row_width, int in_width, int in_height,
|
||||
void* rgb_out, long out_pitch );
|
||||
void atari_ntsc_blit_bgr16( atari_ntsc_t const* ntsc, ATARI_NTSC_IN_T const* atari_in,
|
||||
void atari_ntsc_blit_1555( atari_ntsc_t const* ntsc, atari_ntsc_in_t const* atari_in,
|
||||
long in_row_width, int in_width, int in_height,
|
||||
void* rgb_out, long out_pitch );
|
||||
|
||||
|
@ -105,9 +101,9 @@ value. */
|
|||
|
||||
/* Interface for user-defined custom blitters. */
|
||||
|
||||
enum { atari_ntsc_in_chunk = 2 }; /* number of input pixels read per chunk */
|
||||
enum { atari_ntsc_out_chunk = 7 }; /* number of output pixels generated per chunk */
|
||||
enum { atari_ntsc_black = 0 }; /* palette index for black */
|
||||
enum { atari_ntsc_in_chunk = 2 }; /* number of input pixels read per chunk */
|
||||
enum { atari_ntsc_out_chunk = 7 }; /* number of output pixels generated per chunk */
|
||||
enum { atari_ntsc_black = 0 }; /* palette index for black */
|
||||
|
||||
/* Begins outputting row and starts two pixels. First pixel will be cut off a bit.
|
||||
Use atari_ntsc_black for unused pixels. Declares variables, so must be before first
|
||||
|
@ -119,20 +115,24 @@ enum { atari_ntsc_black = 0 }; /* palette index for black */
|
|||
#define ATARI_NTSC_COLOR_IN( in_index, ntsc, color_in ) \
|
||||
ATARI_NTSC_COLOR_IN_( in_index, color_in, ATARI_NTSC_ENTRY_, ntsc )
|
||||
|
||||
/* Generates output pixel. Bits can be RGB16 or BGR16 */
|
||||
#define ATARI_NTSC_RGB_OUT_RGB16( index, rgb_out ) {\
|
||||
/* Generates output in the specified 16-bit format (x = junk bits).
|
||||
5551: RRRRRGGG GGBBBBBx (5-5-5-1 16-bit RGB)
|
||||
1555: xRRRRRGG GGGBBBBB (1-5-5-5 16-bit RGB)
|
||||
native: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (native internal format)
|
||||
*/
|
||||
#define ATARI_NTSC_RGB_OUT_5551( index, rgb_out ) {\
|
||||
atari_ntsc_rgb_t raw_ =\
|
||||
kernel0 [index ] + kernel1 [(index+10)%7+14] +\
|
||||
kernelx0 [(index+7)%14] + kernelx1 [(index+ 3)%7+14+7];\
|
||||
ATARI_NTSC_CLAMP_( raw_, 0 );\
|
||||
rgb_out = (raw_>>(13)& 0xF800)|(raw_>>(8)&0x07E0)|(raw_>>(4)&0x001F);\
|
||||
rgb_out = (raw_>>(13)& 0xF800)|(raw_>>(8)&0x07C0)|(raw_>>(3)&0x003E);\
|
||||
}
|
||||
#define ATARI_NTSC_RGB_OUT_BGR16( index, rgb_out ) {\
|
||||
#define ATARI_NTSC_RGB_OUT_1555( index, rgb_out ) {\
|
||||
atari_ntsc_rgb_t raw_ =\
|
||||
kernel0 [index ] + kernel1 [(index+10)%7+14] +\
|
||||
kernelx0 [(index+7)%14] + kernelx1 [(index+ 3)%7+14+7];\
|
||||
ATARI_NTSC_CLAMP_( raw_, 0 );\
|
||||
rgb_out = (raw_>>(13)& 0xF800)|(raw_>>(8)&0x07E0)|(raw_>>(4)&0x001F);\
|
||||
rgb_out = (raw_>>(14)& 0x7C00)|(raw_>>(9)&0x03E0)|(raw_>>(4)&0x001F);\
|
||||
}
|
||||
|
||||
/* private */
|
||||
|
|
|
@ -24,8 +24,6 @@
|
|||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "bspf.hxx"
|
||||
|
||||
/* Copyright (C) 2006-2009 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
|
@ -215,8 +213,6 @@ static void init_filters( init_t* impl, atari_ntsc_setup_t const* setup )
|
|||
#endif
|
||||
}
|
||||
|
||||
/* Atari change: more accurate values taken from
|
||||
http://en.wikipedia.org/wiki/YIQ */
|
||||
static float const default_decoder [6] =
|
||||
{ 0.9563f, 0.6210f, -0.2721f, -0.6474f, -1.1070f, 1.7046f };
|
||||
|
||||
|
@ -255,6 +251,7 @@ static void init( init_t* impl, atari_ntsc_setup_t const* setup )
|
|||
|
||||
/* setup decoder matricies */
|
||||
{
|
||||
#if 0 // FIXME - research this
|
||||
/* Atari change:
|
||||
NTSC colorburst angle in YIQ colorspace. Colorburst is at
|
||||
180 degrees in YUV - that is, a gold color. In YIQ, gold is at
|
||||
|
@ -265,6 +262,9 @@ static void init( init_t* impl, atari_ntsc_setup_t const* setup )
|
|||
http://en.wikipedia.org/wiki/YIQ) */
|
||||
static float const colorburst_angle = (213.0f) * PI / 180.0f;
|
||||
float hue = (float) setup->hue * PI + PI / 180 * ext_decoder_hue - PI * setup->burst_phase - colorburst_angle;
|
||||
#else
|
||||
float hue = (float) setup->hue * PI + PI / 180 * ext_decoder_hue;
|
||||
#endif
|
||||
float sat = (float) setup->saturation + 1;
|
||||
float const* decoder = setup->decoder_matrix;
|
||||
if ( !decoder )
|
||||
|
@ -304,14 +304,11 @@ static void init( init_t* impl, atari_ntsc_setup_t const* setup )
|
|||
|
||||
/* kernel generation */
|
||||
|
||||
/* Atari change: more accurate values taken from
|
||||
http://en.wikipedia.org/wiki/YIQ */
|
||||
#define RGB_TO_YIQ( r, g, b, y, i ) (\
|
||||
(y = (r) * 0.299f + (g) * 0.587f + (b) * 0.114f),\
|
||||
(i = (r) * 0.595716f - (g) * 0.274453f - (b) * 0.321263f),\
|
||||
((r) * 0.211456f - (g) * 0.522591f + (b) * 0.311135f)\
|
||||
)
|
||||
|
||||
#define YIQ_TO_RGB( y, i, q, to_rgb, type, r, g ) (\
|
||||
r = (type) (y + to_rgb [0] * i + to_rgb [1] * q),\
|
||||
g = (type) (y + to_rgb [2] * i + to_rgb [3] * q),\
|
||||
|
@ -355,7 +352,6 @@ static void gen_kernel( init_t* impl, float y, float i, float q, atari_ntsc_rgb_
|
|||
/* generate for each scanline burst phase */
|
||||
float const* to_rgb = impl->to_rgb;
|
||||
int burst_remain = burst_count;
|
||||
|
||||
y -= rgb_offset;
|
||||
do
|
||||
{
|
||||
|
@ -418,21 +414,19 @@ static void gen_kernel( init_t* impl, float y, float i, float q, atari_ntsc_rgb_
|
|||
|
||||
static void correct_errors( atari_ntsc_rgb_t color, atari_ntsc_rgb_t* out );
|
||||
|
||||
/* Atari change: adjust DISTRIBUTE_ERROR to 4/7 pixel ratio. */
|
||||
#if DISABLE_CORRECTION
|
||||
#define CORRECT_ERROR( a ) { out [i] += rgb_bias; }
|
||||
#define DISTRIBUTE_ERROR( a, b, c, d ) { out [i] += rgb_bias; }
|
||||
#define DISTRIBUTE_ERROR( a, b, c ) { out [i] += rgb_bias; }
|
||||
#else
|
||||
#define CORRECT_ERROR( a ) { out [a] += error; }
|
||||
#define DISTRIBUTE_ERROR( a, b, c, d ) {\
|
||||
#define DISTRIBUTE_ERROR( a, b, c ) {\
|
||||
atari_ntsc_rgb_t fourth = (error + 2 * atari_ntsc_rgb_builder) >> 2;\
|
||||
fourth &= (rgb_bias >> 1) - atari_ntsc_rgb_builder;\
|
||||
fourth -= rgb_bias >> 2;\
|
||||
out [a] += fourth;\
|
||||
out [b] += fourth;\
|
||||
out [c] += fourth;\
|
||||
out [d] += fourth;\
|
||||
out [i] += error - (fourth * 4);\
|
||||
out [i] += error - (fourth * 3);\
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -458,9 +452,3 @@ static void correct_errors( atari_ntsc_rgb_t color, atari_ntsc_rgb_t* out );
|
|||
#define restrict
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if ATARI_NTSC_OUT_DEPTH <= 16
|
||||
typedef uInt16 atari_ntsc_out_t;
|
||||
#else
|
||||
typedef uInt32 atari_ntsc_out_t;
|
||||
#endif
|
||||
|
|
|
@ -444,21 +444,50 @@ void Console::togglePhosphor()
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Console::toggleNTSC()
|
||||
void Console::toggleNTSC(NTSCFilter::Preset preset, bool show)
|
||||
{
|
||||
ostringstream buf;
|
||||
if(myOSystem->frameBuffer().type() == kDoubleBuffer)
|
||||
{
|
||||
bool state = !myOSystem->settings().getBool("ntsc_filter");
|
||||
myOSystem->frameBuffer().enableNTSC(state);
|
||||
myOSystem->settings().setBool("ntsc_filter", state);
|
||||
buf << "NTSC filtering " << (state ? "enabled" : "disabled");
|
||||
myOSystem->frameBuffer().showMessage(buf.str());
|
||||
if(preset == NTSCFilter::PRESET_OFF)
|
||||
{
|
||||
myOSystem->frameBuffer().enableNTSC(false);
|
||||
buf << "TV filtering disabled";
|
||||
}
|
||||
else
|
||||
{
|
||||
myOSystem->frameBuffer().enableNTSC(true);
|
||||
const string& mode = myOSystem->frameBuffer().ntsc().setPreset(preset);
|
||||
buf << "TV filtering (" << mode << " mode)";
|
||||
}
|
||||
myOSystem->settings().setInt("tv_filter", (int)preset);
|
||||
if(show) myOSystem->frameBuffer().showMessage(buf.str());
|
||||
}
|
||||
else
|
||||
buf << "NTSC filtering not available";
|
||||
buf << "TV filtering not available in software mode";
|
||||
|
||||
myOSystem->frameBuffer().showMessage(buf.str());
|
||||
if(show) myOSystem->frameBuffer().showMessage(buf.str());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Console::changeScanlines(int amount, bool show)
|
||||
{
|
||||
ostringstream buf;
|
||||
if(myOSystem->frameBuffer().type() == kDoubleBuffer)
|
||||
{
|
||||
if(myOSystem->frameBuffer().ntscEnabled())
|
||||
{
|
||||
uInt32 intensity = myOSystem->frameBuffer().changeScanlines(amount);
|
||||
buf << "Scanline intensity at " << intensity << "%";
|
||||
myOSystem->settings().setInt("tv_scanlines", intensity);
|
||||
}
|
||||
else
|
||||
buf << "Scanlines only available in TV filtering mode";
|
||||
}
|
||||
else
|
||||
buf << "Scanlines not available in software mode";
|
||||
|
||||
if(show) myOSystem->frameBuffer().showMessage(buf.str());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -488,7 +517,8 @@ FBInitStatus Console::initializeVideo(bool full)
|
|||
bool enable = myProperties.get(Display_Phosphor) == "YES";
|
||||
int blend = atoi(myProperties.get(Display_PPBlend).c_str());
|
||||
myOSystem->frameBuffer().enablePhosphor(enable, blend);
|
||||
myOSystem->frameBuffer().enableNTSC(myOSystem->settings().getBool("ntsc_filter"));
|
||||
myOSystem->frameBuffer().changeScanlines(0, myOSystem->settings().getInt("tv_scanlines"));
|
||||
toggleNTSC((NTSCFilter::Preset)myOSystem->settings().getInt("tv_filter"));
|
||||
setPalette(myOSystem->settings().getString("palette"));
|
||||
|
||||
// Set the correct framerate based on the format of the ROM
|
||||
|
|
|
@ -35,6 +35,7 @@ class CompuMate;
|
|||
#include "TIATables.hxx"
|
||||
#include "FrameBuffer.hxx"
|
||||
#include "Serializable.hxx"
|
||||
#include "NTSCFilter.hxx"
|
||||
|
||||
/**
|
||||
Contains detailed info about a console.
|
||||
|
@ -202,9 +203,14 @@ class Console : public Serializable
|
|||
void togglePhosphor();
|
||||
|
||||
/**
|
||||
Toggles NTSC filtering effects.
|
||||
Toggles NTSC filtering effects to use the given preset.
|
||||
*/
|
||||
void toggleNTSC();
|
||||
void toggleNTSC(NTSCFilter::Preset preset, bool show = false);
|
||||
|
||||
/**
|
||||
Increase/decrease current scanline intensity by given amount.
|
||||
*/
|
||||
void changeScanlines(int amount, bool show = false);
|
||||
|
||||
/**
|
||||
Toggles the PAL color-loss effect.
|
||||
|
|
|
@ -378,8 +378,35 @@ void EventHandler::poll(uInt64 time)
|
|||
myOSystem->console().changeYStart(-1);
|
||||
break;
|
||||
|
||||
case KBDK_f: // Alt-f toggles NTSC filtering
|
||||
myOSystem->console().toggleNTSC();
|
||||
case KBDK_1: // Alt-1 turns off NTSC filtering
|
||||
myOSystem->console().toggleNTSC(NTSCFilter::PRESET_OFF, true);
|
||||
break;
|
||||
|
||||
case KBDK_2: // Alt-2 turns on 'composite' NTSC filtering
|
||||
myOSystem->console().toggleNTSC(NTSCFilter::PRESET_COMPOSITE, true);
|
||||
break;
|
||||
|
||||
case KBDK_3: // Alt-3 turns on 'svideo' NTSC filtering
|
||||
myOSystem->console().toggleNTSC(NTSCFilter::PRESET_SVIDEO, true);
|
||||
break;
|
||||
|
||||
case KBDK_4: // Alt-4 turns on 'rgb' NTSC filtering
|
||||
myOSystem->console().toggleNTSC(NTSCFilter::PRESET_RGB, true);
|
||||
break;
|
||||
|
||||
case KBDK_5: // Alt-5 turns on 'bad' NTSC filtering
|
||||
myOSystem->console().toggleNTSC(NTSCFilter::PRESET_BAD, true);
|
||||
break;
|
||||
|
||||
case KBDK_6: // Alt-6 turns on 'custom' NTSC filtering
|
||||
myOSystem->console().toggleNTSC(NTSCFilter::PRESET_CUSTOM, true);
|
||||
break;
|
||||
|
||||
case KBDK_7: // Alt-7 changes scanline intensity for NTSC filtering
|
||||
if(mod & KMOD_SHIFT)
|
||||
myOSystem->console().changeScanlines(-5, true);
|
||||
else
|
||||
myOSystem->console().changeScanlines(+5, true);
|
||||
break;
|
||||
|
||||
case KBDK_z:
|
||||
|
@ -440,7 +467,9 @@ void EventHandler::poll(uInt64 time)
|
|||
break;
|
||||
|
||||
case KBDK_p: // Alt-p toggles phosphor effect
|
||||
myOSystem->console().togglePhosphor();
|
||||
// Currently, phosphor mode cannot be enabled with NTSC filtering
|
||||
if(!myOSystem->frameBuffer().ntscEnabled())
|
||||
myOSystem->console().togglePhosphor();
|
||||
break;
|
||||
|
||||
case KBDK_l:
|
||||
|
|
|
@ -36,6 +36,7 @@ namespace GUI {
|
|||
#include "EventHandler.hxx"
|
||||
#include "Rect.hxx"
|
||||
#include "StringList.hxx"
|
||||
#include "NTSCFilter.hxx"
|
||||
#include "bspf.hxx"
|
||||
|
||||
// Different types of framebuffer derived objects
|
||||
|
@ -285,12 +286,37 @@ class FrameBuffer
|
|||
void stateChanged(EventHandler::State state);
|
||||
|
||||
/**
|
||||
Get the zoom level.
|
||||
Get the NTSCFilter object associated with the framebuffer
|
||||
*/
|
||||
uInt32 getZoomLevel() { return myZoomLevel; }
|
||||
NTSCFilter& ntsc() { return myNTSCFilter; }
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// The following methods are system-specific and must be implemented
|
||||
// The following methods are system-specific and *may* be implemented
|
||||
// in derived classes.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
public:
|
||||
/**
|
||||
Enable/disable NTSC filtering effects.
|
||||
*/
|
||||
virtual void enableNTSC(bool enable) { }
|
||||
virtual bool ntscEnabled() const { return false; }
|
||||
|
||||
/**
|
||||
Change scanline intensity.
|
||||
relative = -1 means decrease current intensity by 'directin
|
||||
direction = 0 means to reload the current video mode
|
||||
direction = +1 means go to the next higher video mode
|
||||
|
||||
|
||||
@param relative If non-zero, change current intensity by
|
||||
'relative' amount, otherwise set to 'absolute'
|
||||
@return New current intensity
|
||||
*/
|
||||
virtual uInt32 changeScanlines(int relative, int absolute = 50) { return absolute; }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// The following methods are system-specific and *must* be implemented
|
||||
// in derived classes.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
public:
|
||||
|
@ -299,11 +325,6 @@ class FrameBuffer
|
|||
*/
|
||||
virtual void enablePhosphor(bool enable, int blend) = 0;
|
||||
|
||||
/**
|
||||
Enable/disable NTSC filtering effects.
|
||||
*/
|
||||
virtual void enableNTSC(bool enable) = 0;
|
||||
|
||||
/**
|
||||
This method is called to retrieve the R/G/B data from the given pixel.
|
||||
|
||||
|
@ -374,6 +395,14 @@ class FrameBuffer
|
|||
uInt32 image_x, image_y, image_w, image_h;
|
||||
uInt32 screen_w, screen_h;
|
||||
GraphicsMode gfxmode;
|
||||
|
||||
friend ostream& operator<<(ostream& os, const VideoMode& vm)
|
||||
{
|
||||
os << "image_x=" << vm.image_x << " image_y=" << vm.image_y
|
||||
<< " image_w=" << vm.image_w << " image_h=" << vm.image_h << endl
|
||||
<< "screen_w=" << vm.screen_w << " screen_h=" << vm.screen_h;
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -451,6 +480,9 @@ class FrameBuffer
|
|||
// Indicates if the entire frame need to redrawn
|
||||
bool myRedrawEntireFrame;
|
||||
|
||||
// NTSC object to use in TIA rendering mode
|
||||
NTSCFilter myNTSCFilter;
|
||||
|
||||
// Use phosphor effect (aka no flicker on 30Hz screens)
|
||||
bool myUsePhosphor;
|
||||
|
||||
|
@ -470,9 +502,6 @@ class FrameBuffer
|
|||
// Names of the TIA filters that can be used for this framebuffer
|
||||
StringMap myTIAFilters;
|
||||
|
||||
// Holds the zoom level being used
|
||||
uInt32 myZoomLevel;
|
||||
|
||||
private:
|
||||
/**
|
||||
Grabs or ungrabs the mouse based on the given boolean value.
|
||||
|
|
|
@ -43,7 +43,7 @@ Settings::Settings(OSystem* osystem)
|
|||
setInternal("gl_filter", "nearest");
|
||||
setInternal("gl_aspectn", "90");
|
||||
setInternal("gl_aspectp", "100");
|
||||
setInternal("gl_fsmax", "true");
|
||||
setInternal("gl_fsscale", "false");
|
||||
setInternal("gl_lib", "libGL.so");
|
||||
setInternal("gl_vsync", "true");
|
||||
setInternal("gl_vbo", "true");
|
||||
|
@ -59,8 +59,9 @@ Settings::Settings(OSystem* osystem)
|
|||
setInternal("timing", "sleep");
|
||||
setInternal("uimessages", "true");
|
||||
|
||||
// NTSC filtering options
|
||||
setInternal("ntsc_filter", "false");
|
||||
// TV filtering options
|
||||
setInternal("tv_filter", "0");
|
||||
setInternal("tv_scanlines", "50");
|
||||
|
||||
// Sound options
|
||||
setInternal("sound", "true");
|
||||
|
@ -265,6 +266,10 @@ void Settings::validate()
|
|||
if(i < 80 || i > 120) setInternal("gl_aspectn", "100");
|
||||
i = getInt("gl_aspectp");
|
||||
if(i < 80 || i > 120) setInternal("gl_aspectp", "100");
|
||||
|
||||
i = getInt("tv_filter");
|
||||
if(i < 0 || i > 5) setInternal("tv_filter", "0");
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef SOUND_SUPPORT
|
||||
|
@ -335,11 +340,12 @@ void Settings::usage()
|
|||
<< " linear Blurred scaling (GL_LINEAR)\n"
|
||||
<< " -gl_aspectn <number> Scale the TIA width by the given percentage in NTSC mode\n"
|
||||
<< " -gl_aspectp <number> Scale the TIA width by the given percentage in PAL mode\n"
|
||||
<< " -gl_fsmax <1|0> Stretch GL image in fullscreen emulation mode\n"
|
||||
<< " -gl_fsscale <1|0> Stretch GL image in fullscreen emulation mode to max/integer scale\n"
|
||||
<< " -gl_vsync <1|0> Enable 'synchronize to vertical blank interrupt'\n"
|
||||
<< " -gl_vbo <1|0> Enable 'vertex buffer objects'\n"
|
||||
<< endl
|
||||
<< " -ntsc_filter <1|0> Enable Blargg NTSC filtering effects\n"
|
||||
<< " -tv_filter <0-5> Set TV effects off (0) or to specified mode (1-5)\n"
|
||||
<< " -tv_scanlines <20-100> Set scanline intensity to percentage\n"
|
||||
<< endl
|
||||
#endif
|
||||
<< " -tia_filter <filter> Use the specified filter in emulation mode\n"
|
||||
|
|
|
@ -346,7 +346,7 @@ void VideoDialog::loadConfig()
|
|||
myColorLossCheckbox->setState(instance().settings().getBool("colorloss"));
|
||||
|
||||
// GL stretch setting (GL mode only)
|
||||
myGLStretchCheckbox->setState(instance().settings().getBool("gl_fsmax"));
|
||||
myGLStretchCheckbox->setState(instance().settings().getBool("gl_fsscale"));
|
||||
myGLStretchCheckbox->setEnabled(gl);
|
||||
|
||||
// Use sync to vertical blank (GL mode only)
|
||||
|
@ -409,7 +409,7 @@ void VideoDialog::saveConfig()
|
|||
instance().console().toggleColorLoss(myColorLossCheckbox->getState());
|
||||
|
||||
// GL stretch setting
|
||||
instance().settings().setBool("gl_fsmax", myGLStretchCheckbox->getState());
|
||||
instance().settings().setBool("gl_fsscale", myGLStretchCheckbox->getState());
|
||||
|
||||
// Use sync to vertical blank (GL mode only)
|
||||
instance().settings().setBool("gl_vsync", myUseVSyncCheckbox->getState());
|
||||
|
|
Loading…
Reference in New Issue