//============================================================================ // // 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-2017 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. //============================================================================ #ifndef FRAMEBUFFER_HXX #define FRAMEBUFFER_HXX #include class OSystem; class Console; class Settings; namespace GUI { class Font; } #include "EventHandler.hxx" #include "Rect.hxx" #include "Variant.hxx" #include "FBSurface.hxx" #include "TIASurface.hxx" #include "TIAConstants.hxx" #include "FrameBufferConstants.hxx" #include "bspf.hxx" // 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; Int32 fsIndex; uInt32 zoom; string description; public: VideoMode(); VideoMode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh, Int32 full, uInt32 z = 1, const string& desc = ""); friend ostream& operator<<(ostream& os, const VideoMode& vm) { os << "image=" << vm.image << " screen=" << vm.screen << " full= " << vm.fsIndex << " zoom=" << vm.zoom << " desc=" << vm.description; return os; } private: void applyAspectCorrection(uInt32 aspect, bool 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 platform-specific video stuff. The TIA is drawn here, and all GUI elements (ala ScummVM, which are drawn into FBSurfaces), are in turn drawn here as well. @author Stephen Anthony */ class FrameBuffer { public: enum { kTIAMinW = 320u, kTIAMinH = TIAConstants::minViewableHeight, kFBMinW = 640u, kFBMinH = 480u }; /** Creates a new Frame Buffer */ FrameBuffer(OSystem& osystem); virtual ~FrameBuffer() = default; /** Initialize the framebuffer object (set up the underlying hardware) */ bool initialize(); /** (Re)creates the framebuffer display. This must be called before any calls are made to derived methods. @param title The title of the application / window @param width The width of the framebuffer @param height The height of the framebuffer @return Status of initialization (see FBInitStatus 'enum') */ FBInitStatus createDisplay(const string& title, uInt32 width, uInt32 height); /** Updates the display, which depending on the current mode could mean drawing the TIA, any pending menus, etc. */ void update(); /** Shows a message onscreen. @param message The message to be shown @param position Onscreen position for the message @param force Force showing this message, even if messages are disabled */ void showMessage(const string& message, MessagePosition position = kBottomCenter, bool force = false); /** Toggles showing or hiding framerate statistics. */ void toggleFrameStats(); /** Shows a message containing frame statistics for the current frame. */ void showFrameStats(bool enable); /** Enable/disable any pending messages. Disabled messages aren't removed from the message queue; they're just not redrawn into the framebuffer. */ void enableMessages(bool enable); /** Allocate a new surface. The FrameBuffer class takes all responsibility for freeing this surface (ie, other classes must not delete it directly). @param w The requested width of the new surface. @param h The requested height of the new surface. @param data If non-null, use the given data values as a static surface @return A pointer to a valid surface object, or nullptr. */ shared_ptr allocateSurface(int w, int h, const uInt32* data = nullptr); /** Returns the current dimensions of the framebuffer image. Note that this will take into account the current scaling (if any) as well as image 'centering'. */ const GUI::Rect& imageRect() const { return myImageRect; } /** Returns the current dimensions of the framebuffer window. This is the entire area containing the framebuffer image as well as any 'unusable' area. */ const GUI::Size& screenSize() const { return myScreenSize; } /** Returns the current dimensions of the users' desktop. */ const GUI::Size& desktopSize() const { return myDesktopSize; } /** Get the supported renderers for the video hardware. @return An array of supported renderers */ 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 */ const GUI::Font& font() const { return *myFont; } const GUI::Font& infoFont() const { return *myInfoFont; } 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; } /** Enables/disables fullscreen mode. */ void setFullscreen(bool enable); /** Toggles between fullscreen and window mode. */ void toggleFullscreen(); /** This method is called when the user wants to switch to the next available windowed video mode. direction = -1 means go to the next lower windowed video mode direction = +1 means go to the next higher windowed video mode @param direction Described above */ bool changeWindowedVidMode(int direction); /** Sets the state of the cursor (hidden or grabbed) based on the current mode. */ void setCursorState(); /** Toggles the use of grabmouse (only has effect in emulation mode). The method changes the 'grabmouse' setting and saves it. */ void toggleGrabMouse(); /** Set up the TIA/emulation palette for a screen of any depth > 8. @param raw_palette The array of colors in R/G/B format */ void setPalette(const uInt32* raw_palette); /** Informs the Framebuffer of a change in EventHandler state. */ void stateChanged(EventHandler::State state); ////////////////////////////////////////////////////////////////////// // The following methods are system-specific and can/must be // implemented in derived classes. ////////////////////////////////////////////////////////////////////// public: /** Shows or hides the cursor based on the given boolean value. */ virtual void showCursor(bool show) = 0; /** Answers if the display is currently in fullscreen mode. */ virtual bool fullScreen() const = 0; /** This method is called to retrieve the R/G/B data from the given pixel. @param pixel The pixel containing R/G/B data @param r The red component of the color @param g The green component of the color @param b The blue component of the color */ virtual void getRGB(uInt32 pixel, uInt8* r, uInt8* g, uInt8* b) const = 0; /** This method is called to map a given R/G/B triple to the screen palette. @param r The red component of the color. @param g The green component of the color. @param b The blue component of the color. */ virtual uInt32 mapRGB(uInt8 r, uInt8 g, uInt8 b) const = 0; /** This method is called to get the specified ARGB data from the viewable FrameBuffer area. Note that this isn't the same as any internal surfaces that may be in use; it should return the actual data as it is currently seen onscreen. @param buffer The actual pixel data in ARGB8888 format @param pitch The pitch (in bytes) for the pixel data @param rect The bounding rectangle for the buffer */ virtual void readPixels(uInt8* buffer, uInt32 pitch, const GUI::Rect& rect) const = 0; protected: /** This method is called to query and initialize the video hardware for desktop and fullscreen resolution information. */ virtual void queryHardware(vector& mons, VariantList& ren) = 0; virtual Int32 getCurrentDisplayIndex() = 0; /** 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 @return False on any errors, else true */ virtual bool setVideoMode(const string& title, const VideoMode& mode) = 0; /** This method is called to invalidate the contents of the entire framebuffer (ie, mark the current content as invalid, and erase it on the next drawing pass). */ virtual void invalidate() = 0; /** This method is called to create a surface with the given attributes. @param w The requested width of the new surface. @param h The requested height of the new surface. @param data If non-null, use the given data values as a static surface */ virtual unique_ptr createSurface(uInt32 w, uInt32 h, const uInt32* data) const = 0; /** Grabs or ungrabs the mouse based on the given boolean value. */ virtual void grabMouse(bool grab) = 0; /** Set the icon for the main window. */ virtual void setWindowIcon() = 0; /** This method is called after any drawing is done (per-frame). */ virtual void postFrameUpdate() = 0; /** This method is called to provide information about the FrameBuffer. */ virtual string about() const = 0; protected: // The parent system for the framebuffer OSystem& myOSystem; // Color palette for TIA and UI modes uInt32 myPalette[256+kNumColors]; private: /** Draw pending messages. */ void drawMessage(); /** 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. */ uInt32 maxWindowSizeForScreen(uInt32 baseWidth, uInt32 baseHeight, uInt32 screenWidth, uInt32 screenHeight) const; /** Set all possible video modes (both windowed and fullscreen) available for this framebuffer based on given image dimensions and maximum window size. */ void setAvailableVidModes(uInt32 basewidth, uInt32 baseheight); /** Returns an appropriate video mode based on the current eventhandler state, taking into account the maximum size of the window. @param fullscreen Whether to use a windowed or fullscreen mode @return A valid VideoMode for this framebuffer */ const VideoMode& getSavedVidMode(bool fullscreen); private: /** This class implements an iterator around an array of VideoMode objects. */ class VideoModeList { public: VideoModeList(); VideoModeList(const VideoModeList&) = default; VideoModeList& operator=(const VideoModeList&) = default; void add(const VideoMode& mode); void clear(); bool empty() const; uInt32 size() const; void previous(); const VideoMode& current() const; void next(); void setZoom(uInt32 zoom); friend ostream& operator<<(ostream& os, const VideoModeList& l) { for(const auto& vm: l.myModeList) os << "-----\n" << vm << endl << "-----\n"; return os; } private: vector myModeList; int myIdx; }; private: // Indicates the number of times the framebuffer was initialized uInt32 myInitializedCount; // Used to set intervals between messages while in pause mode Int32 myPausedCount; // Dimensions of the actual image, after zooming, and taking into account // any image 'centering' GUI::Rect myImageRect; // Dimensions of the main window (not always the same as the image) GUI::Size myScreenSize; // Title of the main window/screen string myScreenTitle; // Maximum dimensions of the desktop area GUI::Size myDesktopSize; // The resolution of the attached displays // The primary display is first in the array vector myDisplays; // Supported renderers VariantList myRenderers; // The font object to use for the normal in-game GUI unique_ptr myFont; // The info font object to use for the normal in-game GUI unique_ptr myInfoFont; // The font object to use when space is very limited unique_ptr mySmallFont; // The font object to use for the ROM launcher unique_ptr myLauncherFont; // The TIASurface class takes responsibility for TIA rendering unique_ptr myTIASurface; // Used for onscreen messages and frame statistics // (scanline count and framerate) struct Message { string text; int counter; int x, y, w, h; MessagePosition position; uInt32 color; shared_ptr surface; bool enabled; }; Message myMsg; Message myStatsMsg; // The list of all available video modes for this framebuffer VideoModeList* myCurrentModeList; VideoModeList myWindowedModeList; vector myFullscreenModeLists; // 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 vector> mySurfaceList; // Holds UI palette data (standard and classic colours) static uInt32 ourGUIColors[2][kNumColors-256]; private: // Following constructors and assignment operators not supported FrameBuffer() = delete; FrameBuffer(const FrameBuffer&) = delete; FrameBuffer(FrameBuffer&&) = delete; FrameBuffer& operator=(const FrameBuffer&) = delete; FrameBuffer& operator=(FrameBuffer&&) = delete; }; #endif