Initial commit
This commit is contained in:
449
engines/sci/graphics/frameout.h
Normal file
449
engines/sci/graphics/frameout.h
Normal file
@@ -0,0 +1,449 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#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);
|
||||
|
||||
/**
|
||||
* Deletes planes when restoring a Mac game.
|
||||
*/
|
||||
void deletePlanesForMacRestore();
|
||||
|
||||
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);
|
||||
|
||||
Plane *getTopVisiblePlane();
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* A list of DrawLists used by frameOut(). This is a field to avoid
|
||||
* constructing and destroying DrawLists on every frame.
|
||||
*/
|
||||
ScreenItemListList _screenItemLists;
|
||||
|
||||
/**
|
||||
* 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 // SCI_GRAPHICS_FRAMEOUT_H
|
||||
Reference in New Issue
Block a user