diff --git a/src/common/EventHandlerSDL2.cxx b/src/common/EventHandlerSDL2.cxx index ca1655c34..8fd7a388b 100644 --- a/src/common/EventHandlerSDL2.cxx +++ b/src/common/EventHandlerSDL2.cxx @@ -21,7 +21,7 @@ #include "EventHandlerSDL2.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -EventHandlerSDL2::EventHandlerSDL2(OSystem* osystem) +EventHandlerSDL2::EventHandlerSDL2(OSystem& osystem) : EventHandler(osystem) { } diff --git a/src/common/EventHandlerSDL2.hxx b/src/common/EventHandlerSDL2.hxx index 157bad265..4e2f4d672 100644 --- a/src/common/EventHandlerSDL2.hxx +++ b/src/common/EventHandlerSDL2.hxx @@ -37,7 +37,7 @@ class EventHandlerSDL2 : public EventHandler /** Create a new SDL2 event handler object */ - EventHandlerSDL2(OSystem* osystem); + EventHandlerSDL2(OSystem& osystem); /** Destructor diff --git a/src/common/FBSurfaceSDL2.cxx b/src/common/FBSurfaceSDL2.cxx index 77b5ef0ef..0725c9a49 100644 --- a/src/common/FBSurfaceSDL2.cxx +++ b/src/common/FBSurfaceSDL2.cxx @@ -21,8 +21,7 @@ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBSurfaceSDL2::FBSurfaceSDL2(FrameBufferSDL2& buffer, uInt32 width, uInt32 height) - : FBSurface(buffer.myDefPalette), - myFB(buffer), + : myFB(buffer), mySurface(NULL), myTexture(NULL), mySurfaceIsDirty(true), @@ -111,19 +110,6 @@ void FBSurfaceSDL2::setStaticContents(const uInt32* pixels, uInt32 pitch) reload(); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FBSurfaceSDL2::setInterpolationAndBlending( - bool smoothScale, bool useBlend, uInt32 blendAlpha) -{ - myInterpolate = smoothScale; - myBlendEnabled = useBlend; - myBlendAlpha = uInt8(blendAlpha * 2.55); - - // Re-create the texture with the new settings - free(); - reload(); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 FBSurfaceSDL2::width() const { @@ -236,3 +222,18 @@ void FBSurfaceSDL2::reload() SDL_SetTextureAlphaMod(myTexture, myBlendAlpha); } } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBSurfaceSDL2::applyAttributes(bool immediate) +{ + myInterpolate = myAttributes.smoothing; + myBlendEnabled = myAttributes.blending; + myBlendAlpha = uInt8(myAttributes.blendalpha * 2.55); + + if(immediate) + { + // Re-create the texture with the new settings + free(); + reload(); + } +} diff --git a/src/common/FBSurfaceSDL2.hxx b/src/common/FBSurfaceSDL2.hxx index 56a4d2120..40f0a14f0 100644 --- a/src/common/FBSurfaceSDL2.hxx +++ b/src/common/FBSurfaceSDL2.hxx @@ -33,7 +33,6 @@ class FBSurfaceSDL2 : public FBSurface { public: FBSurfaceSDL2(FrameBufferSDL2& buffer, uInt32 width, uInt32 height); - virtual ~FBSurfaceSDL2(); // Most of the surface drawing primitives are implemented in FBSurface; @@ -44,8 +43,6 @@ class FBSurfaceSDL2 : public FBSurface void addDirtyRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h); void setStaticContents(const uInt32* pixels, uInt32 pitch); - void setInterpolationAndBlending(bool smoothScale, bool useBlend, - uInt32 blendAlpha); uInt32 width() const; uInt32 height() const; @@ -63,6 +60,9 @@ class FBSurfaceSDL2 : public FBSurface void free(); void reload(); + protected: + void applyAttributes(bool immediate); + private: FrameBufferSDL2& myFB; diff --git a/src/common/FBSurfaceTIA.cxx b/src/common/FBSurfaceTIA.cxx deleted file mode 100644 index 1b59eb89e..000000000 --- a/src/common/FBSurfaceTIA.cxx +++ /dev/null @@ -1,237 +0,0 @@ -//============================================================================ -// -// SSSS tt lll lll -// SS SS tt ll ll -// SS tttttt eeee ll ll aaaa -// SSSS tt ee ee ll ll aa -// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" -// SS SS tt ee ll ll aa aa -// SSSS ttt eeeee llll llll aaaaa -// -// Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony -// and the Stella Team -// -// See the file "License.txt" for information on usage and redistribution of -// this file, and for a DISCLAIMER OF ALL WARRANTIES. -// -// $Id$ -//============================================================================ - -#include - -#include "NTSCFilter.hxx" -#include "TIA.hxx" - -#include "FBSurfaceTIA.hxx" - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -FBSurfaceTIA::FBSurfaceTIA(FrameBufferSDL2& buffer) - : FBSurface(buffer.myDefPalette), - myFB(buffer), - mySurface(NULL), - myTexture(NULL), - myScanlines(NULL), - myScanlinesEnabled(false), - myScanlineIntensity(50) -{ - // Texture width is set to contain all possible sizes for a TIA image, - // including Blargg filtering - int width = ATARI_NTSC_OUT_WIDTH(160); - int height = 320; - - // Create a surface in the same format as the parent GL class - const SDL_PixelFormat* pf = myFB.myPixelFormat; - - mySurface = SDL_CreateRGBSurface(0, width, height*2, - pf->BitsPerPixel, pf->Rmask, pf->Gmask, pf->Bmask, pf->Amask); - - mySrcR.x = mySrcR.y = myDstR.x = myDstR.y = myScanR.x = myScanR.y = 0; - mySrcR.w = myDstR.w = width; - mySrcR.h = myDstR.h = height; - myScanR.w = 1; myScanR.h = 0; - - myPitch = mySurface->pitch / pf->BytesPerPixel; - - // Generate scanline data - myScanData = new uInt32[mySurface->h]; - for(int i = 0; i < mySurface->h; i+=2) - { - myScanData[i] = 0x00000000; - myScanData[i+1] = 0xff000000; - } - - // To generate textures - reload(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -FBSurfaceTIA::~FBSurfaceTIA() -{ - if(mySurface) - SDL_FreeSurface(mySurface); - - free(); - delete[] myScanData; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FBSurfaceTIA::getPos(uInt32& x, uInt32& y) const -{ - x = mySrcR.x; - y = mySrcR.y; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FBSurfaceTIA::translateCoords(Int32& x, Int32& y) const -{ - x = mySrcR.x; - y = mySrcR.y; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FBSurfaceTIA::render() -{ - // Copy the mediasource framebuffer to the RGB texture - // In hardware rendering mode, it's faster to just assume that the screen - // is dirty and always do an update - - uInt8* currentFrame = myTIA->currentFrameBuffer(); - uInt8* previousFrame = myTIA->previousFrameBuffer(); - uInt32 width = myTIA->width(); - uInt32 height = myTIA->height(); - uInt32* buffer = (uInt32*) mySurface->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 FrameBufferSDL2::kNormal: - { - uInt32 bufofsY = 0; - uInt32 screenofsY = 0; - for(uInt32 y = 0; y < height; ++y) - { - uInt32 pos = screenofsY; - for(uInt32 x = 0; x < width; ++x) - buffer[pos++] = (uInt32) myFB.myDefPalette[currentFrame[bufofsY + x]]; - - bufofsY += width; - screenofsY += myPitch; - } - break; - } - case FrameBufferSDL2::kPhosphor: - { - uInt32 bufofsY = 0; - uInt32 screenofsY = 0; - for(uInt32 y = 0; y < height; ++y) - { - uInt32 pos = screenofsY; - for(uInt32 x = 0; x < width; ++x) - { - const uInt32 bufofs = bufofsY + x; - buffer[pos++] = (uInt32) - myFB.myAvgPalette[currentFrame[bufofs]][previousFrame[bufofs]]; - } - bufofsY += width; - screenofsY += myPitch; - } - break; - } - case FrameBufferSDL2::kBlarggNormal: - { - myFB.myNTSCFilter.blit_single(currentFrame, width, height, - buffer, mySurface->pitch); - break; - } - case FrameBufferSDL2::kBlarggPhosphor: - { - myFB.myNTSCFilter.blit_double(currentFrame, previousFrame, width, height, - buffer, mySurface->pitch); - break; - } - } - - // Draw TIA image - SDL_UpdateTexture(myTexture, &mySrcR, mySurface->pixels, mySurface->pitch); - SDL_RenderCopy(myFB.myRenderer, myTexture, &mySrcR, &myDstR); - - // Draw overlaying scanlines - if(myScanlinesEnabled) - SDL_RenderCopy(myFB.myRenderer, myScanlines, &myScanR, &myDstR); - - // Let postFrameUpdate() know that a change has been made - myFB.myDirtyFlag = true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FBSurfaceTIA::invalidate() -{ - SDL_FillRect(mySurface, NULL, 0); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FBSurfaceTIA::free() -{ - if(myTexture) - { - SDL_DestroyTexture(myTexture); - myTexture = NULL; - } - if(myScanlines) - { - SDL_DestroyTexture(myScanlines); - myScanlines = NULL; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FBSurfaceTIA::reload() -{ - // Re-create texture; the underlying SDL_Surface is fine as-is - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, myTexFilter[0] ? "1" : "0"); - myTexture = SDL_CreateTexture(myFB.myRenderer, - myFB.myPixelFormat->format, SDL_TEXTUREACCESS_STREAMING, - mySurface->w, mySurface->h); - - // Re-create scanline texture (contents don't change) - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, myTexFilter[1] ? "1" : "0"); - myScanlines = SDL_CreateTexture(myFB.myRenderer, - myFB.myPixelFormat->format, SDL_TEXTUREACCESS_STATIC, - 1, mySurface->h); - SDL_SetTextureBlendMode(myScanlines, SDL_BLENDMODE_BLEND); - SDL_SetTextureAlphaMod(myScanlines, Uint8(myScanlineIntensity*2.55)); - SDL_UpdateTexture(myScanlines, &myScanR, myScanData, 4); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FBSurfaceTIA::updateCoords(uInt32 baseH, - uInt32 imgX, uInt32 imgY, uInt32 imgW, uInt32 imgH) -{ - mySrcR.h = baseH; - myDstR.w = imgW; - myDstR.h = imgH; - - // Scanline repeating is sensitive to non-integral vertical resolution, - // so rounding is performed to eliminate it - // This won't be 100% accurate, but non-integral scaling isn't 100% - // accurate anyway - myScanR.w = 1; - myScanR.h = int(2 * float(imgH) / floor(((float)imgH / baseH) + 0.5)); - - 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 - mySrcR.w = myFB.ntscEnabled() ? ATARI_NTSC_OUT_WIDTH(160) : 160; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FBSurfaceTIA::setTIAPalette(const uInt32* palette) -{ - myFB.myNTSCFilter.setTIAPalette(myFB, palette); -} diff --git a/src/common/FBSurfaceTIA.hxx b/src/common/FBSurfaceTIA.hxx deleted file mode 100644 index 1b9d1509e..000000000 --- a/src/common/FBSurfaceTIA.hxx +++ /dev/null @@ -1,104 +0,0 @@ -//============================================================================ -// -// SSSS tt lll lll -// SS SS tt ll ll -// SS tttttt eeee ll ll aaaa -// SSSS tt ee ee ll ll aa -// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" -// SS SS tt ee ll ll aa aa -// SSSS ttt eeeee llll llll aaaaa -// -// Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony -// and the Stella Team -// -// See the file "License.txt" for information on usage and redistribution of -// this file, and for a DISCLAIMER OF ALL WARRANTIES. -// -// $Id$ -//============================================================================ - -#ifndef FB_SURFACE_TIA_HXX -#define FB_SURFACE_TIA_HXX - -#include "bspf.hxx" -#include "FrameBuffer.hxx" -#include "FrameBufferSDL2.hxx" - -/** - A surface suitable for SDL Render2D API and rendering from a TIA source. - It doesn't implement most of the drawing primitives, since it's concerned - with TIA images only. This class extends FrameBuffer::FBSurface. - - @author Stephen Anthony -*/ -class FBSurfaceTIA : public FBSurface -{ - friend class FrameBufferSDL2; - - public: - FBSurfaceTIA(FrameBufferSDL2& buffer); - virtual ~FBSurfaceTIA(); - - // TIA surfaces don't implement most of the drawing primitives, - // only the methods absolutely necessary for dealing with drawing - // a TIA image - void translateCoords(Int32& x, Int32& y) const; - void render(); - void invalidate(); - void free(); - void reload(); - - void setStaticContents(const uInt32* pixels, uInt32 pitch) { } - void setInterpolationAndBlending(bool smoothScale, bool useBlend, - uInt32 blendAlpha) { } - - uInt32 width() const { return 0; } - uInt32 height() const { return 0; } - - const GUI::Rect& srcRect() { return GUI::Rect(); } - const GUI::Rect& dstRect() { return GUI::Rect(); } -/////////////////////////////////////////////////////// - void getPos(uInt32& x, uInt32& y) const; - uInt32 getWidth() const { return myDstR.w; } - uInt32 getHeight() const { return myDstR.h; } -/////////////////////////////////////////////////////// - - void setSrcPos(uInt32 x, uInt32 y) { } - void setSrcSize(uInt32 w, uInt32 h) { } - void setDstPos(uInt32 x, uInt32 y) { } - void setDstSize(uInt32 w, uInt32 h) { } -/////////////////////////////////////////////////////// - void setPos(uInt32 x, uInt32 y) { } - void setWidth(uInt32 w) { } - void setHeight(uInt32 h) { } -/////////////////////////////////////////////////////// - - - private: - void setTIA(const TIA& tia) { myTIA = &tia; } - void setTIAPalette(const uInt32* palette); - void enableScanlines(bool enable) { myScanlinesEnabled = enable; } - void setScanIntensity(uInt32 intensity) { myScanlineIntensity = intensity; } - void setTexInterpolation(bool enable) { myTexFilter[0] = enable; } - void setScanInterpolation(bool enable) { myTexFilter[1] = enable; } - void updateCoords(uInt32 baseH, uInt32 imgX, uInt32 imgY, uInt32 imgW, uInt32 imgH); - void updateCoords(); - - private: - FrameBufferSDL2& myFB; - const TIA* myTIA; - - SDL_Surface* mySurface; - SDL_Texture* myTexture; - SDL_Texture* myScanlines; - SDL_Rect mySrcR, myDstR, myScanR; - uInt32 myPitch; - - bool myScanlinesEnabled; - uInt32* myScanData; - uInt32 myScanlineIntensity; - - bool myTexFilter[2]; -}; - -#endif diff --git a/src/common/FrameBufferSDL2.cxx b/src/common/FrameBufferSDL2.cxx index 8e4f62fb6..83eaedd0e 100644 --- a/src/common/FrameBufferSDL2.cxx +++ b/src/common/FrameBufferSDL2.cxx @@ -31,17 +31,14 @@ #include "TIA.hxx" #include "FBSurfaceSDL2.hxx" -#include "FBSurfaceTIA.hxx" #include "FrameBufferSDL2.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -FrameBufferSDL2::FrameBufferSDL2(OSystem* osystem) +FrameBufferSDL2::FrameBufferSDL2(OSystem& osystem) : FrameBuffer(osystem), - myFilterType(kNormal), myWindow(NULL), myRenderer(NULL), myWindowFlags(0), - myTiaSurface(NULL), myDirtyFlag(true), myDblBufferedFlag(true) { @@ -50,7 +47,7 @@ FrameBufferSDL2::FrameBufferSDL2(OSystem* osystem) { ostringstream buf; buf << "ERROR: Couldn't initialize SDL: " << SDL_GetError() << endl; - myOSystem->logMessage(buf.str(), 0); + myOSystem.logMessage(buf.str(), 0); return; } @@ -76,9 +73,6 @@ FrameBufferSDL2::~FrameBufferSDL2() SDL_DestroyWindow(myWindow); myWindow = NULL; } - - // We're taking responsibility for this surface - delete myTiaSurface; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -102,21 +96,12 @@ void FrameBufferSDL2::queryHardware(uInt32& w, uInt32& h, VariantList& renderers } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode, - bool full) +bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) { // If not initialized by this point, then immediately fail if(SDL_WasInit(SDL_INIT_VIDEO) == 0) return false; - bool inTIAMode = - myOSystem->eventHandler().state() != EventHandler::S_LAUNCHER && - myOSystem->eventHandler().state() != EventHandler::S_DEBUGGER; - - // Grab the initial height before it's updated below - // We need it for the creating the TIA surface - uInt32 baseHeight = mode.image.height() / mode.zoom; - // (Re)create window and renderer if(myRenderer) { @@ -130,7 +115,7 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode, } // Window centering option - int pos = myOSystem->settings().getBool("center") + int pos = myOSystem.settings().getBool("center") ? SDL_WINDOWPOS_CENTERED : SDL_WINDOWPOS_UNDEFINED; myWindow = SDL_CreateWindow(title.c_str(), pos, pos, mode.image.width(), mode.image.height(), @@ -138,60 +123,34 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode, if(myWindow == NULL) { string msg = "ERROR: Unable to open SDL window: " + string(SDL_GetError()); - myOSystem->logMessage(msg, 0); + myOSystem.logMessage(msg, 0); return false; } // V'synced blits option Uint32 renderFlags = SDL_RENDERER_ACCELERATED; - if(myOSystem->settings().getBool("vsync")) + if(myOSystem.settings().getBool("vsync")) renderFlags |= SDL_RENDERER_PRESENTVSYNC; // Render hint - const string& video = myOSystem->settings().getString("video"); + const string& video = myOSystem.settings().getString("video"); if(video != "") SDL_SetHint(SDL_HINT_RENDER_DRIVER, video.c_str()); myRenderer = SDL_CreateRenderer(myWindow, -1, renderFlags); if(myWindow == NULL) { string msg = "ERROR: Unable to create SDL renderer: " + string(SDL_GetError()); - myOSystem->logMessage(msg, 0); + myOSystem.logMessage(msg, 0); return false; } SDL_RendererInfo renderinfo; if(SDL_GetRendererInfo(myRenderer, &renderinfo) >= 0) { - myOSystem->settings().setValue("video", renderinfo.name); + myOSystem.settings().setValue("video", renderinfo.name); // For now, accelerated renderers imply double buffering // Eventually, SDL may be updated to query this from the render backend myDblBufferedFlag = renderinfo.flags & SDL_RENDERER_ACCELERATED; } - // 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) - { - // 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.width(), mode.image.height()); - - myTiaSurface->enableScanlines(ntscEnabled()); - myTiaSurface->setTexInterpolation(myOSystem->settings().getBool("tia.inter")); - myTiaSurface->setScanIntensity(myOSystem->settings().getInt("tv.scanlines")); - myTiaSurface->setScanInterpolation(myOSystem->settings().getBool("tv.scaninter")); - myTiaSurface->setTIA(myOSystem->console().tia()); - } - - // Any previously allocated textures currently in use by various UI items - // need to be refreshed as well - // This *must* come after the TIA settings have been updated - resetSurfaces(myTiaSurface); - return true; } @@ -218,9 +177,8 @@ string FrameBufferSDL2::about() const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferSDL2::invalidate() { - SDL_RenderClear(myRenderer); - if(myTiaSurface) - myTiaSurface->invalidate(); + myDirtyFlag = true; +// SDL_RenderClear(myRenderer); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -240,7 +198,7 @@ void FrameBufferSDL2::enableFullscreen(bool enable) { uInt32 flags = enable ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0; if(SDL_SetWindowFullscreen(myWindow, flags)) - myOSystem->settings().setValue("fullscreen", enable); + myOSystem.settings().setValue("fullscreen", enable); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -253,13 +211,6 @@ bool FrameBufferSDL2::fullScreen() const #endif } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBufferSDL2::drawTIA(bool fullRedraw) -{ - // The TIA surface takes all responsibility for drawing - myTiaSurface->render(); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferSDL2::postFrameUpdate() { @@ -271,70 +222,6 @@ void FrameBufferSDL2::postFrameUpdate() } } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBufferSDL2::enablePhosphor(bool enable, int blend) -{ - if(myTiaSurface) - { - myUsePhosphor = enable; - myPhosphorBlend = blend; - myFilterType = FilterType(enable ? myFilterType | 0x01 : myFilterType & 0x10); - myRedrawEntireFrame = true; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBufferSDL2::enableNTSC(bool enable) -{ - if(myTiaSurface) - { - myFilterType = FilterType(enable ? myFilterType | 0x10 : myFilterType & 0x01); - myTiaSurface->updateCoords(); - - myTiaSurface->enableScanlines(ntscEnabled()); - myTiaSurface->setScanIntensity(myOSystem->settings().getInt("tv.scanlines")); - myTiaSurface->setTexInterpolation(myOSystem->settings().getBool("tia.inter")); - myTiaSurface->setScanInterpolation(myOSystem->settings().getBool("tv.scaninter")); - - myRedrawEntireFrame = true; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 FrameBufferSDL2::enableScanlines(int relative, int absolute) -{ - if(myTiaSurface) - { - int intensity = myTiaSurface->myScanlineIntensity; - if(relative == 0) intensity = absolute; - else intensity += relative; - intensity = BSPF_max(0, intensity); - intensity = BSPF_min(100, intensity); - - myTiaSurface->setScanIntensity(intensity); - myRedrawEntireFrame = true; - return intensity; - } - return 0; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBufferSDL2::enableScanlineInterpolation(bool enable) -{ - if(myTiaSurface) - { - myTiaSurface->setScanInterpolation(enable); - myRedrawEntireFrame = true; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBufferSDL2::setTIAPalette(const uInt32* palette) -{ - FrameBuffer::setTIAPalette(palette); - myTiaSurface->setTIAPalette(palette); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBSurface* FrameBufferSDL2::createSurface(uInt32 w, uInt32 h) const { @@ -354,29 +241,3 @@ void FrameBufferSDL2::scanline(uInt32 row, uInt8* data) const p_gl.ReadPixels(image.x(), row, image.width(), 1, GL_RGB, GL_UNSIGNED_BYTE, data); #endif } - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string FrameBufferSDL2::effectsInfo() const -{ - ostringstream buf; - switch(myFilterType) - { - case kNormal: - buf << "Disabled, normal mode"; - break; - case kPhosphor: - buf << "Disabled, phosphor mode"; - break; - case kBlarggNormal: - buf << myNTSCFilter.getPreset() << ", scanlines=" - << myTiaSurface->myScanlineIntensity << "/" - << (myTiaSurface->myTexFilter[1] ? "inter" : "nointer"); - break; - case kBlarggPhosphor: - buf << myNTSCFilter.getPreset() << ", phosphor, scanlines=" - << myTiaSurface->myScanlineIntensity << "/" - << (myTiaSurface->myTexFilter[1] ? "inter" : "nointer"); - break; - } - return buf.str(); -} diff --git a/src/common/FrameBufferSDL2.hxx b/src/common/FrameBufferSDL2.hxx index e4dd5e5fe..3a9ad4984 100644 --- a/src/common/FrameBufferSDL2.hxx +++ b/src/common/FrameBufferSDL2.hxx @@ -24,8 +24,6 @@ class OSystem; class FBSurfaceSDL2; -class FBSurfaceTIA; -class TIA; #include "bspf.hxx" #include "FrameBuffer.hxx" @@ -40,13 +38,12 @@ class TIA; class FrameBufferSDL2 : public FrameBuffer { friend class FBSurfaceSDL2; - friend class FBSurfaceTIA; public: /** Creates a new SDL2 framebuffer */ - FrameBufferSDL2(OSystem* osystem); + FrameBufferSDL2(OSystem& osystem); /** Destructor @@ -72,24 +69,6 @@ class FrameBufferSDL2 : public FrameBuffer */ bool fullScreen() const; - /** - Enable/disable phosphor effect. - */ - void enablePhosphor(bool enable, int blend); - - /** - Enable/disable NTSC filtering effects. - */ - void enableNTSC(bool enable); - bool ntscEnabled() const { return myFilterType & 0x10; } - - /** - Set up the TIA/emulation palette for a screen of any depth > 8. - - @param palette The array of colors - */ - void setTIAPalette(const uInt32* palette); - /** This method is called to retrieve the R/G/B data from the given pixel. @@ -116,11 +95,6 @@ class FrameBufferSDL2 : public FrameBuffer */ bool isDoubleBuffered() const { return myDblBufferedFlag; } - /** - This method is called to query the TV effects in use by the FrameBuffer. - */ - string effectsInfo() const; - /** This method is called to get the specified scanline data. @@ -140,16 +114,14 @@ class FrameBufferSDL2 : public FrameBuffer void queryHardware(uInt32& w, uInt32& h, VariantList& renderers); /** - This method is called to change to the given video mode. If the mode - is successfully changed, 'mode' holds the actual dimensions used. + This method is called to change to the given video mode. @param title The title for the created window @param mode The video mode to use - @param full Whether this is a fullscreen or windowed mode @return False on any errors, else true */ - bool setVideoMode(const string& title, const VideoMode& mode, bool full); + bool setVideoMode(const string& title, const VideoMode& mode); /** Enables/disables fullscreen mode. @@ -181,12 +153,6 @@ class FrameBufferSDL2 : public FrameBuffer */ void setWindowIcon() { } // Not currently needed on any supported systems - /** - This method should be called anytime the TIA needs to be redrawn - to the screen (full indicating that a full redraw is required). - */ - void drawTIA(bool full); - /** This method is called to provide information about the FrameBuffer. */ @@ -197,27 +163,6 @@ class FrameBufferSDL2 : public FrameBuffer */ void postFrameUpdate(); - /** - Change scanline intensity and interpolation. - - @param relative If non-zero, change current intensity by - 'relative' amount, otherwise set to 'absolute' - @return New current intensity - */ - uInt32 enableScanlines(int relative, int absolute = 50); - void enableScanlineInterpolation(bool enable); - - private: - // Enumeration created such that phosphor off/on is in LSB, - // and Blargg off/on is in MSB - enum FilterType { - kNormal = 0x00, - kPhosphor = 0x01, - kBlarggNormal = 0x10, - kBlarggPhosphor = 0x11 - }; - FilterType myFilterType; - private: // The SDL video buffer SDL_Window* myWindow; @@ -229,10 +174,6 @@ class FrameBufferSDL2 : public FrameBuffer // it to point to the actual flags used by the SDL_Surface uInt32 myWindowFlags; - // The lower-most base surface (will always be a TIA surface, - // since Dialog surfaces are allocated by the Dialog class directly). - FBSurfaceTIA* myTiaSurface; - // Used by mapRGB (when palettes are created) SDL_PixelFormat* myPixelFormat; diff --git a/src/common/PNGLibrary.cxx b/src/common/PNGLibrary.cxx index b97117523..de03377a5 100644 --- a/src/common/PNGLibrary.cxx +++ b/src/common/PNGLibrary.cxx @@ -156,8 +156,8 @@ string PNGLibrary::saveImage(const string& filename, buf_ptr += pitch; // add pitch } - return saveBufferToPNG(out, buffer, width, height, - props, framebuffer.effectsInfo()); + return saveBufferToPNG(out, buffer, width, height, props, + framebuffer.tiaSurface().effectsInfo()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -180,7 +180,7 @@ string PNGLibrary::saveImage(const string& filename, *buf_ptr++ = 0; // first byte of row is filter type for(uInt32 x = 0; x < width; ++x) { - uInt32 pixel = framebuffer.tiaPixel(y*width+x); + uInt32 pixel = framebuffer.tiaSurface().pixel(y*width+x); framebuffer.getRGB(pixel, &r, &g, &b); *buf_ptr++ = r; *buf_ptr++ = g; @@ -191,8 +191,8 @@ string PNGLibrary::saveImage(const string& filename, } } - return saveBufferToPNG(out, buffer, width << 1, height, - props, framebuffer.effectsInfo()); + return saveBufferToPNG(out, buffer, width << 1, height, props, + framebuffer.tiaSurface().effectsInfo()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/common/SoundNull.hxx b/src/common/SoundNull.hxx index b3ede2e75..afaf7179a 100644 --- a/src/common/SoundNull.hxx +++ b/src/common/SoundNull.hxx @@ -40,7 +40,7 @@ class SoundNull : public Sound Create a new sound object. The init method must be invoked before using the object. */ - SoundNull(OSystem* osystem) : Sound(osystem) + SoundNull(OSystem& osystem) : Sound(osystem) { myOSystem->logMessage("Sound disabled.\n", 1); } diff --git a/src/common/SoundSDL2.cxx b/src/common/SoundSDL2.cxx index 0b170386d..ee5da3cee 100644 --- a/src/common/SoundSDL2.cxx +++ b/src/common/SoundSDL2.cxx @@ -33,7 +33,7 @@ #include "SoundSDL2.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -SoundSDL2::SoundSDL2(OSystem* osystem) +SoundSDL2::SoundSDL2(OSystem& osystem) : Sound(osystem), myIsEnabled(false), myIsInitializedFlag(false), @@ -43,17 +43,17 @@ SoundSDL2::SoundSDL2(OSystem* osystem) myIsMuted(true), myVolume(100) { - myOSystem->logMessage("SoundSDL2::SoundSDL2 started ...", 2); + myOSystem.logMessage("SoundSDL2::SoundSDL2 started ...", 2); // The sound system is opened only once per program run, to eliminate // issues with opening and closing it multiple times // This fixes a bug most prevalent with ATI video cards in Windows, // whereby sound stopped working after the first video change SDL_AudioSpec desired; - desired.freq = myOSystem->settings().getInt("freq"); + desired.freq = myOSystem.settings().getInt("freq"); desired.format = AUDIO_S16SYS; desired.channels = 2; - desired.samples = myOSystem->settings().getInt("fragsize"); + desired.samples = myOSystem.settings().getInt("fragsize"); desired.callback = callback; desired.userdata = (void*)this; @@ -62,7 +62,7 @@ SoundSDL2::SoundSDL2(OSystem* osystem) { buf << "WARNING: Couldn't open SDL audio system! " << endl << " " << SDL_GetError() << endl; - myOSystem->logMessage(buf.str(), 0); + myOSystem.logMessage(buf.str(), 0); return; } @@ -73,7 +73,7 @@ SoundSDL2::SoundSDL2(OSystem* osystem) buf << "WARNING: Sound device doesn't support realtime audio! Make " << "sure a sound" << endl << " server isn't running. Audio is disabled." << endl; - myOSystem->logMessage(buf.str(), 0); + myOSystem.logMessage(buf.str(), 0); SDL_CloseAudio(); return; @@ -87,7 +87,7 @@ SoundSDL2::SoundSDL2(OSystem* osystem) myIsInitializedFlag = true; SDL_PauseAudio(1); - myOSystem->logMessage("SoundSDL2::SoundSDL2 initialized", 2); + myOSystem.logMessage("SoundSDL2::SoundSDL2 initialized", 2); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -100,27 +100,27 @@ SoundSDL2::~SoundSDL2() myIsEnabled = myIsInitializedFlag = false; } - myOSystem->logMessage("SoundSDL2 destroyed", 2); + myOSystem.logMessage("SoundSDL2 destroyed", 2); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL2::setEnabled(bool state) { - myOSystem->settings().setValue("sound", state); + myOSystem.settings().setValue("sound", state); - myOSystem->logMessage(state ? "SoundSDL2::setEnabled(true)" : + myOSystem.logMessage(state ? "SoundSDL2::setEnabled(true)" : "SoundSDL2::setEnabled(false)", 2); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL2::open() { - myOSystem->logMessage("SoundSDL2::open started ...", 2); + myOSystem.logMessage("SoundSDL2::open started ...", 2); myIsEnabled = false; mute(true); - if(!myIsInitializedFlag || !myOSystem->settings().getBool("sound")) + if(!myIsInitializedFlag || !myOSystem.settings().getBool("sound")) { - myOSystem->logMessage("Sound disabled\n", 1); + myOSystem.logMessage("Sound disabled\n", 1); return; } @@ -130,7 +130,7 @@ void SoundSDL2::open() myTIASound.channels(myHardwareSpec.channels, myNumChannels == 2); // Adjust volume to that defined in settings - myVolume = myOSystem->settings().getInt("volume"); + myVolume = myOSystem.settings().getInt("volume"); setVolume(myVolume); // Show some info @@ -142,13 +142,13 @@ void SoundSDL2::open() << " Channels: " << (int)myHardwareSpec.channels << " (" << chanResult << ")" << endl << endl; - myOSystem->logMessage(buf.str(), 1); + myOSystem.logMessage(buf.str(), 1); // And start the SDL sound subsystem ... myIsEnabled = true; mute(false); - myOSystem->logMessage("SoundSDL2::open finished", 2); + myOSystem.logMessage("SoundSDL2::open finished", 2); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -161,7 +161,7 @@ void SoundSDL2::close() myLastRegisterSetCycle = 0; myTIASound.reset(); myRegWriteQueue.clear(); - myOSystem->logMessage("SoundSDL2::close", 2); + myOSystem.logMessage("SoundSDL2::close", 2); } } @@ -193,7 +193,7 @@ void SoundSDL2::setVolume(Int32 percent) { if(myIsInitializedFlag && (percent >= 0) && (percent <= 100)) { - myOSystem->settings().setValue("volume", percent); + myOSystem.settings().setValue("volume", percent); SDL_LockAudio(); myVolume = percent; myTIASound.volume(percent); @@ -224,7 +224,7 @@ void SoundSDL2::adjustVolume(Int8 direction) message = "Volume set to "; message += strval.str(); - myOSystem->frameBuffer().showMessage(message); + myOSystem.frameBuffer().showMessage(message); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -400,7 +400,7 @@ bool SoundSDL2::save(Serializer& out) const } catch(...) { - myOSystem->logMessage("ERROR: SoundSDL2::save", 0); + myOSystem.logMessage("ERROR: SoundSDL2::save", 0); return false; } @@ -441,7 +441,7 @@ bool SoundSDL2::load(Serializer& in) } catch(...) { - myOSystem->logMessage("ERROR: SoundSDL2::load", 0); + myOSystem.logMessage("ERROR: SoundSDL2::load", 0); return false; } diff --git a/src/common/SoundSDL2.hxx b/src/common/SoundSDL2.hxx index 978a2c86e..39c3d358c 100644 --- a/src/common/SoundSDL2.hxx +++ b/src/common/SoundSDL2.hxx @@ -43,7 +43,7 @@ class SoundSDL2 : public Sound Create a new sound object. The init method must be invoked before using the object. */ - SoundSDL2(OSystem* osystem); + SoundSDL2(OSystem& osystem); /** Destructor diff --git a/src/common/module.mk b/src/common/module.mk index 6d1f4b3c2..3c4434678 100644 --- a/src/common/module.mk +++ b/src/common/module.mk @@ -6,7 +6,6 @@ MODULE_OBJS := \ src/common/EventHandlerSDL2.o \ src/common/FrameBufferSDL2.o \ src/common/FBSurfaceSDL2.o \ - src/common/FBSurfaceTIA.o \ src/common/SoundSDL2.o \ src/common/FSNodeZIP.o \ src/common/PNGLibrary.o \ diff --git a/src/common/tv_filters/NTSCFilter.cxx b/src/common/tv_filters/NTSCFilter.cxx index 71290d409..ec1505888 100644 --- a/src/common/tv_filters/NTSCFilter.cxx +++ b/src/common/tv_filters/NTSCFilter.cxx @@ -17,7 +17,7 @@ // $Id$ //============================================================================ -#include "FrameBuffer.hxx" +#include "TIASurface.hxx" #include "Settings.hxx" #include "NTSCFilter.hxx" @@ -36,7 +36,7 @@ NTSCFilter::~NTSCFilter() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void NTSCFilter::setTIAPalette(const FrameBuffer& fb, const uInt32* palette) +void NTSCFilter::setTIAPalette(const TIASurface& tiaSurface, const uInt32* palette) { // Normal TIA palette contains 256 colours, where every odd indexed colour // is used for PAL colour-loss effect @@ -58,9 +58,9 @@ void NTSCFilter::setTIAPalette(const FrameBuffer& fb, const uInt32* palette) uInt8 gj = (palette[j] >> 8) & 0xff; uInt8 bj = palette[j] & 0xff; - *ptr++ = fb.getPhosphor(ri, rj); - *ptr++ = fb.getPhosphor(gi, gj); - *ptr++ = fb.getPhosphor(bi, bj); + *ptr++ = tiaSurface.getPhosphor(ri, rj); + *ptr++ = tiaSurface.getPhosphor(gi, gj); + *ptr++ = tiaSurface.getPhosphor(bi, bj); } } // Set palette for normal fill diff --git a/src/common/tv_filters/NTSCFilter.hxx b/src/common/tv_filters/NTSCFilter.hxx index 0855d97b4..0635945bd 100644 --- a/src/common/tv_filters/NTSCFilter.hxx +++ b/src/common/tv_filters/NTSCFilter.hxx @@ -20,7 +20,7 @@ #ifndef NTSC_FILTER_HXX #define NTSC_FILTER_HXX -class FrameBuffer; +class TIASurface; class Settings; #include "bspf.hxx" @@ -67,7 +67,7 @@ class NTSCFilter uses this as a baseline for calculating its own internal palette in YIQ format. */ - void setTIAPalette(const FrameBuffer& fb, const uInt32* palette); + void setTIAPalette(const TIASurface& tiaSurface, const uInt32* palette); // The following are meant to be used strictly for toggling from the GUI string setPreset(Preset preset); diff --git a/src/debugger/gui/TiaOutputWidget.cxx b/src/debugger/gui/TiaOutputWidget.cxx index 5629109a2..4e29b5fa9 100644 --- a/src/debugger/gui/TiaOutputWidget.cxx +++ b/src/debugger/gui/TiaOutputWidget.cxx @@ -28,6 +28,7 @@ #include "Debugger.hxx" #include "DebuggerParser.hxx" #include "TIADebug.hxx" +#include "TIASurface.hxx" #include "TIA.hxx" #include "TiaOutputWidget.hxx" @@ -150,7 +151,7 @@ void TiaOutputWidget::renderToSurface(FBSurface& s) for(uInt32 x = 0; x < width; ++x, ++i) { uInt8 shift = i > scanoffset ? 1 : 0; - uInt32 pixel = instance().frameBuffer().tiaPixel(i, shift); + uInt32 pixel = instance().frameBuffer().tiaSurface().pixel(i, shift); *line_ptr++ = pixel; *line_ptr++ = pixel; } diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 6bc8179a7..fa2da6725 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -66,14 +66,14 @@ #include "Console.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Console::Console(OSystem* osystem, Cartridge* cart, const Properties& props) +Console::Console(OSystem& osystem, Cartridge& cart, const Properties& props) : myOSystem(osystem), - myEvent(osystem->eventHandler().event()), + myCart(cart), + myEvent(osystem.eventHandler().event()), myProperties(props), myTIA(0), mySwitches(0), mySystem(0), - myCart(cart), myCMHandler(0), myDisplayFormat(""), // Unknown TV format @ start myFramerate(0.0), // Unknown framerate @ start @@ -99,27 +99,27 @@ Console::Console(OSystem* osystem, Cartridge* cart, const Properties& props) myControllers[0] = new Joystick(Controller::Left, myEvent, *mySystem); myControllers[1] = new Joystick(Controller::Right, myEvent, *mySystem); - M6502* m6502 = new M6502(1, myOSystem->settings()); + M6502* m6502 = new M6502(1, myOSystem.settings()); - myRiot = new M6532(*this, myOSystem->settings()); - myTIA = new TIA(*this, myOSystem->sound(), myOSystem->settings()); + myRiot = new M6532(*this, myOSystem.settings()); + myTIA = new TIA(*this, myOSystem.sound(), myOSystem.settings()); mySystem->attach(m6502); mySystem->attach(myRiot); mySystem->attach(myTIA); - mySystem->attach(myCart); + mySystem->attach(&myCart); // Auto-detect NTSC/PAL mode if it's requested string autodetected = ""; myDisplayFormat = myProperties.get(Display_Format); - if(myDisplayFormat == "AUTO" || myOSystem->settings().getBool("rominfo")) + if(myDisplayFormat == "AUTO" || myOSystem.settings().getBool("rominfo")) { // Run the TIA, looking for PAL scanline patterns // We turn off the SuperCharger progress bars, otherwise the SC BIOS // will take over 250 frames! // The 'fastscbios' option must be changed before the system is reset - bool fastscbios = myOSystem->settings().getBool("fastscbios"); - myOSystem->settings().setValue("fastscbios", true); + bool fastscbios = myOSystem.settings().getBool("fastscbios"); + myOSystem.settings().setValue("fastscbios", true); mySystem->reset(true); // autodetect in reset enabled for(int i = 0; i < 60; ++i) myTIA->update(); @@ -131,7 +131,7 @@ Console::Console(OSystem* osystem, Cartridge* cart, const Properties& props) } // Don't forget to reset the SC progress bars again - myOSystem->settings().setValue("fastscbios", fastscbios); + myOSystem.settings().setValue("fastscbios", fastscbios); } myConsoleInfo.DisplayFormat = myDisplayFormat + autodetected; @@ -157,8 +157,8 @@ Console::Console(OSystem* osystem, Cartridge* cart, const Properties& props) // Other ROMs can use it if the setting is enabled bool joyallow4 = md5 == "aa1c41f86ec44c0a44eb64c332ce08af" || md5 == "1bf503c724001b09be79c515ecfcbd03" || - myOSystem->settings().getBool("joyallow4"); - myOSystem->eventHandler().allowAllDirections(joyallow4); + myOSystem.settings().getBool("joyallow4"); + myOSystem.eventHandler().allowAllDirections(joyallow4); // Reset the system to its power-on state mySystem->reset(); @@ -168,9 +168,9 @@ Console::Console(OSystem* osystem, Cartridge* cart, const Properties& props) myConsoleInfo.CartMD5 = myProperties.get(Cartridge_MD5); myConsoleInfo.Control0 = myControllers[0]->about(); myConsoleInfo.Control1 = myControllers[1]->about(); - myConsoleInfo.BankSwitch = cart->about(); + myConsoleInfo.BankSwitch = myCart.about(); - myCart->setRomName(myConsoleInfo.CartName); + myCart.setRomName(myConsoleInfo.CartName); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -274,24 +274,24 @@ void Console::toggleFormat(int direction) } myProperties.set(Display_Format, saveformat); - setPalette(myOSystem->settings().getString("palette")); + setPalette(myOSystem.settings().getString("palette")); setTIAProperties(); myTIA->frameReset(); initializeVideo(); // takes care of refreshing the screen - myOSystem->frameBuffer().showMessage(message); + myOSystem.frameBuffer().showMessage(message); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::toggleColorLoss() { - bool colorloss = !myOSystem->settings().getBool("colorloss"); - myOSystem->settings().setValue("colorloss", colorloss); + bool colorloss = !myOSystem.settings().getBool("colorloss"); + myOSystem.settings().setValue("colorloss", colorloss); myTIA->enableColorLoss(colorloss); string message = string("PAL color-loss ") + (colorloss ? "enabled" : "disabled"); - myOSystem->frameBuffer().showMessage(message); + myOSystem.frameBuffer().showMessage(message); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -304,7 +304,7 @@ void Console::toggleColorLoss(bool state) void Console::togglePalette() { string palette, message; - palette = myOSystem->settings().getString("palette"); + palette = myOSystem.settings().getString("palette"); if(palette == "standard") // switch to z26 { @@ -337,8 +337,8 @@ void Console::togglePalette() message = "Standard Stella palette"; } - myOSystem->settings().setValue("palette", palette); - myOSystem->frameBuffer().showMessage(message); + myOSystem.settings().setValue("palette", palette); + myOSystem.frameBuffer().showMessage(message); setPalette(palette); } @@ -369,7 +369,7 @@ void Console::setPalette(const string& type) (myDisplayFormat.compare(0, 5, "SECAM") == 0) ? palettes[paletteNum][2] : palettes[paletteNum][0]; - myOSystem->frameBuffer().setTIAPalette(palette); + myOSystem.frameBuffer().setPalette(palette); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -382,16 +382,16 @@ void Console::togglePhosphor() { myProperties.set(Display_Phosphor, "No"); enable = false; - myOSystem->frameBuffer().showMessage("Phosphor effect disabled"); + myOSystem.frameBuffer().showMessage("Phosphor effect disabled"); } else { myProperties.set(Display_Phosphor, "Yes"); enable = true; - myOSystem->frameBuffer().showMessage("Phosphor effect enabled"); + myOSystem.frameBuffer().showMessage("Phosphor effect enabled"); } - myOSystem->frameBuffer().enablePhosphor(enable, blend); + myOSystem.frameBuffer().tiaSurface().enablePhosphor(enable, blend); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -403,35 +403,30 @@ void Console::setProperties(const Properties& props) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBInitStatus Console::initializeVideo(bool full) { + setPalette(myOSystem.settings().getString("palette")); + FBInitStatus fbstatus = kSuccess; if(full) { const string& title = string("Stella ") + STELLA_VERSION + ": \"" + myProperties.get(Cartridge_Name) + "\""; - fbstatus = myOSystem->frameBuffer().createDisplay(title, + fbstatus = myOSystem.frameBuffer().createDisplay(title, myTIA->width() << 1, myTIA->height()); if(fbstatus != kSuccess) return fbstatus; - myOSystem->frameBuffer().showFrameStats(myOSystem->settings().getBool("stats")); - setColorLossPalette(); + myOSystem.frameBuffer().showFrameStats(myOSystem.settings().getBool("stats")); + generateColorLossPalette(); } - bool enable = myProperties.get(Display_Phosphor) == "YES"; - int blend = atoi(myProperties.get(Display_PPBlend).c_str()); - myOSystem->frameBuffer().enablePhosphor(enable, blend); - myOSystem->frameBuffer().setNTSC( - (NTSCFilter::Preset)myOSystem->settings().getInt("tv.filter"), false); - setPalette(myOSystem->settings().getString("palette")); - // Set the correct framerate based on the format of the ROM // This can be overridden by changing the framerate in the // VideoDialog box or on the commandline, but it can't be saved // (ie, framerate is now determined based on number of scanlines). - int framerate = myOSystem->settings().getInt("framerate"); + int framerate = myOSystem.settings().getInt("framerate"); if(framerate > 0) myFramerate = float(framerate); - myOSystem->setFramerate(myFramerate); + myOSystem.setFramerate(myFramerate); // Make sure auto-frame calculation is only enabled when necessary myTIA->enableAutoFrame(framerate <= 0); @@ -445,20 +440,19 @@ void Console::initializeAudio() // Initialize the sound interface. // The # of channels can be overridden in the AudioDialog box or on // the commandline, but it can't be saved. - int framerate = myOSystem->settings().getInt("framerate"); + int framerate = myOSystem.settings().getInt("framerate"); if(framerate > 0) myFramerate = float(framerate); const string& sound = myProperties.get(Cartridge_Sound); - myOSystem->sound().close(); - myOSystem->sound().setChannels(sound == "STEREO" ? 2 : 1); - myOSystem->sound().setFrameRate(myFramerate); - myOSystem->sound().open(); + myOSystem.sound().close(); + myOSystem.sound().setChannels(sound == "STEREO" ? 2 : 1); + myOSystem.sound().setFrameRate(myFramerate); + myOSystem.sound().open(); // Make sure auto-frame calculation is only enabled when necessary myTIA->enableAutoFrame(framerate <= 0); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* Original frying research and code by Fred Quimby. I've tried the following variations on this code: - Both OR and Exclusive OR instead of AND. This generally crashes the game @@ -478,6 +472,7 @@ void Console::initializeAudio() Until someone comes up with a more accurate way to emulate frying, I'm leaving this as Fred posted it. -- B. */ +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::fry() const { for (int ZPmem=0; ZPmem<0x100; ZPmem += rand() % 4) @@ -493,7 +488,7 @@ void Console::changeYStart(int direction) { if(ystart >= 64) { - myOSystem->frameBuffer().showMessage("YStart at maximum"); + myOSystem.frameBuffer().showMessage("YStart at maximum"); return; } ystart++; @@ -502,7 +497,7 @@ void Console::changeYStart(int direction) { if(ystart == 0) { - myOSystem->frameBuffer().showMessage("YStart at minimum"); + myOSystem.frameBuffer().showMessage("YStart at minimum"); return; } ystart--; @@ -512,11 +507,11 @@ void Console::changeYStart(int direction) myTIA->setYStart(ystart); myTIA->frameReset(); - myOSystem->frameBuffer().refresh(); + myOSystem.frameBuffer().refresh(); ostringstream val; val << ystart; - myOSystem->frameBuffer().showMessage("YStart " + val.str()); + myOSystem.frameBuffer().showMessage("YStart " + val.str()); myProperties.set(Display_YStart, val.str()); } @@ -524,14 +519,14 @@ void Console::changeYStart(int direction) void Console::changeHeight(int direction) { uInt32 height = myTIA->height(); - uInt32 dheight = myOSystem->frameBuffer().desktopSize().h; + uInt32 dheight = myOSystem.frameBuffer().desktopSize().h; if(direction == +1) // increase Height { height++; if(height > 256 || height > dheight) { - myOSystem->frameBuffer().showMessage("Height at maximum"); + myOSystem.frameBuffer().showMessage("Height at maximum"); return; } } @@ -540,7 +535,7 @@ void Console::changeHeight(int direction) height--; if(height < 210) { - myOSystem->frameBuffer().showMessage("Height at minimum"); + myOSystem.frameBuffer().showMessage("Height at minimum"); return; } } @@ -553,7 +548,7 @@ void Console::changeHeight(int direction) ostringstream val; val << height; - myOSystem->frameBuffer().showMessage("Height " + val.str()); + myOSystem.frameBuffer().showMessage("Height " + val.str()); myProperties.set(Display_Height, val.str()); } @@ -586,7 +581,7 @@ void Console::setTIAProperties() // Make sure these values fit within the bounds of the desktop // If not, attempt to center vertically - uInt32 dheight = myOSystem->frameBuffer().desktopSize().h; + uInt32 dheight = myOSystem.frameBuffer().desktopSize().h; if(height > dheight) { ystart += height - dheight; @@ -612,7 +607,7 @@ void Console::setControllers(const string& rommd5) if(left == "COMPUMATE" || right == "COMPUMATE") { delete myCMHandler; - myCMHandler = new CompuMate(*((CartridgeCM*)myCart), myEvent, *mySystem); + myCMHandler = new CompuMate(*((CartridgeCM*)&myCart), myEvent, *mySystem); myControllers[0] = myCMHandler->leftController(); myControllers[1] = myCMHandler->rightController(); return; @@ -729,14 +724,14 @@ void Console::setControllers(const string& rommd5) } else if(right == "ATARIVOX") { - const string& nvramfile = myOSystem->nvramDir() + "atarivox_eeprom.dat"; + const string& nvramfile = myOSystem.nvramDir() + "atarivox_eeprom.dat"; myControllers[rightPort] = new AtariVox(Controller::Right, myEvent, - *mySystem, myOSystem->serialPort(), - myOSystem->settings().getString("avoxport"), nvramfile); + *mySystem, myOSystem.serialPort(), + myOSystem.settings().getString("avoxport"), nvramfile); } else if(right == "SAVEKEY") { - const string& nvramfile = myOSystem->nvramDir() + "savekey_eeprom.dat"; + const string& nvramfile = myOSystem.nvramDir() + "savekey_eeprom.dat"; myControllers[rightPort] = new SaveKey(Controller::Right, myEvent, *mySystem, nvramfile); } @@ -761,7 +756,7 @@ void Console::setControllers(const string& rommd5) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::loadUserPalette() { - const string& palette = myOSystem->paletteFile(); + const string& palette = myOSystem.paletteFile(); ifstream in(palette.c_str(), ios::binary); if(!in) return; @@ -816,7 +811,7 @@ void Console::loadUserPalette() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::setColorLossPalette() +void Console::generateColorLossPalette() { // Look at all the palettes, since we don't know which one is // currently active @@ -857,8 +852,8 @@ void Console::setColorLossPalette() void Console::setFramerate(float framerate) { myFramerate = framerate; - myOSystem->setFramerate(framerate); - myOSystem->sound().setFrameRate(framerate); + myOSystem.setFramerate(framerate); + myOSystem.sound().setFrameRate(framerate); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -866,7 +861,7 @@ void Console::toggleTIABit(TIABit bit, const string& bitname, bool show) const { bool result = myTIA->toggleBit(bit); string message = bitname + (result ? " enabled" : " disabled"); - myOSystem->frameBuffer().showMessage(message); + myOSystem.frameBuffer().showMessage(message); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -874,7 +869,7 @@ void Console::toggleBits() const { bool enabled = myTIA->toggleBits(); string message = string("TIA bits") + (enabled ? " enabled" : " disabled"); - myOSystem->frameBuffer().showMessage(message); + myOSystem.frameBuffer().showMessage(message); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -882,7 +877,7 @@ void Console::toggleTIACollision(TIABit bit, const string& bitname, bool show) c { bool result = myTIA->toggleCollision(bit); string message = bitname + (result ? " collision enabled" : " collision disabled"); - myOSystem->frameBuffer().showMessage(message); + myOSystem.frameBuffer().showMessage(message); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -890,33 +885,33 @@ void Console::toggleCollisions() const { bool enabled = myTIA->toggleCollisions(); string message = string("TIA collisions") + (enabled ? " enabled" : " disabled"); - myOSystem->frameBuffer().showMessage(message); + myOSystem.frameBuffer().showMessage(message); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::toggleHMOVE() const { if(myTIA->toggleHMOVEBlank()) - myOSystem->frameBuffer().showMessage("HMOVE blanking enabled"); + myOSystem.frameBuffer().showMessage("HMOVE blanking enabled"); else - myOSystem->frameBuffer().showMessage("HMOVE blanking disabled"); + myOSystem.frameBuffer().showMessage("HMOVE blanking disabled"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::toggleFixedColors() const { if(myTIA->toggleFixedColors()) - myOSystem->frameBuffer().showMessage("Fixed debug colors enabled"); + myOSystem.frameBuffer().showMessage("Fixed debug colors enabled"); else - myOSystem->frameBuffer().showMessage("Fixed debug colors disabled"); + myOSystem.frameBuffer().showMessage("Fixed debug colors disabled"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::addDebugger() { #ifdef DEBUGGER_SUPPORT - myOSystem->createDebugger(*this); - mySystem->m6502().attach(myOSystem->debugger()); + myOSystem.createDebugger(*this); + mySystem->m6502().attach(myOSystem.debugger()); #endif } @@ -1156,6 +1151,7 @@ uInt32 Console::ourUserSECAMPalette[256] = { 0 }; // filled from external file // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Console::Console(const Console& console) : myOSystem(console.myOSystem), + myCart(console.myCart), myEvent(console.myEvent) { assert(false); diff --git a/src/emucore/Console.hxx b/src/emucore/Console.hxx index 5122625ce..ed88a831f 100644 --- a/src/emucore/Console.hxx +++ b/src/emucore/Console.hxx @@ -68,7 +68,7 @@ class Console : public Serializable @param cart The cartridge to use with this console @param props The properties for the cartridge */ - Console(OSystem* osystem, Cartridge* cart, const Properties& props); + Console(OSystem& osystem, Cartridge& cart, const Properties& props); /** Create a new console object by copying another one @@ -126,7 +126,7 @@ class Console : public Serializable @return The cartridge for this console */ - Cartridge& cartridge() const { return *myCart; } + Cartridge& cartridge() const { return myCart; } /** Get the 6532 used by the console @@ -327,7 +327,7 @@ class Console : public Serializable normally can't have it enabled (NTSC), since it's also used for 'greying out' the frame in the debugger. */ - void setColorLossPalette(); + void generateColorLossPalette(); /** Returns a pointer to the palette data for the palette currently defined @@ -339,8 +339,11 @@ class Console : public Serializable void toggleTIACollision(TIABit bit, const string& bitname, bool show = true) const; private: - // Pointer to the osystem object - OSystem* myOSystem; + // Reference to the osystem object + OSystem& myOSystem; + + // Pointer to the Cartridge (the debugger needs it) + Cartridge& myCart; // Reference to the event object to use Event& myEvent; @@ -360,9 +363,6 @@ class Console : public Serializable // Pointer to the 6502 based system being emulated System* mySystem; - // Pointer to the Cartridge (the debugger needs it) - Cartridge* myCart; - // Pointer to the 6532 (aka RIOT) (the debugger needs it) // A RIOT of my own! (...with apologies to The Clash...) M6532* myRiot; diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 3dd2c902f..6c28bab1a 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -55,7 +55,7 @@ #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -EventHandler::EventHandler(OSystem* osystem) +EventHandler::EventHandler(OSystem& osystem) : myOSystem(osystem), myOverlay(NULL), myMouseControl(NULL), @@ -102,27 +102,27 @@ void EventHandler::initialize() setActionMappings(kEmulationMode); setActionMappings(kMenuMode); - myUseCtrlKeyFlag = myOSystem->settings().getBool("ctrlcombo"); + myUseCtrlKeyFlag = myOSystem.settings().getBool("ctrlcombo"); - Joystick::setDeadZone(myOSystem->settings().getInt("joydeadzone")); - Paddles::setDigitalSensitivity(myOSystem->settings().getInt("dsense")); - Paddles::setMouseSensitivity(myOSystem->settings().getInt("msense")); + Joystick::setDeadZone(myOSystem.settings().getInt("joydeadzone")); + Paddles::setDigitalSensitivity(myOSystem.settings().getInt("dsense")); + Paddles::setMouseSensitivity(myOSystem.settings().getInt("msense")); // Set quick select delay when typing characters in listwidgets - ListWidget::setQuickSelectDelay(myOSystem->settings().getInt("listdelay")); + ListWidget::setQuickSelectDelay(myOSystem.settings().getInt("listdelay")); // Set number of lines a mousewheel will scroll - ScrollBarWidget::setWheelLines(myOSystem->settings().getInt("mwheel")); + ScrollBarWidget::setWheelLines(myOSystem.settings().getInt("mwheel")); // Integer to string conversions (for HEX) use upper or lower-case - Common::Base::setHexUppercase(myOSystem->settings().getBool("dbg.uhex")); + Common::Base::setHexUppercase(myOSystem.settings().getBool("dbg.uhex")); // Joystick stuff #ifdef JOYSTICK_SUPPORT initializeJoysticks(); // Map the stelladaptors we've found according to the specified ports - mapStelladaptors(myOSystem->settings().getString("saport")); + mapStelladaptors(myOSystem.settings().getString("saport")); setJoymap(); setActionMappings(kEmulationMode); @@ -137,9 +137,9 @@ void EventHandler::initialize() for(uInt32 i = 0; i < myJoysticks.size(); ++i) buf << " " << i << ": " << myJoysticks[i]->about() << endl; } - myOSystem->logMessage(buf.str(), 1); + myOSystem.logMessage(buf.str(), 1); #else - myOSystem->logMessage("Joystick support disabled.", 1); + myOSystem.logMessage("Joystick support disabled.", 1); #endif } @@ -147,7 +147,7 @@ void EventHandler::initialize() void EventHandler::reset(State state) { setEventState(state); - myOSystem->state().reset(); + myOSystem.state().reset(); setContinuousSnapshots(0); @@ -256,7 +256,7 @@ void EventHandler::mapStelladaptors(const string& saport) } } } - myOSystem->settings().setValue("saport", saport); + myOSystem.settings().setValue("saport", saport); // We're potentially swapping out an input device behind the back of // the Event system, so we make sure all Stelladaptor-generated events @@ -276,16 +276,16 @@ void EventHandler::mapStelladaptors(const string& saport) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::toggleSAPortOrder() { - const string& saport = myOSystem->settings().getString("saport"); + const string& saport = myOSystem.settings().getString("saport"); if(saport == "lr") { mapStelladaptors("rl"); - myOSystem->frameBuffer().showMessage("Stelladaptor ports right/left"); + myOSystem.frameBuffer().showMessage("Stelladaptor ports right/left"); } else { mapStelladaptors("lr"); - myOSystem->frameBuffer().showMessage("Stelladaptor ports left/right"); + myOSystem.frameBuffer().showMessage("Stelladaptor ports left/right"); } } @@ -299,21 +299,21 @@ void EventHandler::poll(uInt64 time) // related to emulation if(myState == S_EMULATE) { - myOSystem->console().riot().update(); + myOSystem.console().riot().update(); #if 0 // Now check if the StateManager should be saving or loading state // Per-frame cheats are disabled if the StateManager is active, since // it would interfere with proper playback - if(myOSystem->state().isActive()) + if(myOSystem.state().isActive()) { - myOSystem->state().update(); + myOSystem.state().update(); } else #endif { #ifdef CHEATCODE_SUPPORT - const CheatList& cheats = myOSystem->cheat().perFrame(); + const CheatList& cheats = myOSystem.cheat().perFrame(); for(uInt32 i = 0; i < cheats.size(); i++) cheats[i]->evaluate(); #endif @@ -359,7 +359,7 @@ void EventHandler::handleKeyEvent(StellaKey key, StellaMod mod, char ascii, bool #endif if(key == KBDK_RETURN) { - myOSystem->frameBuffer().toggleFullscreen(); + myOSystem.frameBuffer().toggleFullscreen(); } // These only work when in emulation mode else if(myState == S_EMULATE) @@ -367,160 +367,160 @@ void EventHandler::handleKeyEvent(StellaKey key, StellaMod mod, char ascii, bool switch(key) { case KBDK_EQUALS: - myOSystem->frameBuffer().changeWindowedVidMode(+1); + myOSystem.frameBuffer().changeWindowedVidMode(+1); break; case KBDK_MINUS: - myOSystem->frameBuffer().changeWindowedVidMode(-1); + myOSystem.frameBuffer().changeWindowedVidMode(-1); break; case KBDK_LEFTBRACKET: - myOSystem->sound().adjustVolume(-1); + myOSystem.sound().adjustVolume(-1); break; case KBDK_RIGHTBRACKET: - myOSystem->sound().adjustVolume(+1); + myOSystem.sound().adjustVolume(+1); break; case KBDK_PAGEUP: // Alt-PageUp increases YStart - myOSystem->console().changeYStart(+1); + myOSystem.console().changeYStart(+1); break; case KBDK_PAGEDOWN: // Alt-PageDown decreases YStart - myOSystem->console().changeYStart(-1); + myOSystem.console().changeYStart(-1); break; case KBDK_1: // Alt-1 turns off NTSC filtering - myOSystem->frameBuffer().setNTSC(NTSCFilter::PRESET_OFF); + myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::PRESET_OFF); break; case KBDK_2: // Alt-2 turns on 'composite' NTSC filtering - myOSystem->frameBuffer().setNTSC(NTSCFilter::PRESET_COMPOSITE); + myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::PRESET_COMPOSITE); break; case KBDK_3: // Alt-3 turns on 'svideo' NTSC filtering - myOSystem->frameBuffer().setNTSC(NTSCFilter::PRESET_SVIDEO); + myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::PRESET_SVIDEO); break; case KBDK_4: // Alt-4 turns on 'rgb' NTSC filtering - myOSystem->frameBuffer().setNTSC(NTSCFilter::PRESET_RGB); + myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::PRESET_RGB); break; case KBDK_5: // Alt-5 turns on 'bad' NTSC filtering - myOSystem->frameBuffer().setNTSC(NTSCFilter::PRESET_BAD); + myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::PRESET_BAD); break; case KBDK_6: // Alt-6 turns on 'custom' NTSC filtering - myOSystem->frameBuffer().setNTSC(NTSCFilter::PRESET_CUSTOM); + myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::PRESET_CUSTOM); break; case KBDK_7: // Alt-7 changes scanline intensity for NTSC filtering if(mod & KMOD_SHIFT) - myOSystem->frameBuffer().setScanlineIntensity(-5); + myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(-5); else - myOSystem->frameBuffer().setScanlineIntensity(+5); + myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(+5); break; case KBDK_8: // Alt-8 turns toggles scanline interpolation - myOSystem->frameBuffer().toggleScanlineInterpolation(); + myOSystem.frameBuffer().tiaSurface().toggleScanlineInterpolation(); break; case KBDK_9: // Alt-9 selects various custom adjustables for NTSC filtering - if(myOSystem->frameBuffer().ntscEnabled()) + if(myOSystem.frameBuffer().tiaSurface().ntscEnabled()) { if(mod & KMOD_SHIFT) - myOSystem->frameBuffer().showMessage( - myOSystem->frameBuffer().ntsc().setPreviousAdjustable()); + myOSystem.frameBuffer().showMessage( + myOSystem.frameBuffer().tiaSurface().ntsc().setPreviousAdjustable()); else - myOSystem->frameBuffer().showMessage( - myOSystem->frameBuffer().ntsc().setNextAdjustable()); + myOSystem.frameBuffer().showMessage( + myOSystem.frameBuffer().tiaSurface().ntsc().setNextAdjustable()); } break; case KBDK_0: // Alt-0 changes custom adjustables for NTSC filtering - if(myOSystem->frameBuffer().ntscEnabled()) + if(myOSystem.frameBuffer().tiaSurface().ntscEnabled()) { if(mod & KMOD_SHIFT) - myOSystem->frameBuffer().showMessage( - myOSystem->frameBuffer().ntsc().decreaseAdjustable()); + myOSystem.frameBuffer().showMessage( + myOSystem.frameBuffer().tiaSurface().ntsc().decreaseAdjustable()); else - myOSystem->frameBuffer().showMessage( - myOSystem->frameBuffer().ntsc().increaseAdjustable()); + myOSystem.frameBuffer().showMessage( + myOSystem.frameBuffer().tiaSurface().ntsc().increaseAdjustable()); } break; case KBDK_Z: if(mod & KMOD_SHIFT) - myOSystem->console().toggleP0Collision(); + myOSystem.console().toggleP0Collision(); else - myOSystem->console().toggleP0Bit(); + myOSystem.console().toggleP0Bit(); break; case KBDK_X: if(mod & KMOD_SHIFT) - myOSystem->console().toggleP1Collision(); + myOSystem.console().toggleP1Collision(); else - myOSystem->console().toggleP1Bit(); + myOSystem.console().toggleP1Bit(); break; case KBDK_C: if(mod & KMOD_SHIFT) - myOSystem->console().toggleM0Collision(); + myOSystem.console().toggleM0Collision(); else - myOSystem->console().toggleM0Bit(); + myOSystem.console().toggleM0Bit(); break; case KBDK_V: if(mod & KMOD_SHIFT) - myOSystem->console().toggleM1Collision(); + myOSystem.console().toggleM1Collision(); else - myOSystem->console().toggleM1Bit(); + myOSystem.console().toggleM1Bit(); break; case KBDK_B: if(mod & KMOD_SHIFT) - myOSystem->console().toggleBLCollision(); + myOSystem.console().toggleBLCollision(); else - myOSystem->console().toggleBLBit(); + myOSystem.console().toggleBLBit(); break; case KBDK_N: if(mod & KMOD_SHIFT) - myOSystem->console().togglePFCollision(); + myOSystem.console().togglePFCollision(); else - myOSystem->console().togglePFBit(); + myOSystem.console().togglePFBit(); break; case KBDK_M: - myOSystem->console().toggleHMOVE(); + myOSystem.console().toggleHMOVE(); break; case KBDK_COMMA: - myOSystem->console().toggleFixedColors(); + myOSystem.console().toggleFixedColors(); break; case KBDK_PERIOD: if(mod & KMOD_SHIFT) - myOSystem->console().toggleCollisions(); + myOSystem.console().toggleCollisions(); else - myOSystem->console().toggleBits(); + myOSystem.console().toggleBits(); break; case KBDK_P: // Alt-p toggles phosphor effect - myOSystem->console().togglePhosphor(); + myOSystem.console().togglePhosphor(); break; case KBDK_L: - myOSystem->frameBuffer().toggleFrameStats(); + myOSystem.frameBuffer().toggleFrameStats(); break; case KBDK_S: if(myContSnapshotInterval == 0) { ostringstream buf; - uInt32 interval = myOSystem->settings().getInt("ssinterval"); + uInt32 interval = myOSystem.settings().getInt("ssinterval"); buf << "Enabling shotshots in " << interval << " second intervals"; - myOSystem->frameBuffer().showMessage(buf.str()); + myOSystem.frameBuffer().showMessage(buf.str()); setContinuousSnapshots(interval); } else @@ -529,7 +529,7 @@ void EventHandler::handleKeyEvent(StellaKey key, StellaMod mod, char ascii, bool buf << "Disabling snapshots, generated " << (myContSnapshotCounter / myContSnapshotInterval) << " files"; - myOSystem->frameBuffer().showMessage(buf.str()); + myOSystem.frameBuffer().showMessage(buf.str()); setContinuousSnapshots(0); } break; @@ -556,7 +556,7 @@ void EventHandler::handleKeyEvent(StellaKey key, StellaMod mod, char ascii, bool { case KBDK_0: // Ctrl-0 switches between mouse control modes if(myMouseControl) - myOSystem->frameBuffer().showMessage(myMouseControl->next()); + myOSystem.frameBuffer().showMessage(myMouseControl->next()); break; case KBDK_1: // Ctrl-1 swaps Stelladaptor/2600-daptor ports @@ -564,47 +564,47 @@ void EventHandler::handleKeyEvent(StellaKey key, StellaMod mod, char ascii, bool break; case KBDK_F: // (Shift) Ctrl-f toggles NTSC/PAL/SECAM mode - myOSystem->console().toggleFormat(mod & KMOD_SHIFT ? -1 : 1); + myOSystem.console().toggleFormat(mod & KMOD_SHIFT ? -1 : 1); break; case KBDK_G: // Ctrl-g (un)grabs mouse - if(!myOSystem->frameBuffer().fullScreen()) - myOSystem->frameBuffer().toggleGrabMouse(); + if(!myOSystem.frameBuffer().fullScreen()) + myOSystem.frameBuffer().toggleGrabMouse(); break; case KBDK_L: // Ctrl-l toggles PAL color-loss effect - myOSystem->console().toggleColorLoss(); + myOSystem.console().toggleColorLoss(); break; case KBDK_P: // Ctrl-p toggles different palettes - myOSystem->console().togglePalette(); + myOSystem.console().togglePalette(); break; case KBDK_R: // Ctrl-r reloads the currently loaded ROM - myOSystem->reloadConsole(); + myOSystem.reloadConsole(); break; case KBDK_PAGEUP: // Ctrl-PageUp increases Height - myOSystem->console().changeHeight(+1); + myOSystem.console().changeHeight(+1); break; case KBDK_PAGEDOWN: // Ctrl-PageDown decreases Height - myOSystem->console().changeHeight(-1); + myOSystem.console().changeHeight(-1); break; case KBDK_S: // Ctrl-s saves properties to a file { - string filename = myOSystem->baseDir() + - myOSystem->console().properties().get(Cartridge_Name) + ".pro"; + string filename = myOSystem.baseDir() + + myOSystem.console().properties().get(Cartridge_Name) + ".pro"; ofstream out(filename.c_str(), ios::out); if(out) { - myOSystem->console().properties().save(out); + myOSystem.console().properties().save(out); out.close(); - myOSystem->frameBuffer().showMessage("Properties saved"); + myOSystem.frameBuffer().showMessage("Properties saved"); } else - myOSystem->frameBuffer().showMessage("Error saving properties"); + myOSystem.frameBuffer().showMessage("Error saving properties"); break; } @@ -718,7 +718,7 @@ void EventHandler::handleJoyEvent(int stick, int button, uInt8 state) // enum; subtracting four gives us Controller 0 and 1 if(myState == S_EMULATE) { - switch(myOSystem->console().controller(Controller::Left).type()) + switch(myOSystem.console().controller(Controller::Left).type()) { case Controller::Keyboard: if(button < 12) myEvent.set(SA_Key[joy.type-4][button], state); @@ -726,7 +726,7 @@ void EventHandler::handleJoyEvent(int stick, int button, uInt8 state) default: if(button < 4) myEvent.set(SA_Button[joy.type-4][button], state); } - switch(myOSystem->console().controller(Controller::Right).type()) + switch(myOSystem.console().controller(Controller::Right).type()) { case Controller::Keyboard: if(button < 12) myEvent.set(SA_Key[joy.type-4][button], state); @@ -895,7 +895,7 @@ void EventHandler::handleSystemEvent(SystemEvent e, int data1, int data2) switch(e) { case EVENT_WINDOW_EXPOSED: - myOSystem->frameBuffer().refresh(); + myOSystem.frameBuffer().refresh(); break; default: // handle other events as testing requires // cerr << "handleSystemEvent: " << e << endl; @@ -964,23 +964,23 @@ void EventHandler::handleEvent(Event::Type event, int state) return; case Event::VolumeDecrease: - if(state) myOSystem->sound().adjustVolume(-1); + if(state) myOSystem.sound().adjustVolume(-1); return; case Event::VolumeIncrease: - if(state) myOSystem->sound().adjustVolume(+1); + if(state) myOSystem.sound().adjustVolume(+1); return; case Event::SaveState: - if(state) myOSystem->state().saveState(); + if(state) myOSystem.state().saveState(); return; case Event::ChangeState: - if(state) myOSystem->state().changeState(); + if(state) myOSystem.state().changeState(); return; case Event::LoadState: - if(state) myOSystem->state().loadState(); + if(state) myOSystem.state().loadState(); return; case Event::TakeSnapshot: @@ -992,11 +992,11 @@ void EventHandler::handleEvent(Event::Type event, int state) myState == S_DEBUGGER) && state) { // Go back to the launcher, or immediately quit - if(myOSystem->settings().getBool("exitlauncher") || - myOSystem->launcherUsed()) + if(myOSystem.settings().getBool("exitlauncher") || + myOSystem.launcherUsed()) { - myOSystem->deleteConsole(); - myOSystem->createLauncher(); + myOSystem.deleteConsole(); + myOSystem.createLauncher(); } else handleEvent(Event::Quit, 1); @@ -1008,7 +1008,7 @@ void EventHandler::handleEvent(Event::Type event, int state) { saveKeyMapping(); saveJoyMapping(); - myOSystem->quit(); + myOSystem.quit(); } return; @@ -1039,22 +1039,22 @@ void EventHandler::handleEvent(Event::Type event, int state) // Events which generate messages case Event::ConsoleColor: - if(state) myOSystem->frameBuffer().showMessage("Color Mode"); + if(state) myOSystem.frameBuffer().showMessage("Color Mode"); break; case Event::ConsoleBlackWhite: - if(state) myOSystem->frameBuffer().showMessage("BW Mode"); + if(state) myOSystem.frameBuffer().showMessage("BW Mode"); break; case Event::ConsoleLeftDiffA: - if(state) myOSystem->frameBuffer().showMessage("Left Difficulty A"); + if(state) myOSystem.frameBuffer().showMessage("Left Difficulty A"); break; case Event::ConsoleLeftDiffB: - if(state) myOSystem->frameBuffer().showMessage("Left Difficulty B"); + if(state) myOSystem.frameBuffer().showMessage("Left Difficulty B"); break; case Event::ConsoleRightDiffA: - if(state) myOSystem->frameBuffer().showMessage("Right Difficulty A"); + if(state) myOSystem.frameBuffer().showMessage("Right Difficulty A"); break; case Event::ConsoleRightDiffB: - if(state) myOSystem->frameBuffer().showMessage("Right Difficulty B"); + if(state) myOSystem.frameBuffer().showMessage("Right Difficulty B"); break; case Event::NoType: // Ignore unmapped events @@ -1261,7 +1261,7 @@ void EventHandler::setKeymap() { // Since istringstream swallows whitespace, we have to make the // delimiters be spaces - string list = myOSystem->settings().getString("keymap"); + string list = myOSystem.settings().getString("keymap"); replace(list.begin(), list.end(), ':', ' '); istringstream buf(list); @@ -1300,7 +1300,7 @@ void EventHandler::setJoymap() setDefaultJoymap(Event::NoType, kMenuMode); // Get all mappings from the settings - istringstream buf(myOSystem->settings().getString("joymap")); + istringstream buf(myOSystem.settings().getString("joymap")); string joymap; // First check the event type, and disregard the entire mapping if it's invalid @@ -1339,7 +1339,7 @@ void EventHandler::setComboMap() { // Since istringstream swallows whitespace, we have to make the // delimiters be spaces - string list = myOSystem->settings().getString("combomap"); + string list = myOSystem.settings().getString("combomap"); replace(list.begin(), list.end(), ':', ' '); istringstream buf(list); @@ -1623,7 +1623,7 @@ void EventHandler::setDefaultJoymap(Event::Type event, EventMode mode) else myJoysticks[i]->eraseEvent(event, mode); // only reset the specific event } - myOSystem->setDefaultJoymap(event, mode); + myOSystem.setDefaultJoymap(event, mode); setActionMappings(mode); #endif } @@ -1639,7 +1639,7 @@ void EventHandler::saveKeyMapping() for(int i = 0; i < KBDK_LAST; ++i) keybuf << ":" << myKeyTable[i][mode]; - myOSystem->settings().setValue("keymap", keybuf.str()); + myOSystem.settings().setValue("keymap", keybuf.str()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1674,7 +1674,7 @@ void EventHandler::saveJoyMapping() for(iter = myJoystickMap.begin(); iter != myJoystickMap.end(); ++iter) joybuf << "^" << iter->second; - myOSystem->settings().setValue("joymap", joybuf.str()); + myOSystem.settings().setValue("joymap", joybuf.str()); #endif } @@ -1692,7 +1692,7 @@ void EventHandler::saveComboMapping() for(int j = 1; j < kEventsPerCombo; ++j) buf << "," << myComboTable[i][j]; } - myOSystem->settings().setValue("combomap", buf.str()); + myOSystem.settings().setValue("combomap", buf.str()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1866,10 +1866,10 @@ void EventHandler::takeSnapshot(uInt32 number) // Figure out the correct snapshot name string filename; bool showmessage = number == 0; - string sspath = myOSystem->snapshotSaveDir() + - (myOSystem->settings().getString("snapname") != "int" ? - myOSystem->romFile().getNameWithExt("") - : myOSystem->console().properties().get(Cartridge_Name)); + string sspath = myOSystem.snapshotSaveDir() + + (myOSystem.settings().getString("snapname") != "int" ? + myOSystem.romFile().getNameWithExt("") + : myOSystem.console().properties().get(Cartridge_Name)); // Check whether we want multiple snapshots created if(number > 0) @@ -1878,7 +1878,7 @@ void EventHandler::takeSnapshot(uInt32 number) buf << sspath << "_" << hex << setw(8) << setfill('0') << number << ".png"; filename = buf.str(); } - else if(!myOSystem->settings().getBool("sssingle")) + else if(!myOSystem.settings().getBool("sssingle")) { // Determine if the file already exists, checking each successive filename // until one doesn't exist @@ -1902,35 +1902,35 @@ void EventHandler::takeSnapshot(uInt32 number) filename = sspath + ".png"; // Now create a PNG snapshot - if(myOSystem->settings().getBool("ss1x")) + if(myOSystem.settings().getBool("ss1x")) { string msg = - myOSystem->png().saveImage(filename, myOSystem->frameBuffer(), - myOSystem->console().tia(), - myOSystem->console().properties()); + myOSystem.png().saveImage(filename, myOSystem.frameBuffer(), + myOSystem.console().tia(), + myOSystem.console().properties()); if(showmessage) - myOSystem->frameBuffer().showMessage(msg); + myOSystem.frameBuffer().showMessage(msg); } else { // Make sure we have a 'clean' image, with no onscreen messages - myOSystem->frameBuffer().enableMessages(false); + myOSystem.frameBuffer().enableMessages(false); string msg = - myOSystem->png().saveImage(filename, myOSystem->frameBuffer(), - myOSystem->console().properties()); + myOSystem.png().saveImage(filename, myOSystem.frameBuffer(), + myOSystem.console().properties()); // Re-enable old messages - myOSystem->frameBuffer().enableMessages(true); + myOSystem.frameBuffer().enableMessages(true); if(showmessage) - myOSystem->frameBuffer().showMessage(msg); + myOSystem.frameBuffer().showMessage(msg); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::setMouseControllerMode(const string& enable) { - if(&myOSystem->console()) + if(&myOSystem.console()) { delete myMouseControl; myMouseControl = NULL; @@ -1941,7 +1941,7 @@ void EventHandler::setMouseControllerMode(const string& enable) usemouse = false; else // 'analog' { - switch(myOSystem->console().controller(Controller::Left).type()) + switch(myOSystem.console().controller(Controller::Left).type()) { case Controller::Paddles: case Controller::Driving: @@ -1954,7 +1954,7 @@ void EventHandler::setMouseControllerMode(const string& enable) default: break; } - switch(myOSystem->console().controller(Controller::Right).type()) + switch(myOSystem.console().controller(Controller::Right).type()) { case Controller::Paddles: case Controller::Driving: @@ -1970,9 +1970,9 @@ void EventHandler::setMouseControllerMode(const string& enable) } const string& control = usemouse ? - myOSystem->console().properties().get(Controller_MouseAxis) : "none"; + myOSystem.console().properties().get(Controller_MouseAxis) : "none"; - myMouseControl = new MouseControl(myOSystem->console(), control); + myMouseControl = new MouseControl(myOSystem.console(), control); myMouseControl->next(); // set first available mode } } @@ -1980,7 +1980,7 @@ void EventHandler::setMouseControllerMode(const string& enable) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::setContinuousSnapshots(uInt32 interval) { - myContSnapshotInterval = (uInt32) myOSystem->frameRate() * interval; + myContSnapshotInterval = (uInt32) myOSystem.frameRate() * interval; myContSnapshotCounter = 0; } @@ -1989,44 +1989,44 @@ void EventHandler::enterMenuMode(State state) { setEventState(state); myOverlay->reStack(); - myOSystem->sound().mute(true); + myOSystem.sound().mute(true); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::leaveMenuMode() { setEventState(S_EMULATE); - myOSystem->sound().mute(false); + myOSystem.sound().mute(false); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EventHandler::enterDebugMode() { #ifdef DEBUGGER_SUPPORT - if(myState == S_DEBUGGER || !(&myOSystem->console())) + if(myState == S_DEBUGGER || !(&myOSystem.console())) return false; // Make sure debugger starts in a consistent state // This absolutely *has* to come before we actually change to debugger // mode, since it takes care of locking the debugger state, which will // probably be modified below - myOSystem->debugger().setStartState(); + myOSystem.debugger().setStartState(); setEventState(S_DEBUGGER); - FBInitStatus fbstatus = myOSystem->createFrameBuffer(); + FBInitStatus fbstatus = myOSystem.createFrameBuffer(); if(fbstatus != kSuccess) { - myOSystem->debugger().setQuitState(); + myOSystem.debugger().setQuitState(); setEventState(S_EMULATE); if(fbstatus == kFailTooLarge) - myOSystem->frameBuffer().showMessage("Debugger window too large for screen", + myOSystem.frameBuffer().showMessage("Debugger window too large for screen", kBottomCenter, true); return false; } myOverlay->reStack(); - myOSystem->sound().mute(true); + myOSystem.sound().mute(true); #else - myOSystem->frameBuffer().showMessage("Debugger support not included", + myOSystem.frameBuffer().showMessage("Debugger support not included", kBottomCenter, true); #endif @@ -2042,11 +2042,11 @@ void EventHandler::leaveDebugMode() return; // Make sure debugger quits in a consistent state - myOSystem->debugger().setQuitState(); + myOSystem.debugger().setQuitState(); setEventState(S_EMULATE); - myOSystem->createFrameBuffer(); - myOSystem->sound().mute(false); + myOSystem.createFrameBuffer(); + myOSystem.sound().mute(false); #endif } @@ -2057,7 +2057,7 @@ void EventHandler::setEventState(State state) // Normally, the usage of Control key is determined by 'ctrlcombo' // For certain ROMs it may be forced off, whatever the setting - myUseCtrlKeyFlag = myOSystem->settings().getBool("ctrlcombo"); + myUseCtrlKeyFlag = myOSystem.settings().getBool("ctrlcombo"); // Only enable Unicode in GUI modes, since there we need it for ascii data // Otherwise, it causes a performance hit, so leave it off @@ -2065,37 +2065,37 @@ void EventHandler::setEventState(State state) { case S_EMULATE: myOverlay = NULL; - myOSystem->sound().mute(false); + myOSystem.sound().mute(false); //FIXME SDL_EnableUNICODE(0); - if(myOSystem->console().controller(Controller::Left).type() == + if(myOSystem.console().controller(Controller::Left).type() == Controller::CompuMate) myUseCtrlKeyFlag = false; break; case S_PAUSE: myOverlay = NULL; - myOSystem->sound().mute(true); + myOSystem.sound().mute(true); //FIXME SDL_EnableUNICODE(0); break; case S_MENU: - myOverlay = &myOSystem->menu(); + myOverlay = &myOSystem.menu(); //FIXME SDL_EnableUNICODE(1); break; case S_CMDMENU: - myOverlay = &myOSystem->commandMenu(); + myOverlay = &myOSystem.commandMenu(); //FIXME SDL_EnableUNICODE(1); break; case S_LAUNCHER: - myOverlay = &myOSystem->launcher(); + myOverlay = &myOSystem.launcher(); //FIXME SDL_EnableUNICODE(1); break; #ifdef DEBUGGER_SUPPORT case S_DEBUGGER: - myOverlay = &myOSystem->debugger(); + myOverlay = &myOSystem.debugger(); //FIXME SDL_EnableUNICODE(1); break; #endif @@ -2106,15 +2106,15 @@ void EventHandler::setEventState(State state) } // Inform various subsystems about the new state - myOSystem->stateChanged(myState); - if(&myOSystem->frameBuffer()) + myOSystem.stateChanged(myState); + if(&myOSystem.frameBuffer()) { - myOSystem->frameBuffer().stateChanged(myState); - myOSystem->frameBuffer().setCursorState(); + myOSystem.frameBuffer().stateChanged(myState); + myOSystem.frameBuffer().setCursorState(); } - if(&myOSystem->console()) + if(&myOSystem.console()) { - myOSystem->console().stateChanged(myState); + myOSystem.console().stateChanged(myState); } // Always clear any pending events when changing states diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx index 57498adc9..f611ebb7a 100644 --- a/src/emucore/EventHandler.hxx +++ b/src/emucore/EventHandler.hxx @@ -86,7 +86,7 @@ class EventHandler /** Create a new event handler object */ - EventHandler(OSystem* osystem); + EventHandler(OSystem& osystem); /** Destructor @@ -319,7 +319,7 @@ class EventHandler protected: // Global OSystem object - OSystem* myOSystem; + OSystem& myOSystem; /** Methods which are called by derived classes to handle specific types diff --git a/src/emucore/FBSurface.cxx b/src/emucore/FBSurface.cxx index 05ee22745..3b0b0fa22 100644 --- a/src/emucore/FBSurface.cxx +++ b/src/emucore/FBSurface.cxx @@ -21,9 +21,8 @@ #include "FBSurface.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -FBSurface::FBSurface(const uInt32* palette) - : myPalette(palette), - myPixels(NULL), +FBSurface::FBSurface() + : myPixels(NULL), myPitch(0) { // NOTE: myPixels and myPitch MUST be set in child classes that inherit @@ -278,3 +277,6 @@ void FBSurface::drawSurface(const FBSurface* surface) dst += myPitch; } } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const uInt32* FBSurface::myPalette = 0; diff --git a/src/emucore/FBSurface.hxx b/src/emucore/FBSurface.hxx index 647337771..e2b1575a3 100644 --- a/src/emucore/FBSurface.hxx +++ b/src/emucore/FBSurface.hxx @@ -21,6 +21,7 @@ #define FBSURFACE_HXX class FrameBuffer; +class TIASurface; #include "bspf.hxx" #include "Font.hxx" @@ -51,11 +52,13 @@ enum FrameStyle { class FBSurface { + friend class TIASurface; + public: /** Creates a new FBSurface object */ - FBSurface(const uInt32* palette); + FBSurface(); /** Destructor @@ -259,17 +262,6 @@ class FBSurface */ virtual void setStaticContents(const uInt32* pixels, uInt32 pitch) = 0; - /** - This method should be called to modify the interpolation and - blending effects to be applied to this surface. - - @param smoothScale Whether to use interpolation during scaling - @param useBlend Whether the surface should use alpha blending - @param blendAlpha The alpha to use during blending (if used) - */ - virtual void setInterpolationAndBlending(bool smoothScale, - bool useBlend, uInt32 blendAlpha) = 0; - /** This method should be called to translate the given coordinates to the (destination) surface coordinates. @@ -302,10 +294,35 @@ class FBSurface */ virtual void reload() = 0; + static void setPalette(const uInt32* palette) { myPalette = palette; } + protected: - const uInt32* myPalette; + /** + The rendering attributes that can be modified for this texture. + These probably can only be implemented in child FBSurfaces where + the specific functionality actually exists. + */ + struct Attributes { + bool smoothing; // Scaling is smoothed or blocky + bool blending; // Blending is enabled + uInt32 blendalpha; // Alpha to use in blending mode (0-100%) + }; + /** + The child class chooses which (if any) of the actual attributes + can be applied. + + @param immediate Whether to re-initialize the surface immediately + with the new attributes, or wait until manually + reloaded + */ + virtual void applyAttributes(bool immediate = true) = 0; + + protected: + static const uInt32* myPalette; uInt32* myPixels; uInt32 myPitch; + + Attributes myAttributes; }; #endif diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 70ebcef18..fb1ca2a7f 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -38,6 +38,7 @@ #include "TIA.hxx" #include "FBSurface.hxx" +#include "TIASurface.hxx" #include "FrameBuffer.hxx" #ifdef DEBUGGER_SUPPORT @@ -45,19 +46,15 @@ #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -FrameBuffer::FrameBuffer(OSystem* osystem) +FrameBuffer::FrameBuffer(OSystem& osystem) : myOSystem(osystem), myRedrawEntireFrame(true), - myUsePhosphor(false), - myPhosphorBlend(77), myInitializedCount(0), - myPausedCount(0) + myPausedCount(0), + myTIASurface(NULL) { myMsg.surface = myStatsMsg.surface = NULL; myMsg.enabled = myStatsMsg.enabled = false; - - // Load NTSC filter settings - myNTSCFilter.loadConfig(myOSystem->settings()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -67,6 +64,7 @@ FrameBuffer::~FrameBuffer(void) delete myInfoFont; delete mySmallFont; delete myLauncherFont; + delete myTIASurface; // Free all allocated surfaces while(!mySurfaceList.empty()) @@ -85,7 +83,7 @@ bool FrameBuffer::initialize() // Check the 'maxres' setting, which is an undocumented developer feature // that specifies the desktop size (not normally set) - const GUI::Size& s = myOSystem->settings().getSize("maxres"); + const GUI::Size& s = myOSystem.settings().getSize("maxres"); if(s.w > 0 && s.h > 0) { query_w = s.w; @@ -126,7 +124,7 @@ bool FrameBuffer::initialize() // very small screens if(!smallScreen) { - const string& lf = myOSystem->settings().getString("launcherfont"); + const string& lf = myOSystem.settings().getString("launcherfont"); if(lf == "small") myLauncherFont = new GUI::Font(GUI::consoleDesc); else if(lf == "medium") @@ -150,6 +148,20 @@ bool FrameBuffer::initialize() myTIAZoomLevels.push_back(desc.str(), zoom); } + // Set palette for GUI (upper area of array, doesn't change during execution) + for(int i = 0, j = 256; i < kNumColors-256; ++i, ++j) + { + Uint8 r = (ourGUIColors[i] >> 16) & 0xff; + Uint8 g = (ourGUIColors[i] >> 8) & 0xff; + Uint8 b = ourGUIColors[i] & 0xff; + + myPalette[j] = mapRGB(r, g, b); + } + FBSurface::setPalette(myPalette); + + // Create a TIA surface; we need it for rendering TIA images + myTIASurface = new TIASurface(*this, myOSystem); + return true; } @@ -181,7 +193,7 @@ FBInitStatus FrameBuffer::createDisplay(const string& title, return kFailTooLarge; // FIXSDL - remove size limitations here? - if(myOSystem->settings().getString("fullscreen") == "1") + if(myOSystem.settings().getString("fullscreen") == "1") { if(myDesktopSize.w < width || myDesktopSize.h < height) return kFailTooLarge; @@ -208,15 +220,21 @@ FBInitStatus FrameBuffer::createDisplay(const string& title, myScreenSize = mode.screen; if(width <= (uInt32)myScreenSize.w && height <= (uInt32)myScreenSize.h) { - if(setVideoMode(myScreenTitle, mode, useFullscreen)) + if(setVideoMode(myScreenTitle, mode)) { + // Inform TIA surface about new mode + if(myOSystem.eventHandler().state() != EventHandler::S_LAUNCHER && + myOSystem.eventHandler().state() != EventHandler::S_DEBUGGER) + myTIASurface->initialize(myOSystem.console(), mode); + // Did we get the requested fullscreen state? - myOSystem->settings().setValue("fullscreen", fullScreen()); + myOSystem.settings().setValue("fullscreen", fullScreen()); + resetSurfaces(); setCursorState(); } else { - myOSystem->logMessage("ERROR: Couldn't initialize video subsystem", 0); + myOSystem.logMessage("ERROR: Couldn't initialize video subsystem", 0); return kFailNotSupported; } } @@ -245,15 +263,14 @@ FBInitStatus FrameBuffer::createDisplay(const string& title, // Take care of some items that are only done once per framebuffer creation. if(myInitializedCount == 1) { - myOSystem->logMessage(about(), 1); - setUIPalette(); + myOSystem.logMessage(about(), 1); setWindowIcon(); } else { string post_about = about(); if(post_about != pre_about) - myOSystem->logMessage(post_about, 1); + myOSystem.logMessage(post_about, 1); } return kSuccess; @@ -265,31 +282,31 @@ void FrameBuffer::update() // Determine which mode we are in (from the EventHandler) // Take care of S_EMULATE mode here, otherwise let the GUI // figure out what to draw - switch(myOSystem->eventHandler().state()) + switch(myOSystem.eventHandler().state()) { case EventHandler::S_EMULATE: { // Run the console for one frame // Note that the debugger can cause a breakpoint to occur, which changes // the EventHandler state 'behind our back' - we need to check for that - myOSystem->console().tia().update(); + myOSystem.console().tia().update(); #ifdef DEBUGGER_SUPPORT - if(myOSystem->eventHandler().state() != EventHandler::S_EMULATE) break; + if(myOSystem.eventHandler().state() != EventHandler::S_EMULATE) break; #endif - if(myOSystem->eventHandler().frying()) - myOSystem->console().fry(); + if(myOSystem.eventHandler().frying()) + myOSystem.console().fry(); // And update the screen - drawTIA(myRedrawEntireFrame); + drawTIA(); // Show frame statistics if(myStatsMsg.enabled) { - const ConsoleInfo& info = myOSystem->console().about(); + const ConsoleInfo& info = myOSystem.console().about(); char msg[30]; BSPF_snprintf(msg, 30, "%3u @ %3.2ffps => %s", - myOSystem->console().tia().scanlines(), - myOSystem->console().getFramerate(), info.DisplayFormat.c_str()); + myOSystem.console().tia().scanlines(), + myOSystem.console().getFramerate(), info.DisplayFormat.c_str()); myStatsMsg.surface->fillRect(0, 0, myStatsMsg.w, myStatsMsg.h, kBGColor); myStatsMsg.surface->drawString(infoFont(), msg, 1, 1, myStatsMsg.w, myStatsMsg.color, kTextAlignLeft); @@ -306,10 +323,10 @@ void FrameBuffer::update() { // Only update the screen if it's been invalidated if(myRedrawEntireFrame) - drawTIA(true); + drawTIA(); // Show a pause message every 5 seconds - if(myPausedCount++ >= 7*myOSystem->frameRate()) + if(myPausedCount++ >= 7*myOSystem.frameRate()) { myPausedCount = 0; showMessage("Paused", kMiddleCenter); @@ -321,7 +338,7 @@ void FrameBuffer::update() { // When onscreen messages are enabled in double-buffer mode, // a full redraw is required - myOSystem->menu().draw(myMsg.enabled && isDoubleBuffered()); + myOSystem.menu().draw(myMsg.enabled && isDoubleBuffered()); break; // S_MENU } @@ -329,7 +346,7 @@ void FrameBuffer::update() { // When onscreen messages are enabled in double-buffer mode, // a full redraw is required - myOSystem->commandMenu().draw(myMsg.enabled && isDoubleBuffered()); + myOSystem.commandMenu().draw(myMsg.enabled && isDoubleBuffered()); break; // S_CMDMENU } @@ -337,7 +354,7 @@ void FrameBuffer::update() { // When onscreen messages are enabled in double-buffer mode, // a full redraw is required - myOSystem->launcher().draw(myMsg.enabled && isDoubleBuffered()); + myOSystem.launcher().draw(myMsg.enabled && isDoubleBuffered()); break; // S_LAUNCHER } @@ -346,7 +363,7 @@ void FrameBuffer::update() { // When onscreen messages are enabled in double-buffer mode, // a full redraw is required - myOSystem->debugger().draw(myMsg.enabled && isDoubleBuffered()); + myOSystem.debugger().draw(myMsg.enabled && isDoubleBuffered()); break; // S_DEBUGGER } #endif @@ -371,7 +388,7 @@ void FrameBuffer::showMessage(const string& message, MessagePosition position, bool force) { // Only show messages if they've been enabled - if(!(force || myOSystem->settings().getBool("uimessages"))) + if(!(force || myOSystem.settings().getBool("uimessages"))) return; // Erase old messages on the screen @@ -383,7 +400,7 @@ void FrameBuffer::showMessage(const string& message, MessagePosition position, // Precompute the message coordinates myMsg.text = message; - myMsg.counter = uInt32(myOSystem->frameRate()) << 1; // Show message for 2 seconds + myMsg.counter = uInt32(myOSystem.frameRate()) << 1; // Show message for 2 seconds myMsg.color = kBtnTextColor; myMsg.w = font().getStringWidth(myMsg.text) + 10; @@ -397,13 +414,13 @@ void FrameBuffer::showMessage(const string& message, MessagePosition position, // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::toggleFrameStats() { - showFrameStats(!myOSystem->settings().getBool("stats")); + showFrameStats(!myOSystem.settings().getBool("stats")); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::showFrameStats(bool enable) { - myOSystem->settings().setValue("stats", enable); + myOSystem.settings().setValue("stats", enable); myStatsMsg.enabled = enable; refresh(); } @@ -414,7 +431,7 @@ void FrameBuffer::enableMessages(bool enable) if(enable) { // Only re-enable frame stats if they were already enabled before - myStatsMsg.enabled = myOSystem->settings().getBool("stats"); + myStatsMsg.enabled = myOSystem.settings().getBool("stats"); } else { @@ -502,6 +519,15 @@ inline void FrameBuffer::drawMessage() } } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +inline void FrameBuffer::drawTIA() +{ + myTIASurface->render(); + + // Let postFrameUpdate() know that a change has been made +//FIXSDL invalidate(); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::refresh() { @@ -514,66 +540,66 @@ void FrameBuffer::refresh() // This method is in essence a FULL refresh, putting all rendering // buffers in a known, fully redrawn state - switch(myOSystem->eventHandler().state()) + switch(myOSystem.eventHandler().state()) { case EventHandler::S_EMULATE: case EventHandler::S_PAUSE: invalidate(); - drawTIA(true); + drawTIA(); if(isDoubleBuffered()) { postFrameUpdate(); invalidate(); - drawTIA(true); + drawTIA(); } break; case EventHandler::S_MENU: invalidate(); - drawTIA(true); - myOSystem->menu().draw(true); + drawTIA(); + myOSystem.menu().draw(true); if(isDoubleBuffered()) { postFrameUpdate(); invalidate(); - drawTIA(true); - myOSystem->menu().draw(true); + drawTIA(); + myOSystem.menu().draw(true); } break; case EventHandler::S_CMDMENU: invalidate(); - drawTIA(true); - myOSystem->commandMenu().draw(true); + drawTIA(); + myOSystem.commandMenu().draw(true); if(isDoubleBuffered()) { postFrameUpdate(); invalidate(); - drawTIA(true); - myOSystem->commandMenu().draw(true); + drawTIA(); + myOSystem.commandMenu().draw(true); } break; case EventHandler::S_LAUNCHER: invalidate(); - myOSystem->launcher().draw(true); + myOSystem.launcher().draw(true); if(isDoubleBuffered()) { postFrameUpdate(); invalidate(); - myOSystem->launcher().draw(true); + myOSystem.launcher().draw(true); } break; #ifdef DEBUGGER_SUPPORT case EventHandler::S_DEBUGGER: invalidate(); - myOSystem->debugger().draw(true); + myOSystem.debugger().draw(true); if(isDoubleBuffered()) { postFrameUpdate(); invalidate(); - myOSystem->debugger().draw(true); + myOSystem.debugger().draw(true); } break; #endif @@ -583,59 +609,6 @@ void FrameBuffer::refresh() } } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBuffer::setNTSC(NTSCFilter::Preset preset, bool show) -{ - ostringstream buf; - if(preset == NTSCFilter::PRESET_OFF) - { - enableNTSC(false); - buf << "TV filtering disabled"; - } - else - { - enableNTSC(true); - const string& mode = myNTSCFilter.setPreset(preset); - buf << "TV filtering (" << mode << " mode)"; - } - myOSystem->settings().setValue("tv.filter", (int)preset); - - if(show) showMessage(buf.str()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBuffer::setScanlineIntensity(int amount) -{ - ostringstream buf; - if(ntscEnabled()) - { - uInt32 intensity = enableScanlines(amount); - buf << "Scanline intensity at " << intensity << "%"; - myOSystem->settings().setValue("tv.scanlines", intensity); - } - else - buf << "Scanlines only available in TV filtering mode"; - - showMessage(buf.str()); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBuffer::toggleScanlineInterpolation() -{ - ostringstream buf; - if(ntscEnabled()) - { - bool enable = !myOSystem->settings().getBool("tv.scaninter"); - enableScanlineInterpolation(enable); - buf << "Scanline interpolation " << (enable ? "enabled" : "disabled"); - myOSystem->settings().setValue("tv.scaninter", enable); - } - else - buf << "Scanlines only available in TV filtering mode"; - - showMessage(buf.str()); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 FrameBuffer::allocateSurface(int w, int h) { @@ -646,7 +619,7 @@ uInt32 FrameBuffer::allocateSurface(int w, int h) mySurfaceList.insert(make_pair((uInt32)mySurfaceList.size(), surface)); // Return a reference to it - return mySurfaceList.size() - 1; + return (uInt32)mySurfaceList.size() - 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -657,7 +630,7 @@ FBSurface* FrameBuffer::surface(uInt32 id) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBuffer::resetSurfaces(FBSurface* tiasurface) +void FrameBuffer::resetSurfaces() { // Free all resources for each surface, then reload them // Due to possible timing and/or synchronization issues, all free()'s @@ -668,75 +641,30 @@ void FrameBuffer::resetSurfaces(FBSurface* tiasurface) map::iterator iter; for(iter = mySurfaceList.begin(); iter != mySurfaceList.end(); ++iter) iter->second->free(); - if(tiasurface) - tiasurface->free(); for(iter = mySurfaceList.begin(); iter != mySurfaceList.end(); ++iter) iter->second->reload(); - if(tiasurface) - tiasurface->reload(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 FrameBuffer::tiaPixel(uInt32 idx, uInt8 shift) const +void FrameBuffer::setPalette(const uInt32* palette) { - uInt8 c = *(myOSystem->console().tia().currentFrameBuffer() + idx) | shift; - uInt8 p = *(myOSystem->console().tia().previousFrameBuffer() + idx) | shift; - - return (!myUsePhosphor ? myDefPalette[c] : myAvgPalette[c][p]); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBuffer::setTIAPalette(const uInt32* palette) -{ - int i, j; - +cerr << "FrameBuffer::setPalette\n"; // Set palette for normal fill - for(i = 0; i < 256; ++i) + for(int i = 0; i < 256; ++i) { Uint8 r = (palette[i] >> 16) & 0xff; Uint8 g = (palette[i] >> 8) & 0xff; Uint8 b = palette[i] & 0xff; - myDefPalette[i] = mapRGB(r, g, b); + myPalette[i] = mapRGB(r, g, b); } - // Set palette for phosphor effect - for(i = 0; i < 256; ++i) - { - for(j = 0; j < 256; ++j) - { - uInt8 ri = (palette[i] >> 16) & 0xff; - uInt8 gi = (palette[i] >> 8) & 0xff; - uInt8 bi = palette[i] & 0xff; - uInt8 rj = (palette[j] >> 16) & 0xff; - uInt8 gj = (palette[j] >> 8) & 0xff; - uInt8 bj = palette[j] & 0xff; - - Uint8 r = (Uint8) getPhosphor(ri, rj); - Uint8 g = (Uint8) getPhosphor(gi, gj); - Uint8 b = (Uint8) getPhosphor(bi, bj); - - myAvgPalette[i][j] = mapRGB(r, g, b); - } - } + // Let the TIA surface know about the new palette + myTIASurface->setPalette(myPalette, palette); myRedrawEntireFrame = true; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBuffer::setUIPalette() -{ - // Set palette for GUI - for(int i = 0, j = 256; i < kNumColors-256; ++i, ++j) - { - Uint8 r = (ourGUIColors[i] >> 16) & 0xff; - Uint8 g = (ourGUIColors[i] >> 8) & 0xff; - Uint8 b = ourGUIColors[i] & 0xff; - - myDefPalette[j] = mapRGB(r, g, b); - } -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::stateChanged(EventHandler::State state) { @@ -758,7 +686,7 @@ enableFullscreen(enable); #if 0 //FIXSDL #ifdef WINDOWED_SUPPORT // '-1' means fullscreen mode is completely disabled - bool full = enable && myOSystem->settings().getString("fullscreen") != "-1"; + bool full = enable && myOSystem.settings().getString("fullscreen") != "-1"; setHint(kFullScreen, full); // Do a dummy call to getSavedVidMode to set up the modelists @@ -782,7 +710,7 @@ void FrameBuffer::toggleFullscreen() bool FrameBuffer::changeWindowedVidMode(int direction) { #ifdef WINDOWED_SUPPORT - EventHandler::State state = myOSystem->eventHandler().state(); + EventHandler::State state = myOSystem.eventHandler().state(); bool tiaMode = (state != EventHandler::S_DEBUGGER && state != EventHandler::S_LAUNCHER); @@ -800,10 +728,11 @@ bool FrameBuffer::changeWindowedVidMode(int direction) const VideoMode& mode = myCurrentModeList->current(); myImageRect = mode.image; myScreenSize = mode.screen; - if(setVideoMode(myScreenTitle, mode, false)) + if(setVideoMode(myScreenTitle, mode)) { + resetSurfaces(); showMessage(mode.description); - myOSystem->settings().setValue("tia.zoom", mode.zoom); + myOSystem.settings().setValue("tia.zoom", mode.zoom); refresh(); return true; } @@ -817,29 +746,20 @@ void FrameBuffer::setCursorState() // Always grab mouse in fullscreen or during emulation (if enabled), // and don't show the cursor during emulation bool emulation = - myOSystem->eventHandler().state() == EventHandler::S_EMULATE; + myOSystem.eventHandler().state() == EventHandler::S_EMULATE; grabMouse(fullScreen() || - (emulation && myOSystem->settings().getBool("grabmouse"))); + (emulation && myOSystem.settings().getBool("grabmouse"))); showCursor(!emulation); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::toggleGrabMouse() { - bool state = myOSystem->settings().getBool("grabmouse"); - myOSystem->settings().setValue("grabmouse", !state); + bool state = myOSystem.settings().getBool("grabmouse"); + myOSystem.settings().setValue("grabmouse", !state); setCursorState(); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 FrameBuffer::getPhosphor(uInt8 c1, uInt8 c2) const -{ - if(c2 > c1) - BSPF_swap(c1, c2); - - return ((c1 - c2) * myPhosphorBlend)/100 + c2; -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 FrameBuffer::maxWindowSizeForScreen(uInt32 baseWidth, uInt32 baseHeight, uInt32 screenWidth, uInt32 screenHeight) @@ -867,7 +787,7 @@ void FrameBuffer::setAvailableVidModes(uInt32 baseWidth, uInt32 baseHeight) // Check if zooming is allowed for this state (currently only allowed // for TIA screens) - EventHandler::State state = myOSystem->eventHandler().state(); + EventHandler::State state = myOSystem.eventHandler().state(); bool tiaMode = (state != EventHandler::S_DEBUGGER && state != EventHandler::S_LAUNCHER); @@ -880,8 +800,8 @@ void FrameBuffer::setAvailableVidModes(uInt32 baseWidth, uInt32 baseHeight) myDesktopSize.w, myDesktopSize.h); // Aspect ratio - bool ntsc = myOSystem->console().about().InitialFrameRate == "60"; - uInt32 aspect = myOSystem->settings().getInt(ntsc ? + bool ntsc = myOSystem.console().about().InitialFrameRate == "60"; + uInt32 aspect = myOSystem.settings().getInt(ntsc ? "tia.aspectn" : "tia.aspectp"); // Figure our the smallest zoom level we can use @@ -925,9 +845,9 @@ cerr << "Windowed modes:\n" << myWindowedModeList << endl } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const FrameBuffer::VideoMode& FrameBuffer::getSavedVidMode(bool fullscreen) +const VideoMode& FrameBuffer::getSavedVidMode(bool fullscreen) { - EventHandler::State state = myOSystem->eventHandler().state(); + EventHandler::State state = myOSystem.eventHandler().state(); if(fullscreen) myCurrentModeList = &myFullscreenModeList; @@ -940,7 +860,7 @@ const FrameBuffer::VideoMode& FrameBuffer::getSavedVidMode(bool fullscreen) if(state == EventHandler::S_DEBUGGER || state == EventHandler::S_LAUNCHER) myCurrentModeList->setZoom(1); else - myCurrentModeList->setZoom(myOSystem->settings().getInt("tia.zoom")); + myCurrentModeList->setZoom(myOSystem.settings().getInt("tia.zoom")); return myCurrentModeList->current(); } @@ -950,7 +870,7 @@ const FrameBuffer::VideoMode& FrameBuffer::getSavedVidMode(bool fullscreen) // VideoMode implementation // // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -FrameBuffer::VideoMode::VideoMode() +VideoMode::VideoMode() : fullscreen(false), zoom(1), description("") @@ -958,7 +878,7 @@ FrameBuffer::VideoMode::VideoMode() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -FrameBuffer::VideoMode::VideoMode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh, +VideoMode::VideoMode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh, bool full, uInt32 z, const string& desc) : fullscreen(full), zoom(z), @@ -975,7 +895,7 @@ FrameBuffer::VideoMode::VideoMode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void FrameBuffer::VideoMode::applyAspectCorrection(uInt32 aspect, uInt32 stretch) +void VideoMode::applyAspectCorrection(uInt32 aspect, uInt32 stretch) { // Width is modified by aspect ratio; other factors may be applied below uInt32 iw = (uInt32)(float(image.width() * aspect) / 100.0); @@ -993,7 +913,7 @@ void FrameBuffer::VideoMode::applyAspectCorrection(uInt32 aspect, uInt32 stretch float scaleY = float(mode.image_h) / mode.screen_h; // Scale to actual or integral factors - if(myOSystem->settings().getBool("gl_fsscale")) + if(myOSystem.settings().getBool("gl_fsscale")) { // Scale to full (non-integral) available space if(scaleX > scaleY) @@ -1084,7 +1004,7 @@ void FrameBuffer::VideoModeList::previous() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const FrameBuffer::VideoMode& FrameBuffer::VideoModeList::current() const +const VideoMode& FrameBuffer::VideoModeList::current() const { return myModeList[myIdx]; } diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index d9e257c89..0450678ce 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -30,12 +30,12 @@ namespace GUI { class Font; } -#include "FBSurface.hxx" #include "EventHandler.hxx" #include "Rect.hxx" #include "StringList.hxx" -#include "NTSCFilter.hxx" #include "Variant.hxx" +#include "FBSurface.hxx" +#include "TIASurface.hxx" #include "bspf.hxx" // Return values for initialization of framebuffer window @@ -85,6 +85,39 @@ enum { kNumColors }; +// Contains all relevant info for the dimensions of a video screen +// Also takes care of the case when the image should be 'centered' +// within the given screen: +// 'image' is the image dimensions into the screen +// 'screen' are the dimensions of the screen itself +class VideoMode +{ + friend class FrameBuffer; + + public: + GUI::Rect image; + GUI::Size screen; + bool fullscreen; + uInt32 zoom; + string description; + + public: + VideoMode(); + VideoMode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh, bool full, + uInt32 z = 1, const string& desc = ""); + + friend ostream& operator<<(ostream& os, const VideoMode& vm) + { + os << "image=" << vm.image << " screen=" << vm.screen << endl + << "full= " << vm.fullscreen << " zoom=" << vm.zoom + << " desc=" << vm.description; + return os; + } + + private: + void applyAspectCorrection(uInt32 aspect, uInt32 stretch = false); +}; + /** This class encapsulates all video buffers and is the basis for the video display in Stella. All graphics ports should derive from this class for @@ -107,7 +140,7 @@ class FrameBuffer /** Creates a new Frame Buffer */ - FrameBuffer(OSystem* osystem); + FrameBuffer(OSystem& osystem); /** Destructor @@ -210,6 +243,11 @@ class FrameBuffer */ const VariantList& supportedRenderers() const { return myRenderers; } + /** + Get the supported TIA zoom levels (windowed mode) for the framebuffer. + */ + const VariantList& supportedTIAZoomLevels() const { return myTIAZoomLevels; } + /** Get the font object(s) of the framebuffer */ @@ -218,6 +256,11 @@ class FrameBuffer const GUI::Font& smallFont() const { return *mySmallFont; } const GUI::Font& launcherFont() const { return *myLauncherFont; } + /** + Get the TIA surface associated with the framebuffer. + */ + TIASurface& tiaSurface() const { return *myTIASurface; } + /** Refresh display according to the current state, taking single vs. double-buffered modes into account, and redrawing accordingly. @@ -256,91 +299,18 @@ class FrameBuffer */ void toggleGrabMouse(); - /** - Get the supported TIA zoom levels (windowed mode) for the framebuffer. - */ - const VariantList& supportedTIAZoomLevels() { return myTIAZoomLevels; } - - /** - Get the TIA pixel associated with the given TIA buffer index, - shifting by the given offset (for greyscale values). - */ - uInt32 tiaPixel(uInt32 idx, uInt8 shift = 0) const; - /** Set up the TIA/emulation palette for a screen of any depth > 8. @param palette The array of colors */ - virtual void setTIAPalette(const uInt32* palette); + void setPalette(const uInt32* palette); /** Informs the Framebuffer of a change in EventHandler state. */ void stateChanged(EventHandler::State state); - /** - Get the NTSCFilter object associated with the framebuffer - */ - NTSCFilter& ntsc() { return myNTSCFilter; } - - /** - Use NTSC filtering effects specified by the given preset. - */ - void setNTSC(NTSCFilter::Preset preset, bool show = true); - - /** - Increase/decrease current scanline intensity by given relative amount. - */ - void setScanlineIntensity(int relative); - - /** - Toggles interpolation/smoothing of scanlines in TV modes. - */ - void toggleScanlineInterpolation(); - - /** - Used to calculate an averaged color for the 'phosphor' effect. - - @param c1 Color 1 - @param c2 Color 2 - - @return Averaged value of the two colors - */ - uInt8 getPhosphor(uInt8 c1, uInt8 c2) const; - - // Contains all relevant info for the dimensions of a video screen - // Also takes care of the case when the image should be 'centered' - // within the given screen: - // 'image' is the image dimensions into the screen - // 'screen' are the dimensions of the screen itself - class VideoMode - { - friend class FrameBuffer; - - public: - GUI::Rect image; - GUI::Size screen; - bool fullscreen; - uInt32 zoom; - string description; - - public: - VideoMode(); - VideoMode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh, bool full, - uInt32 z = 1, const string& desc = ""); - - friend ostream& operator<<(ostream& os, const VideoMode& vm) - { - os << "image=" << vm.image << " screen=" << vm.screen << endl - << "desc=" << vm.description << " zoom=" << vm.zoom; - return os; - } - - private: - void applyAspectCorrection(uInt32 aspect, uInt32 stretch = false); - }; - ////////////////////////////////////////////////////////////////////// // The following methods are system-specific and can/must be // implemented in derived classes. @@ -356,18 +326,6 @@ class FrameBuffer */ virtual bool fullScreen() const = 0; - /** - Enable/disable/query NTSC filtering effects. - */ - virtual void enableNTSC(bool enable) { } - virtual bool ntscEnabled() const { return false; } - virtual string effectsInfo() const { return "None / not available"; } - - /** - Enable/disable phosphor effect. - */ - virtual void enablePhosphor(bool enable, int blend) = 0; - /** This method is called to retrieve the R/G/B data from the given pixel. @@ -411,16 +369,14 @@ class FrameBuffer virtual void queryHardware(uInt32& w, uInt32& h, VariantList& ren) = 0; /** - This method is called to change to the given video mode. If the mode - is successfully changed, 'mode' holds the actual dimensions used. + This method is called to change to the given video mode. @param title The title for the created window @param mode The video mode to use - @param full Whether this is a fullscreen or windowed mode @return False on any errors, else true */ - virtual bool setVideoMode(const string& title, const VideoMode& mode, bool full) = 0; + virtual bool setVideoMode(const string& title, const VideoMode& mode) = 0; /** Enables/disables fullscreen mode. @@ -444,16 +400,6 @@ class FrameBuffer */ virtual FBSurface* createSurface(uInt32 w, uInt32 h) const = 0; - /** - Change scanline intensity and interpolation. - - @param relative If non-zero, change current intensity by - 'relative' amount, otherwise set to 'absolute' - @return New current intensity - */ - virtual uInt32 enableScanlines(int relative, int absolute = 50) { return absolute; } - virtual void enableScanlineInterpolation(bool enable) { } - /** Grabs or ungrabs the mouse based on the given boolean value. */ @@ -464,12 +410,6 @@ class FrameBuffer */ virtual void setWindowIcon() = 0; - /** - This method should be called anytime the TIA needs to be redrawn - to the screen (full indicating that a full redraw is required). - */ - virtual void drawTIA(bool full) = 0; - /** This method is called after any drawing is done (per-frame). */ @@ -480,35 +420,15 @@ class FrameBuffer */ virtual string about() const = 0; - /** - Issues a 'free' and 'reload' instruction to all surfaces that the - framebuffer knows about. - */ - void resetSurfaces(FBSurface* tiasurface = (FBSurface*)0); - protected: // The parent system for the framebuffer - OSystem* myOSystem; + OSystem& myOSystem; // 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; - - // Amount to blend when using phosphor effect - int myPhosphorBlend; - - // TIA palettes for normal and phosphor modes - // 'myDefPalette' also contains the UI palette - Uint32 myDefPalette[256+kNumColors]; - Uint32 myAvgPalette[256][256]; - - // Names of the TIA zoom levels that can be used for this framebuffer - VariantList myTIAZoomLevels; + // Color palette for TIA and UI modes + Uint32 myPalette[256+kNumColors]; private: /** @@ -516,6 +436,18 @@ class FrameBuffer */ void drawMessage(); + /** + This method should be called anytime the TIA needs to be redrawn + to the screen. + */ + void drawTIA(); + + /** + Issues a 'free' and 'reload' instruction to all surfaces that the + framebuffer knows about. + */ + void resetSurfaces(); + /** Calculate the maximum level by which the base window can be zoomed and still fit in the given screen dimensions. @@ -544,11 +476,6 @@ class FrameBuffer */ const VideoMode& getSavedVidMode(bool fullscreen); - /** - Set up the user interface palette for a screen of any depth > 8. - */ - void setUIPalette(); - private: /** This class implements an iterator around an array of VideoMode objects. @@ -566,7 +493,7 @@ class FrameBuffer uInt32 size() const; void previous(); - const FrameBuffer::VideoMode& current() const; + const VideoMode& current() const; void next(); void setZoom(uInt32 zoom); @@ -619,6 +546,9 @@ class FrameBuffer // The font object to use for the ROM launcher GUI::Font* myLauncherFont; + // The TIASurface class takes responsibility for TIA rendering + TIASurface* myTIASurface; + // Used for onscreen messages and frame statistics // (scanline count and framerate) struct Message { @@ -638,6 +568,9 @@ class FrameBuffer VideoModeList myFullscreenModeList; VideoModeList* myCurrentModeList; + // Names of the TIA zoom levels that can be used for this framebuffer + VariantList myTIAZoomLevels; + // Holds a reference to all the surfaces that have been created map mySurfaceList; diff --git a/src/emucore/MediaFactory.hxx b/src/emucore/MediaFactory.hxx index 139193169..9e7f429f6 100644 --- a/src/emucore/MediaFactory.hxx +++ b/src/emucore/MediaFactory.hxx @@ -74,7 +74,7 @@ class MediaFactory #endif } - static Settings* createSettings(OSystem* osystem) + static Settings* createSettings(OSystem& osystem) { #if defined(BSPF_UNIX) return new SettingsUNIX(osystem); @@ -87,12 +87,12 @@ class MediaFactory #endif } - static FrameBuffer* createVideo(OSystem* osystem) + static FrameBuffer* createVideo(OSystem& osystem) { return new FrameBufferSDL2(osystem); } - static Sound* createAudio(OSystem* osystem) + static Sound* createAudio(OSystem& osystem) { #ifdef SOUND_SUPPORT return new SoundSDL2(osystem); @@ -101,7 +101,7 @@ class MediaFactory #endif } - static EventHandler* createEventHandler(OSystem* osystem) + static EventHandler* createEventHandler(OSystem& osystem) { return new EventHandlerSDL2(osystem); } diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index 518c916a5..ff7d0dffd 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -115,7 +115,7 @@ OSystem::OSystem() << " [" << BSPF_ARCH << "]"; myBuildInfo = info.str(); - mySettings = MediaFactory::createSettings(this); + mySettings = MediaFactory::createSettings(*this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -174,12 +174,12 @@ bool OSystem::create() // Get relevant information about the video hardware // This must be done before any graphics context is created, since // it may be needed to initialize the size of graphical objects - myFrameBuffer = MediaFactory::createVideo(this); + myFrameBuffer = MediaFactory::createVideo(*this); if(!myFrameBuffer->initialize()) return false; // Create the event handler for the system - myEventHandler = MediaFactory::createEventHandler(this); + myEventHandler = MediaFactory::createEventHandler(*this); myEventHandler->initialize(); // Create a properties set for us to use and set it up @@ -238,7 +238,7 @@ void OSystem::saveConfig() { // Ask all subsystems to save their settings if(myFrameBuffer) - myFrameBuffer->ntsc().saveConfig(*mySettings); + myFrameBuffer->tiaSurface().ntsc().saveConfig(*mySettings); mySettings->saveConfig(); } @@ -352,7 +352,7 @@ FBInitStatus OSystem::createFrameBuffer() void OSystem::createSound() { if(!mySound) - mySound = MediaFactory::createAudio(this); + mySound = MediaFactory::createAudio(*this); #ifndef SOUND_SUPPORT mySettings->setValue("sound", false); #endif @@ -626,7 +626,7 @@ Console* OSystem::openConsole(const FilesystemNode& romfile, string& md5, // Finally, create the cart with the correct properties if(cart) - console = new Console(this, cart, props); + console = new Console(*this, *cart, props); } // Free the image since we don't need it any longer diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index e204ae606..e4f2f83f6 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -34,7 +34,7 @@ #include "Settings.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Settings::Settings(OSystem* osystem) +Settings::Settings(OSystem& osystem) : myOSystem(osystem) { // Video-related options @@ -165,10 +165,10 @@ void Settings::loadConfig() string line, key, value; string::size_type equalPos, garbage; - ifstream in(myOSystem->configFile().c_str()); + ifstream in(myOSystem.configFile().c_str()); if(!in || !in.is_open()) { - myOSystem->logMessage("ERROR: Couldn't load settings file", 0); + myOSystem.logMessage("ERROR: Couldn't load settings file", 0); return; } @@ -236,7 +236,7 @@ string Settings::loadCommandLine(int argc, char** argv) if(++i >= argc) { buf << "Missing argument for '" << key << "'" << endl; - myOSystem->logMessage(buf.str(), 0); + myOSystem.logMessage(buf.str(), 0); return ""; } string value = argv[i]; @@ -257,7 +257,7 @@ string Settings::loadCommandLine(int argc, char** argv) buf << "(E)\n"; } - myOSystem->logMessage(buf.str(), 2); + myOSystem.logMessage(buf.str(), 2); } else return key; @@ -513,10 +513,10 @@ void Settings::saveConfig() if(!settingsChanged) return; - ofstream out(myOSystem->configFile().c_str()); + ofstream out(myOSystem.configFile().c_str()); if(!out || !out.is_open()) { - myOSystem->logMessage("ERROR: Couldn't save settings file", 0); + myOSystem.logMessage("ERROR: Couldn't save settings file", 0); return; } @@ -674,7 +674,8 @@ int Settings::setExternal(const string& key, const Variant& value, } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Settings::Settings(const Settings&) +Settings::Settings(const Settings& s) + : myOSystem(s.myOSystem) { } diff --git a/src/emucore/Settings.hxx b/src/emucore/Settings.hxx index eec660bda..c2b73b4d6 100644 --- a/src/emucore/Settings.hxx +++ b/src/emucore/Settings.hxx @@ -40,7 +40,7 @@ class Settings /** Create a new settings abstract class */ - Settings(OSystem* osystem); + Settings(OSystem& osystem); /** Destructor @@ -122,7 +122,7 @@ class Settings protected: // The parent OSystem object - OSystem* myOSystem; + OSystem& myOSystem; // Structure used for storing settings struct Setting diff --git a/src/emucore/Sound.hxx b/src/emucore/Sound.hxx index 650a2ea09..777bfc493 100644 --- a/src/emucore/Sound.hxx +++ b/src/emucore/Sound.hxx @@ -39,7 +39,7 @@ class Sound : public Serializable Create a new sound object. The init method must be invoked before using the object. */ - Sound(OSystem* osystem) { myOSystem = osystem; } + Sound(OSystem& osystem) : myOSystem(osystem) { } /** Destructor @@ -129,7 +129,7 @@ class Sound : public Serializable protected: // The OSystem for this sound object - OSystem* myOSystem; + OSystem& myOSystem; }; #endif diff --git a/src/emucore/TIASurface.cxx b/src/emucore/TIASurface.cxx new file mode 100644 index 000000000..1f60e4285 --- /dev/null +++ b/src/emucore/TIASurface.cxx @@ -0,0 +1,371 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +// +// $Id$ +//============================================================================ + +#include "FrameBuffer.hxx" +#include "Settings.hxx" +#include "OSystem.hxx" +#include "Console.hxx" +#include "TIA.hxx" + +#include "TIASurface.hxx" + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +TIASurface::TIASurface(FrameBuffer& buffer, OSystem& system) + : myFB(buffer), + myOSystem(system), + myTIA(NULL), + myTiaSurface(NULL), + mySLineSurface(NULL), + myFilterType(kNormal), + myUsePhosphor(false), + myPhosphorBlend(77), + myScanlinesEnabled(false) +{ + // Load NTSC filter settings + myNTSCFilter.loadConfig(myOSystem.settings()); + + // Create a surface for the TIA image and scanlines; we'll need them eventually + uInt32 tiaID = myFB.allocateSurface(ATARI_NTSC_OUT_WIDTH(160), 320); + myTiaSurface = myFB.surface(tiaID); + uInt32 scanID = myFB.allocateSurface(1, 320); + mySLineSurface = myFB.surface(scanID); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +TIASurface::~TIASurface() +{ +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIASurface::initialize(const Console& console, const VideoMode& mode) +{ + myTIA = &(console.tia()); + + +#if 0 +// FIX HERE /////////////////////////////////// + + + + +#if 0 + bool enable = myProperties.get(Display_Phosphor) == "YES"; + int blend = atoi(myProperties.get(Display_PPBlend).c_str()); + myOSystem.frameBuffer().tiaSurface().enablePhosphor(enable, blend); + myOSystem.frameBuffer().tiaSurface().setNTSC( + (NTSCFilter::Preset)myOSystem.settings().getInt("tv.filter"), false); +#endif + + + + + + // Grab the initial height before it's updated below + // We need it for the creating the TIA surface + uInt32 baseHeight = mode.image.height() / mode.zoom; + + // 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) + { + // 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.width(), mode.image.height()); + + myTiaSurface->enableScanlines(ntscEnabled()); + myTiaSurface->setTexInterpolation(myOSystem.settings().getBool("tia.inter")); + myTiaSurface->setScanIntensity(myOSystem.settings().getInt("tv.scanlines")); + myTiaSurface->setScanInterpolation(myOSystem.settings().getBool("tv.scaninter")); + myTiaSurface->setTIA(myOSystem.console().tia()); + } +///////////////////////////////////////////// +#endif +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIASurface::setPalette(const uInt32* tia_palette, const uInt32* rgb_palette) +{ + myPalette = tia_palette; + +cerr << "TIASurface::setPalette\n"; + for(int i = 0; i < 256; ++i) + cerr << myPalette[i] << " "; + cerr << endl; + + // Set palette for phosphor effect + for(int i = 0; i < 256; ++i) + { + for(int j = 0; j < 256; ++j) + { + uInt8 ri = (rgb_palette[i] >> 16) & 0xff; + uInt8 gi = (rgb_palette[i] >> 8) & 0xff; + uInt8 bi = rgb_palette[i] & 0xff; + uInt8 rj = (rgb_palette[j] >> 16) & 0xff; + uInt8 gj = (rgb_palette[j] >> 8) & 0xff; + uInt8 bj = rgb_palette[j] & 0xff; + + Uint8 r = (Uint8) getPhosphor(ri, rj); + Uint8 g = (Uint8) getPhosphor(gi, gj); + Uint8 b = (Uint8) getPhosphor(bi, bj); + + myPhosphorPalette[i][j] = myFB.mapRGB(r, g, b); + } + } + + // The NTSC filtering needs access to the raw RGB data, since it calculates + // its own internal palette + myNTSCFilter.setTIAPalette(*this, rgb_palette); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt32 TIASurface::pixel(uInt32 idx, uInt8 shift) const +{ + uInt8 c = *(myTIA->currentFrameBuffer() + idx) | shift; + uInt8 p = *(myTIA->previousFrameBuffer() + idx) | shift; + + return (!myUsePhosphor ? myPalette[c] : myPhosphorPalette[c][p]); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIASurface::setNTSC(NTSCFilter::Preset preset, bool show) +{ + ostringstream buf; + if(preset == NTSCFilter::PRESET_OFF) + { + enableNTSC(false); + buf << "TV filtering disabled"; + } + else + { + enableNTSC(true); + const string& mode = myNTSCFilter.setPreset(preset); + buf << "TV filtering (" << mode << " mode)"; + } + myOSystem.settings().setValue("tv.filter", (int)preset); + + if(show) myFB.showMessage(buf.str()); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIASurface::setScanlineIntensity(int amount) +{ + ostringstream buf; + if(ntscEnabled()) + { + uInt32 intensity = enableScanlines(amount); + buf << "Scanline intensity at " << intensity << "%"; + myOSystem.settings().setValue("tv.scanlines", intensity); + } + else + buf << "Scanlines only available in TV filtering mode"; + + myFB.showMessage(buf.str()); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIASurface::toggleScanlineInterpolation() +{ + ostringstream buf; + if(ntscEnabled()) + { + bool enable = !myOSystem.settings().getBool("tv.scaninter"); + enableScanlineInterpolation(enable); + buf << "Scanline interpolation " << (enable ? "enabled" : "disabled"); + myOSystem.settings().setValue("tv.scaninter", enable); + } + else + buf << "Scanlines only available in TV filtering mode"; + + myFB.showMessage(buf.str()); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt32 TIASurface::enableScanlines(int relative, int absolute) +{ + uInt32& intensity = mySLineSurface->myAttributes.blendalpha; + if(relative == 0) intensity = absolute; + else intensity += relative; + intensity = BSPF_max(0u, intensity); + intensity = BSPF_min(100u, intensity); + + mySLineSurface->applyAttributes(); +//FIXSDL myRedrawEntireFrame = true; + return intensity; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIASurface::enableScanlineInterpolation(bool enable) +{ + mySLineSurface->myAttributes.smoothing = enable; + mySLineSurface->applyAttributes(); +//FIXSDL myRedrawEntireFrame = true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIASurface::enablePhosphor(bool enable, int blend) +{ + myUsePhosphor = enable; + myPhosphorBlend = blend; + myFilterType = FilterType(enable ? myFilterType | 0x01 : myFilterType & 0x10); +//FIXSDL myRedrawEntireFrame = true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt8 TIASurface::getPhosphor(uInt8 c1, uInt8 c2) const +{ + if(c2 > c1) + BSPF_swap(c1, c2); + + return ((c1 - c2) * myPhosphorBlend)/100 + c2; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIASurface::enableNTSC(bool enable) +{ + myFilterType = FilterType(enable ? myFilterType | 0x10 : myFilterType & 0x01); + + // Normal vs NTSC mode uses different source widths + const GUI::Rect& src = myTiaSurface->srcRect(); + myTiaSurface->setSrcSize(enable ? ATARI_NTSC_OUT_WIDTH(160) : 160, src.height()); + + myTiaSurface->myAttributes.smoothing = + myOSystem.settings().getBool("tia.inter"); + myTiaSurface->applyAttributes(); + + myScanlinesEnabled = enable; + mySLineSurface->myAttributes.smoothing = + myOSystem.settings().getBool("tv.scaninter"); + mySLineSurface->myAttributes.blendalpha = + myOSystem.settings().getInt("tv.scanlines"); + mySLineSurface->applyAttributes(); + +//FIXSDL myRedrawEntireFrame = true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +string TIASurface::effectsInfo() const +{ + ostringstream buf; + switch(myFilterType) + { + case kNormal: + buf << "Disabled, normal mode"; + break; + case kPhosphor: + buf << "Disabled, phosphor mode"; + break; + case kBlarggNormal: + buf << myNTSCFilter.getPreset() << ", scanlines=" + << mySLineSurface->myAttributes.blendalpha << "/" + << (mySLineSurface->myAttributes.smoothing ? "inter" : "nointer"); + break; + case kBlarggPhosphor: + buf << myNTSCFilter.getPreset() << ", phosphor, scanlines=" + << mySLineSurface->myAttributes.blendalpha << "/" + << (mySLineSurface->myAttributes.smoothing ? "inter" : "nointer"); + break; + } + return buf.str(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIASurface::render() +{ +#if 0 +cerr << "src: " << myTiaSurface->srcRect() << endl + << "dst: " << myTiaSurface->dstRect() << endl + << endl; +#endif + // Copy the mediasource framebuffer to the RGB texture + // In hardware rendering mode, it's faster to just assume that the screen + // is dirty and always do an update + + uInt8* currentFrame = myTIA->currentFrameBuffer(); + uInt8* previousFrame = myTIA->previousFrameBuffer(); + uInt32 width = myTIA->width(); + uInt32 height = myTIA->height(); + + uInt32 *buffer, pitch; + myTiaSurface->basePtr(buffer, pitch); +//cerr << "buffer=" << buffer << ", pitch=" << pitch << endl; + + // TODO - Eventually 'phosphor' won't be a separate mode, and will become + // a post-processing filter by blending several frames. + switch(myFilterType) + { + case kNormal: + { + uInt32 bufofsY = 0; + uInt32 screenofsY = 0; + for(uInt32 y = 0; y < height; ++y) + { + uInt32 pos = screenofsY; + for(uInt32 x = 0; x < width; ++x) + buffer[pos++] = (uInt32) myPalette[currentFrame[bufofsY + x]]; + + bufofsY += width; + screenofsY += pitch; + } + break; + } + case kPhosphor: + { + uInt32 bufofsY = 0; + uInt32 screenofsY = 0; + for(uInt32 y = 0; y < height; ++y) + { + uInt32 pos = screenofsY; + for(uInt32 x = 0; x < width; ++x) + { + const uInt32 bufofs = bufofsY + x; + buffer[pos++] = (uInt32) + myPhosphorPalette[currentFrame[bufofs]][previousFrame[bufofs]]; + } + bufofsY += width; + screenofsY += pitch; + } + break; + } + case kBlarggNormal: + { + myNTSCFilter.blit_single(currentFrame, width, height, + buffer, pitch); + break; + } + case kBlarggPhosphor: + { + myNTSCFilter.blit_double(currentFrame, previousFrame, width, height, + buffer, pitch); + break; + } + } + + // Draw TIA image + myTiaSurface->render(); + + // Draw overlaying scanlines + if(myScanlinesEnabled) + mySLineSurface->render(); +} diff --git a/src/emucore/TIASurface.hxx b/src/emucore/TIASurface.hxx new file mode 100644 index 000000000..deb6a29d5 --- /dev/null +++ b/src/emucore/TIASurface.hxx @@ -0,0 +1,174 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +// +// $Id$ +//============================================================================ + +#ifndef TIASURFACE_HXX +#define TIASURFACE_HXX + +class TIA; +class Console; +class OSystem; +class FrameBuffer; +class FBSurface; +class VideoMode; + +#include "NTSCFilter.hxx" +#include "bspf.hxx" + +/** + This class is basically a wrapper around all things related to rendering + the TIA image to FBSurface's, and presenting the results to the screen. + This is placed in a separate class since currently, rendering a TIA image + can consist of TV filters, a separate scanline surface, phosphor modes, etc. + + @author Stephen Anthony +*/ + +class TIASurface +{ + friend class FrameBuffer; + + public: + /** + Creates a new TIASurface object + */ + TIASurface(FrameBuffer& buffer, OSystem& system); + + /** + Destructor + */ + virtual ~TIASurface(); + + /** + Set the TIA object, which is needed for actually rendering the TIA image. + */ + void initialize(const Console& console, const VideoMode& mode); + + /** + Set the palette for TIA rendering. This currently consists of two + components: the actual TIA palette, and a mixed TIA palette used + in phosphor mode. The latter may eventually disappear once a better + phosphor emulation is developed. + + @param tia_palette An actual TIA palette, converted to data values + that are actually usable by the framebuffer + @param rgb_palette The RGB components of the palette, needed for + calculating a phosphor palette + */ + void setPalette(const uInt32* tia_palette, const uInt32* rgb_palette); + + /** + Get the TIA pixel associated with the given TIA buffer index, + shifting by the given offset (for greyscale values). + */ + uInt32 pixel(uInt32 idx, uInt8 shift = 0) const; + + /** + Get the NTSCFilter object associated with the framebuffer + */ + NTSCFilter& ntsc() { return myNTSCFilter; } + + /** + Use NTSC filtering effects specified by the given preset. + */ + void setNTSC(NTSCFilter::Preset preset, bool show = true); + + /** + Increase/decrease current scanline intensity by given relative amount. + */ + void setScanlineIntensity(int relative); + + /** + Toggles interpolation/smoothing of scanlines in TV modes. + */ + void toggleScanlineInterpolation(); + + /** + Change scanline intensity and interpolation. + + @param relative If non-zero, change current intensity by + 'relative' amount, otherwise set to 'absolute' + @return New current intensity + */ + uInt32 enableScanlines(int relative, int absolute = 50); + void enableScanlineInterpolation(bool enable); + + /** + Enable/disable phosphor effect. + */ + void enablePhosphor(bool enable, int blend); + + /** + Used to calculate an averaged color for the 'phosphor' effect. + + @param c1 Color 1 + @param c2 Color 2 + + @return Averaged value of the two colors + */ + uInt8 getPhosphor(uInt8 c1, uInt8 c2) const; + + /** + Enable/disable/query NTSC filtering effects. + */ + void enableNTSC(bool enable); + bool ntscEnabled() const { return myFilterType & 0x10; } + string effectsInfo() const; + + /** + This method should be called to draw the TIA image(s) to the screen. + */ + void render(); + + private: + FrameBuffer& myFB; + OSystem& myOSystem; + TIA* myTIA; + + FBSurface *myTiaSurface, *mySLineSurface; + + // Enumeration created such that phosphor off/on is in LSB, + // and Blargg off/on is in MSB + enum FilterType { + kNormal = 0x00, + kPhosphor = 0x01, + kBlarggNormal = 0x10, + kBlarggPhosphor = 0x11 + }; + FilterType myFilterType; + + // NTSC object to use in TIA rendering mode + NTSCFilter myNTSCFilter; + + // Use phosphor effect (aka no flicker on 30Hz screens) + bool myUsePhosphor; + + // Amount to blend when using phosphor effect + int myPhosphorBlend; + + // Use scanlines in TIA rendering mode + bool myScanlinesEnabled; + + // Palette for normal TIA rendering mode + const uInt32* myPalette; + + // Palette for phosphor rendering mode + uInt32 myPhosphorPalette[256][256]; +}; + +#endif diff --git a/src/emucore/module.mk b/src/emucore/module.mk index 57591721b..2422de2b0 100644 --- a/src/emucore/module.mk +++ b/src/emucore/module.mk @@ -71,6 +71,7 @@ MODULE_OBJS := \ src/emucore/TIA.o \ src/emucore/TIASnd.o \ src/emucore/TIATables.o \ + src/emucore/TIASurface.o \ src/emucore/TrackBall.o \ src/emucore/Thumbulator.o diff --git a/src/gui/VideoDialog.cxx b/src/gui/VideoDialog.cxx index 3fe94eac2..96fbe2905 100644 --- a/src/gui/VideoDialog.cxx +++ b/src/gui/VideoDialog.cxx @@ -463,7 +463,7 @@ void VideoDialog::saveConfig() adj.artifacts = myTVArtifacts->getValue(); adj.fringing = myTVFringe->getValue(); adj.bleed = myTVBleed->getValue(); - instance().frameBuffer().ntsc().setCustomAdjustables(adj); + instance().frameBuffer().tiaSurface().ntsc().setCustomAdjustables(adj); // TV scanline intensity and interpolation instance().settings().setValue("tv.scanlines", myTVScanIntenseLabel->getLabel()); @@ -565,7 +565,8 @@ void VideoDialog::handleTVModeChange(NTSCFilter::Preset preset) void VideoDialog::loadTVAdjustables(NTSCFilter::Preset preset) { NTSCFilter::Adjustable adj; - instance().frameBuffer().ntsc().getAdjustables(adj, (NTSCFilter::Preset)preset); + instance().frameBuffer().tiaSurface().ntsc().getAdjustables( + adj, (NTSCFilter::Preset)preset); myTVSharp->setValue(adj.sharpness); myTVSharpLabel->setValue(adj.sharpness); myTVHue->setValue(adj.hue); diff --git a/src/macosx/SettingsMACOSX.cxx b/src/macosx/SettingsMACOSX.cxx index 5fc9d64d5..d2aaecc1b 100644 --- a/src/macosx/SettingsMACOSX.cxx +++ b/src/macosx/SettingsMACOSX.cxx @@ -26,7 +26,7 @@ extern "C" { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -SettingsMACOSX::SettingsMACOSX(OSystem* osystem) +SettingsMACOSX::SettingsMACOSX(OSystem& osystem) : Settings(osystem) { } diff --git a/src/macosx/SettingsMACOSX.hxx b/src/macosx/SettingsMACOSX.hxx index 3448c3006..ad7df1b29 100644 --- a/src/macosx/SettingsMACOSX.hxx +++ b/src/macosx/SettingsMACOSX.hxx @@ -36,7 +36,7 @@ class SettingsMACOSX : public Settings /** Create a new UNIX settings object */ - SettingsMACOSX(OSystem* osystem); + SettingsMACOSX(OSystem& osystem); /** Destructor diff --git a/src/unix/SettingsUNIX.cxx b/src/unix/SettingsUNIX.cxx index 6dbf257c9..8cda009c8 100644 --- a/src/unix/SettingsUNIX.cxx +++ b/src/unix/SettingsUNIX.cxx @@ -20,7 +20,7 @@ #include "SettingsUNIX.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -SettingsUNIX::SettingsUNIX(OSystem* osystem) +SettingsUNIX::SettingsUNIX(OSystem& osystem) : Settings(osystem) { } diff --git a/src/unix/SettingsUNIX.hxx b/src/unix/SettingsUNIX.hxx index 6ee549d34..5349be54a 100644 --- a/src/unix/SettingsUNIX.hxx +++ b/src/unix/SettingsUNIX.hxx @@ -36,7 +36,7 @@ class SettingsUNIX : public Settings /** Create a new UNIX settings object */ - SettingsUNIX(OSystem* osystem); + SettingsUNIX(OSystem& osystem); /** Destructor diff --git a/src/windows/SettingsWINDOWS.cxx b/src/windows/SettingsWINDOWS.cxx index 45927c694..cbdcc7140 100644 --- a/src/windows/SettingsWINDOWS.cxx +++ b/src/windows/SettingsWINDOWS.cxx @@ -20,7 +20,7 @@ #include "SettingsWINDOWS.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -SettingsWINDOWS::SettingsWINDOWS(OSystem* osystem) +SettingsWINDOWS::SettingsWINDOWS(OSystem& osystem) : Settings(osystem) { setInternal("fragsize", "1024"); diff --git a/src/windows/SettingsWINDOWS.hxx b/src/windows/SettingsWINDOWS.hxx index 46075e868..fcaaa2edb 100644 --- a/src/windows/SettingsWINDOWS.hxx +++ b/src/windows/SettingsWINDOWS.hxx @@ -30,7 +30,7 @@ class SettingsWINDOWS : public Settings /** Create a new UNIX settings object */ - SettingsWINDOWS(OSystem* osystem); + SettingsWINDOWS(OSystem& osystem); /** Destructor