From e3fa8da1f966bdb08f6e35424a08462cc903e6cb Mon Sep 17 00:00:00 2001 From: stephena Date: Sun, 6 May 2012 17:45:48 +0000 Subject: [PATCH] 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 --- src/common/FBSurfaceTIA.cxx | 74 +++--- src/common/FBSurfaceTIA.hxx | 12 +- src/common/FrameBufferGL.cxx | 139 ++++++----- src/common/FrameBufferGL.hxx | 14 ++ src/common/FrameBufferSoft.cxx | 1 + src/common/FrameBufferSoft.hxx | 6 +- src/common/tv_filters/NTSCFilter.cxx | 308 +++++------------------- src/common/tv_filters/NTSCFilter.hxx | 116 ++++----- src/common/tv_filters/atari_ntsc.c | 132 +++++----- src/common/tv_filters/atari_ntsc.h | 36 +-- src/common/tv_filters/atari_ntsc_impl.h | 26 +- src/emucore/Console.cxx | 48 +++- src/emucore/Console.hxx | 10 +- src/emucore/EventHandler.cxx | 35 ++- src/emucore/FrameBuffer.hxx | 51 +++- src/emucore/Settings.cxx | 16 +- src/gui/VideoDialog.cxx | 4 +- 17 files changed, 473 insertions(+), 555 deletions(-) diff --git a/src/common/FBSurfaceTIA.cxx b/src/common/FBSurfaceTIA.cxx index afd822dbe..97e156900 100644 --- a/src/common/FBSurfaceTIA.cxx +++ b/src/common/FBSurfaceTIA.cxx @@ -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 diff --git a/src/common/FBSurfaceTIA.hxx b/src/common/FBSurfaceTIA.hxx index 0a8112de9..9a7337405 100644 --- a/src/common/FBSurfaceTIA.hxx +++ b/src/common/FBSurfaceTIA.hxx @@ -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 diff --git a/src/common/FrameBufferGL.cxx b/src/common/FrameBufferGL.cxx index 910e7fa04..81eabc1b0 100644 --- a/src/common/FrameBufferGL.cxx +++ b/src/common/FrameBufferGL.cxx @@ -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; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/FrameBufferGL.hxx b/src/common/FrameBufferGL.hxx index 30088d641..0818e6c59 100644 --- a/src/common/FrameBufferGL.hxx +++ b/src/common/FrameBufferGL.hxx @@ -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. diff --git a/src/common/FrameBufferSoft.cxx b/src/common/FrameBufferSoft.cxx index 98cc185a8..aeddfc29d 100644 --- a/src/common/FrameBufferSoft.cxx +++ b/src/common/FrameBufferSoft.cxx @@ -34,6 +34,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FrameBufferSoft::FrameBufferSoft(OSystem* osystem) : FrameBuffer(osystem), + myZoomLevel(2), myRenderType(kSoftZoom_16), myTiaDirty(false), myInUIMode(false), diff --git a/src/common/FrameBufferSoft.hxx b/src/common/FrameBufferSoft.hxx index 8b6d72cb3..e01e7d411 100644 --- a/src/common/FrameBufferSoft.hxx +++ b/src/common/FrameBufferSoft.hxx @@ -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; diff --git a/src/common/tv_filters/NTSCFilter.cxx b/src/common/tv_filters/NTSCFilter.cxx index 306599d13..94e096458 100644 --- a/src/common/tv_filters/NTSCFilter.cxx +++ b/src/common/tv_filters/NTSCFilter.cxx @@ -17,20 +17,26 @@ // $Id$ //============================================================================ -#include -#include -#include - #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 Set sharpness for NTSC filter (default %.2g)", mySetup.sharpness); - Log_print("\t-ntsc-resolution Set resolution for NTSC filter (default %.2g)", mySetup.resolution); - Log_print("\t-ntsc-artifacts Set luma artifacts ratio for NTSC filter (default %.2g)", mySetup.artifacts); - Log_print("\t-ntsc-fringing Set chroma fringing ratio for NTSC filter (default %.2g)", mySetup.fringing); - Log_print("\t-ntsc-bleed Set bleed for NTSC filter (default %.2g)", mySetup.bleed); - Log_print("\t-ntsc-burstphase 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" -}; diff --git a/src/common/tv_filters/NTSCFilter.hxx b/src/common/tv_filters/NTSCFilter.hxx index 6c0068fa6..dbaf7c9ab 100644 --- a/src/common/tv_filters/NTSCFilter.hxx +++ b/src/common/tv_filters/NTSCFilter.hxx @@ -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 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 diff --git a/src/common/tv_filters/atari_ntsc.c b/src/common/tv_filters/atari_ntsc.c index 5e240e63a..97956dd16 100644 --- a/src/common/tv_filters/atari_ntsc.c +++ b/src/common/tv_filters/atari_ntsc.c @@ -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; diff --git a/src/common/tv_filters/atari_ntsc.h b/src/common/tv_filters/atari_ntsc.h index 2abd6b037..800f11bdb 100644 --- a/src/common/tv_filters/atari_ntsc.h +++ b/src/common/tv_filters/atari_ntsc.h @@ -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 */ diff --git a/src/common/tv_filters/atari_ntsc_impl.h b/src/common/tv_filters/atari_ntsc_impl.h index b0e5d7d31..5cfb9a6db 100644 --- a/src/common/tv_filters/atari_ntsc_impl.h +++ b/src/common/tv_filters/atari_ntsc_impl.h @@ -24,8 +24,6 @@ #include #include -#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 diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 59e656929..ec4122f38 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -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 diff --git a/src/emucore/Console.hxx b/src/emucore/Console.hxx index 36e79d358..aad04929f 100644 --- a/src/emucore/Console.hxx +++ b/src/emucore/Console.hxx @@ -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. diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index ed89f64b3..c622fcb8c 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -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: diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index c35c94bbc..c503b5df1 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -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. diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index d4809bb58..0899946c7 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -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 Scale the TIA width by the given percentage in NTSC mode\n" << " -gl_aspectp 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 Use the specified filter in emulation mode\n" diff --git a/src/gui/VideoDialog.cxx b/src/gui/VideoDialog.cxx index 2aebd5271..9d4994cd9 100644 --- a/src/gui/VideoDialog.cxx +++ b/src/gui/VideoDialog.cxx @@ -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());