scummvm/engines/sci/graphics/frameout.h
Colin Snover 432fd522d2 ENGINES: Remove default1x scaler flag
This flag is removed for a few reasons:

* Engines universally set this flag to true for widths > 320,
  which made it redundant everywhere;
* This flag functioned primarily as a "force 1x scaler" flag,
  since its behaviour was almost completely undocumented and users
  would need to figure out that they'd need an explicit non-default
  scaler set to get a scaler to operate at widths > 320;
* (Most importantly) engines should not be in the business of
  deciding how the backend may choose to render its virtual screen.
  The choice of rendering behaviour belongs to the user, and the
  backend, in that order.

A nearby future commit restores the default1x scaler behaviour in
the SDL backend code for the moment, but in the future it is my
hope that there will be a better configuration UI to allow users
to specify how they want scaling to work for high resolutions.
2017-10-07 12:30:29 -05:00

437 lines
13 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef SCI_GRAPHICS_FRAMEOUT_H
#define SCI_GRAPHICS_FRAMEOUT_H
#include "engines/util.h" // for initGraphics
#include "sci/event.h"
#include "sci/graphics/plane32.h"
#include "sci/graphics/screen_item32.h"
namespace Sci {
typedef Common::Array<DrawList> ScreenItemListList;
typedef Common::Array<RectList> EraseListList;
class GfxCursor32;
class GfxTransitions32;
struct PlaneShowStyle;
/**
* Frameout class, kFrameOut and relevant functions for SCI32 games.
* Roughly equivalent to GraphicsMgr in SSCI.
*/
class GfxFrameout {
friend class GfxTransitions32;
public:
GfxFrameout(SegManager *segMan, GfxPalette32 *palette, GfxTransitions32 *transitions, GfxCursor32 *cursor);
~GfxFrameout();
void clear();
void run();
/**
* Returns true if the game should render at a resolution greater than
* 320x240.
*/
inline bool isHiRes() const { return _isHiRes; }
/**
* Gets the x-resolution used by game scripts.
*/
inline int16 getScriptWidth() const { return _scriptWidth; }
/**
* Gets the y-resolution used by game scripts.
*/
inline int16 getScriptHeight() const { return _scriptHeight; }
/**
* Gets the x-resolution of the output buffer.
*/
inline int16 getScreenWidth() const { return _currentBuffer.w; }
/**
* Gets the y-resolution of the output buffer.
*/
inline int16 getScreenHeight() const { return _currentBuffer.h; }
private:
GfxCursor32 *_cursor;
GfxPalette32 *_palette;
GfxTransitions32 *_transitions;
SegManager *_segMan;
/**
* Whether or not the game should render at a resolution above 320x240.
*/
bool _isHiRes;
/**
* The resolution used by game scripts.
* @see celobj32.h comments on kLowResX/kLowResY.
*/
int16 _scriptWidth, _scriptHeight;
/**
* Determines whether the current game should be rendered in high
* resolution.
*/
bool detectHiRes() const;
#pragma mark -
#pragma mark Screen items
public:
/**
* Adds a screen item.
*/
void addScreenItem(ScreenItem &screenItem) const;
/**
* Updates a screen item.
*/
void updateScreenItem(ScreenItem &screenItem) const;
/**
* Deletes a screen item.
*/
void deleteScreenItem(ScreenItem &screenItem);
/**
* Deletes a screen item from the given plane.
*/
void deleteScreenItem(ScreenItem &screenItem, Plane &plane);
/**
* Deletes a screen item from the given plane.
*/
void deleteScreenItem(ScreenItem &screenItem, const reg_t plane);
void kernelAddScreenItem(const reg_t object);
void kernelUpdateScreenItem(const reg_t object);
void kernelDeleteScreenItem(const reg_t object);
bool kernelSetNowSeen(const reg_t screenItemObject) const;
int16 kernelObjectIntersect(const reg_t object1, const reg_t object2) const;
private:
void remapMarkRedraw();
bool getNowSeenRect(const reg_t screenItemObject, Common::Rect &result) const;
#pragma mark -
#pragma mark Planes
public:
/**
* Creates and adds a new plane to the plane list. Ownership of the passed
* object is transferred to GfxFrameout.
*
* @note This method is on Screen in SSCI, but it is only ever called on
* `GraphicsMgr.screen`.
*/
void addPlane(Plane *plane);
/**
* Deletes a plane within the current plane list.
*
* @note This method is on Screen in SSCI, but it is only ever called on
* `GraphicsMgr.screen`.
*/
void deletePlane(Plane &plane);
const PlaneList &getPlanes() const {
return _planes;
}
const PlaneList &getVisiblePlanes() const {
return _visiblePlanes;
}
void kernelAddPlane(const reg_t object);
void kernelUpdatePlane(const reg_t object);
void kernelDeletePlane(const reg_t object);
void kernelMovePlaneItems(const reg_t object, const int16 deltaX, const int16 deltaY, const bool scrollPics);
int16 kernelGetHighPlanePri();
private:
/**
* The list of planes (i.e. layers) that will be rendered to the screen on
* the next call to `frameOut`.
*
* @note This field is on `GraphicsMgr.screen` in SSCI.
*/
PlaneList _planes;
/**
* Updates an existing plane with properties from the given VM object.
*/
void updatePlane(Plane &plane);
#pragma mark -
#pragma mark Pics
public:
void kernelAddPicAt(const reg_t planeObject, const GuiResourceId pictureId, const int16 pictureX, const int16 pictureY, const bool mirrorX, const bool deleteDuplicate);
#pragma mark -
#pragma mark Rendering
public:
/**
* Updates the hardware screen, no more than once per tick.
*
* @param delta An additional number of ticks that should elapse
* since the last time the screen was updated before it gets updated now.
* This is used for updating the screen within run_vm, where we normally
* expect that a call to kFrameOut will occur later during the current
* frame, but if it does not, then update the screen on the second frame
* anyway since the game is doing something bad.
*/
void updateScreen(const int delta = 0);
/**
* Resets the pixel format of the hardware surface to the given format.
*/
void setPixelFormat(const Graphics::PixelFormat &format) const {
initGraphics(_currentBuffer.w, _currentBuffer.h, &format);
}
/**
* Whether or not to throttle kFrameOut calls.
*/
bool _throttleKernelFrameOut;
/**
* Whether `palMorphFrameOut` should be used instead of `frameOut` for
* rendering. Used by `kMorphOn` to explicitly enable `palMorphFrameOut` for
* one frame.
*/
bool _palMorphIsOn;
inline const Buffer &getCurrentBuffer() const {
return _currentBuffer;
}
void kernelFrameOut(const bool showBits);
/**
* Throttles the engine as necessary to maintain 60fps output.
*/
void throttle();
/**
* Updates the internal screen buffer for the next frame. If
* `shouldShowBits` is true, also sends the buffer to hardware. If
* `eraseRect` is non-empty, it is added to the erase list for this frame.
*/
void frameOut(const bool shouldShowBits, const Common::Rect &eraseRect = Common::Rect());
/**
* TODO: Documentation
*/
void palMorphFrameOut(const int8 *styleRanges, PlaneShowStyle *showStyle);
/**
* Draws the given rect from the internal screen buffer to hardware without
* processing any other graphics updates except for cursor changes.
*/
void directFrameOut(const Common::Rect &showRect);
/**
* Redraws the game screen from the internal frame buffer to the system.
* Used after pixel format changes.
*
* @param skipRect An area of the screen that does not need to be redrawn.
*/
void redrawGameScreen(const Common::Rect &skipRect) const;
#ifdef USE_RGB_COLOR
/**
* Sends the entire internal screen buffer and palette to hardware.
*/
void resetHardware();
#endif
/**
* Modifies the raw pixel data for the next frame with new palette indexes
* based on matched style ranges.
*/
void alterVmap(const Palette &palette1, const Palette &palette2, const int8 style, const int8 *const styleRanges);
// This function is used within ScreenItem subsystem and assigned to various
// booleanish fields that seem to represent the state of the screen item
// (created, updated, deleted). In GK1/DOS, Phant1/m68k, SQ6/DOS, SQ6/Win,
// and Phant2/Win, this function simply returns 1. If you know of any
// game/environment where this function returns some value other than 1, or
// if you used to work at Sierra and can explain why this is a thing (and if
// anyone needs to care about it), please open a ticket!!
inline int getScreenCount() const {
return 1;
};
/**
* Shakes the screen.
*/
void shakeScreen(const int16 numShakes, const ShakeDirection direction);
private:
/**
* The last time the hardware screen was updated.
*/
uint32 _lastScreenUpdateTick;
/**
* State tracker to provide more accurate 60fps video throttling.
*/
uint8 _throttleState;
/**
* The internal display pixel buffer. During `frameOut`, this buffer is
* drawn into according to the draw and erase rects calculated by
* `calcLists`, then drawn out to the hardware surface according to the
* `_showList` rects (which are also calculated by `calcLists`).
*/
Buffer _currentBuffer;
/**
* When true, a change to the remap zone in the palette has occurred and
* screen items with remap data need to be redrawn.
*/
bool _remapOccurred;
/**
* A list of rectangles, in screen coordinates, that represent portions of
* the internal screen buffer that are dirty and should be drawn to the
* hardware display surface.
*
* @note This field is on `GraphicsMgr.screen` in SSCI.
*/
RectList _showList;
/**
* The amount of extra overdraw that is acceptable when merging two show
* list rectangles together into a single larger rectangle.
*
* @note This field is on `GraphicsMgr.screen` in SSCI.
*/
int _overdrawThreshold;
/**
* The list of planes that are currently drawn to the hardware display
* surface. Used to calculate differences in plane properties between the
* last frame and current frame.
*
* @note This field is on `GraphicsMgr.visibleScreen` in SSCI.
*/
PlaneList _visiblePlanes;
/**
* Calculates the location and dimensions of dirty rects over the entire
* screen for rendering the next frame. The draw and erase lists in
* `drawLists` and `eraseLists` each represent one plane on the screen.
* The optional `eraseRect` argument allows a specific area of the screen to
* be explicitly erased.
*/
void calcLists(ScreenItemListList &drawLists, EraseListList &eraseLists, const Common::Rect &eraseRect = Common::Rect());
/**
* Erases the areas in the given erase list from the visible screen buffer
* by filling them with the color from the corresponding plane. This is an
* optimisation for colored-type planes only; other plane types have to be
* redrawn from pixel data.
*/
void drawEraseList(const RectList &eraseList, const Plane &plane);
/**
* Draws all screen items from the given draw list to the visible screen
* buffer.
*/
void drawScreenItemList(const DrawList &screenItemList);
/**
* Adds a new rectangle to the list of regions to write out to the hardware.
* The provided rect may be merged into an existing rectangle to reduce the
* number of blit operations.
*/
void mergeToShowList(const Common::Rect &drawRect, RectList &showList, const int overdrawThreshold);
/**
* Sends all dirty rects from the internal frame buffer to the backend, then
* updates the hardware screen.
*/
void showBits();
/**
* Validates whether the given palette index in the style range should copy
* a color from the next palette to the source palette during a palette
* morph operation.
*/
inline bool validZeroStyle(const uint8 style, const int i) const {
if (style != 0) {
return false;
}
// TODO: Cannot check Shivers or MGDX until those executables can be
// unwrapped
switch (g_sci->getGameId()) {
case GID_KQ7:
case GID_PHANTASMAGORIA:
case GID_SQ6:
return (i > 71 && i < 104);
break;
default:
return true;
}
}
#pragma mark -
#pragma mark Mouse cursor
public:
reg_t kernelIsOnMe(const reg_t object, const Common::Point &position, const bool checkPixel) const;
private:
void updateMousePositionForRendering() const {
// In SSCI, mouse events were received via hardware interrupt, so the
// mouse cursor would always get updated immediately when the user moved
// the mouse. ScummVM must poll for mouse events from the backend
// instead, so we poll just before rendering so that the latest mouse
// position is rendered instead of whatever position it was at the last
// time kGetEvent was called. Without this, the mouse appears stuck
// during loops that do not make calls to kGetEvent, like transitions.
g_sci->getEventManager()->getSciEvent(kSciEventPeek);
}
/**
* Determines whether or not the point given by `position` is inside of the
* given screen item.
*/
bool isOnMe(const ScreenItem &screenItem, const Plane &plane, const Common::Point &position, const bool checkPixel) const;
#pragma mark -
#pragma mark Debugging
public:
void printPlaneList(Console *con) const;
void printVisiblePlaneList(Console *con) const;
void printPlaneListInternal(Console *con, const PlaneList &planeList) const;
void printPlaneItemList(Console *con, const reg_t planeObject) const;
void printVisiblePlaneItemList(Console *con, const reg_t planeObject) const;
void printPlaneItemListInternal(Console *con, const ScreenItemList &screenItemList) const;
};
} // End of namespace Sci
#endif